getCurrentStatus error on iOS 11.2.2 on Zebra iMZ320 with Xamarin

Hi to all,

I've an application devoloped with Xamarin.Forms that use an Ipad for device. I can print all before the last update of ios version (with ios 11.2.1 i can print all very well). With the last update, my printer doesn't print, the error in "Malformed Status"

 

I use LinkOS_Xamarin_SDK 1.1.75. The error is systematic on the method that check the printer status .. I think it's something similar to what is shown here :

 

https://developer.zebra.com/community/technologies/printers/label-printers/blog/2017/11/01/ios-11-bluetooth-disconnectio…

 

and here :

 

iMZ320 in iOS:Sometimes getCurrentStatus shows ErrorCode=7

 

i'm sure that only one device is connected with the printer. Please someone can tell me a solution to get around the problem (i try to remove the call on method for the printer status, but error still persist. Expetion is throwning on the following line in bold :

 

        public bool CheckPrinterStatus(IConnection connection)

        {

            IZebraPrinter printer = ZebraPrinterFactory.Current.GetInstance(PrinterLanguage.ZPL, connection);

            IPrinterStatus status = printer.CurrentStatus;

 

            if (!status.IsReadyToPrint)

            {

                //Log.Debug(tag, "Printer in Error: " + status.ToString());

                string error = "Printer in Error: " + status.ToString();

            }

            return true;

        }

 

 

Thanks in advance.

Nicola Lazzara
The problem remains the same

The problem remains the same even on version 11.2.5 of ios.

Someone have a solution or workaround?

Vote: 
Vote up!
Vote down!

Points: 0

You voted ‘up’


John Ferlazzo
Hi Nicole,This may be similar

Hi Nicole,

This may be similar to the issue in

You can check that you are not opening any connections and communicating with the printer on the main thread. Try to keep everything in one separate thread (Open connection, get printer instance/status and write to connection).

Vote: 
Vote up!
Vote down!

Points: 0

You voted ‘up’


Nicola Lazzara
Hi john thanks for your help,

Hi john thanks for your help, but dosen't work for me.

My code is this :

When i click on print button my code is :

            bool isPrintOK = await CheckPrinterStatus();

            if (!string.IsNullOrEmpty(address))

            {

                if (isPrintOK)

                {

                   

                    myZpl = myHelper.BuildPrintTemplate();

                    var printingTask = Task<bool>.Factory.StartNew(() =>

                    {

                        PrinterHelper myPrinterHelper = new PrinterHelper();

                        myPrinterHelper.Print2(address, myZpl);

                        return App.printingOK;

                    });

                    printingTask.Wait();

}

}

The first problem is on CheckPrinterStatus() call;

After your response i changed with this logic :

        public static void CheckPrinter(string address)

        {

            bool connectionOK = false;

            bool statusValid = false;

            string _messagePaper = string.Empty;

            string _messageHeadOpen = string.Empty;

            string _messageSleepingMode = string.Empty;

            var t = Task.Run(() =>

            {

                try

                {

                    IConnection connectionCheckStatus = ConnectionBuilder.Current.Build("BT:" + address);

                    connectionCheckStatus.Open();

                    if (connectionCheckStatus.IsConnected)

                    {

                        connectionOK = true;

                        IZebraPrinter printer = ZebraPrinterFactory.Current.GetInstance(PrinterLanguage.ZPL, connectionCheckStatus);

                        IPrinterStatus status = printer.CurrentStatus;

                        if (status != null)

                        {

                            statusValid = true;

                            if (status.IsPaperOut)

                                _messagePaper = "\n Attention, paper on printer is Ended, please insert before continue";

                            if (status.IsHeadOpen)

                                _messageHeadOpen = "\n Attetion, printer cover is not closed, please close cover before continue";

                        }

                        else

                        {

                            _messagePaper = string.Empty;

                            _messageHeadOpen = string.Empty;

                            _messageSleepingMode = string.Empty;

                            statusValid = false;

                        }

                    }

                    else

                    {

                        connectionOK = false;

                    }

                }

                catch(Exception ex)

                {

                   

                }

                finally

                {

                }

            });

            t.Wait();

            if(!connectionOK || !statusValid)

            {

                App.messagePaper = string.Empty;

                App.messageHeadOpen = string.Empty;

                App.messageSleepingMode = string.Empty;

                App.printerStatusValid = statusValid;

                App.printerConnection = connectionOK;

            }

            else

            {

                App.messagePaper = _messagePaper;

                App.messageHeadOpen = _messageHeadOpen;

                App.messageSleepingMode = _messageSleepingMode;

                App.printerStatusValid = statusValid;

                App.printerConnection = connectionOK;

            }

        }

This is the situation at run time :

Check_1.png

And when start printer.CurrentStatus call, the result is this :

Check_2.png

I try to ingnore this excption and continue the execution of code. So i start a new thread for printig (called printingTask) as you can see and wait in main thread the response. This is Print2 method :

        public void Print2(string address, string myZpl)

        {

            string zpl = myZpl;

            try

            {

                var t = Task.Run(() =>

                {

                    try

                    {

                        IConnection connectionPrint = ConnectionBuilder.Current.Build("BT:" + address);

                        connectionPrint.Open();

                        if ((SetPrintLanguage(connectionPrint)) && (CheckPrinterStatus(connectionPrint)))

                        {

                            connectionPrint.Write(Encoding.UTF8.GetBytes(zpl));

                            App.printingOK = true;

                        }

                        else

                            App.printingOK = false;

                    }

                    catch (Exception ex)

                    {

                        App.printingOK = false;

                    }

                });

                t.Wait();

            }

            catch (Exception e)

            {

                //if the device is unable to connect, an exception is thrown

                PrinterExceptions myPrinterExcepiton = new PrinterExceptions();

                string error = e.ToString();

                App.printingOK = false;

            }

            finally

            {

            }

        }

And this is SetPrintLanguage and check printer status method :

        private bool SetPrintLanguage(IConnection connection)

        {

            string setLanguage = string.Format("! U1 setvar \"device.languages\" \"zpl\"\r\n\r\n! U1 setvar \"formats.cancel_all\" \"\"\r\n\r\n!U1 setvar \"ezpl.media_type\" \"continuous\"\r\n\r\n! U1 setvar \"media.type\" \"journal\"\r\n\r\n! U1 getvar \"device.languages\"\r\n\r\n");

            byte[] response = connection.SendAndWaitForResponse(Encoding.UTF8.GetBytes(setLanguage), 1000, 1000);

            string s = Encoding.UTF8.GetString(response, 0, response.Length);

            if (!s.Contains("zpl"))

            {

                string error = "Not a ZPL printer.";

                return false;

            }

            return true;

        }

        public bool CheckPrinterStatus(IConnection connection)

        {

            bool returnValue = false;

            try

            {

                if (connection.IsConnected)

                {

                    IZebraPrinter printer = ZebraPrinterFactory.Current.GetInstance(PrinterLanguage.ZPL, connection);

                    IPrinterStatus status = printer.CurrentStatus;

                    if (!status.IsReadyToPrint)

                    {

                        string error = "Printer in Error: " + status.ToString();

                    }

                    else

                    {

                        returnValue = true;

                    }

                }

                else

                {

                    string connectionLose = "no connection available with printer";

                }

            }

            catch(Exception ex)

            {

                string message = ex.Message;

                returnValue = false;

            }

            return returnValue;

        }

On call on "connection.SendAndWaitForResponse" .. system go in exception (connection is ok as you can see) : Print_2_step1.png

Print2_step2.png

I think I have correctly replicated the logic to put checks and printing on the same task, but as you can see I still can not print. Am I doing something wrong?

Vote: 
Vote up!
Vote down!

Points: 0

You voted ‘up’


Anonymous (not verified)
Here are the recommendations

Here are the recommendations for using Link-OS SDK API, including Xamarin SDK.

  1. As a best pracitce, Zebra recommends not making calls to our API from the GUI thread. Use a seperate Thread or Task to accomplish this.
  2. Each ZebraPrinter object should only be used on a single thread

By following the recommendations, a lot of failures can be avoided. In the above code, the Task.Run() and Task.Wait() are used, which sounds like that a GUI thread is held until the Task.Run() finishes. Can we try using new Thread.run() or new Task() to spawn a thread or task to run on itself without synchronizing with the GUI thread? Hope this helps.

Vote: 
Vote up!
Vote down!

Points: 0

You voted ‘up’


Nicola Lazzara
Hi Steven, I thank you for

Hi Steven, I thank you for your availability, I also tried putting the "new" on the print thread (or on the thread to check the status of the printer), although in reality use Task.Run is the implicit way to instantiate a new task, the error remains exactly the same. I repeat that until the ios 11.2.1 version I was able to print successfully. Is your development team with the configuration I use able to print with a Zebra printer?

my application has been developed in xamarin.forms (pcl), the reference device is an ipad (with now the IOS version 11.2.5 installed). The version of the Zebra plugin for printing that I use is as follows: "LinkOS_Xamarin_SDK 1.1.75", while the firmware installed on the printer is this: "V73.20.10.10Z".

Currently the release of the application is likely not to be successful if you can not print.

Thank you for your kind attention

Nicola

Vote: 
Vote up!
Vote down!

Points: 0

You voted ‘up’


Anonymous (not verified)
Hi Nicola,Here is a simple

Hi Nicola,

Here is a simple program that prints out a barcode on iMZ320 (with V73.20.10Z). It demonstrates the flow of creating a connection, checking status and printing label. I verified that it works on iOS 11.2.5 and iMZ320 with LinkOS_Xamarin_SDK 1.1.75. You will need to change the namespace and the printer serial number in the code to match with yours. You may disable your code that related to Zebra SDK API. Simply plug in the below code and assign a button to Print() function. Hope this helps for debugging your code further.

using LinkOS.Plugin;

using LinkOS.Plugin.Abstractions;

using System;

using System.Threading;

using System.Text;

using Xamarin.Forms;

namespace HelloWorld // Update the namespace to yours

{

    public class LabelPrintTest

    {

        public LabelPrintTest() { }

        public void Print()

        {

            new Thread(printLabel).Start(); // Run a background thread for print and print related.

        }

        public void printLabel()

        {

            string message = "";

            IConnection connection = null;

            try

            {

                connection = ConnectionBuilder.Current.Build("BT:XXXXJ134101571"); // iMZ320. Change it to the Serial Number of yours.

                connection.Open();

                IZebraPrinter printer = ZebraPrinterFactory.Current.GetInstance(PrinterLanguage.ZPL, connection);

                IPrinterStatus status = printer.CurrentStatus;

                if (status.IsReadyToPrint) {

                    String testLabel1 = @"^XA^FO20, 10^BY2^BEN,70,Y,N^FD8033609249442^FS^XZ";

                    connection.Write(Encoding.UTF8.GetBytes(testLabel1));

                }

            }

            catch (Exception e)

            {

                message = "Exception: " + (e.Message);

            }

            finally

            {

                if ((connection != null) && (connection.IsConnected))

                {

                    connection.Close();

                }

            }

        }

    }

}

Vote: 
Vote up!
Vote down!

Points: 0

You voted ‘up’


Nicola Lazzara
thanks steve, you have been

thanks steve, you have been very kindly, but I would like to ask you how to handle the possibility of waiting for the end of the printing process so you can notify if it was successful or not.

if i write this code :

                    Task myPrintTask = new Task(Print);                 

                    myPrintTask .Start();

                    myPrintTask .Wait();

the code go in catch on printer.GetStatus .. meanwhile if i call Print with this :

newTask(Print) .. print is ok, but main thread  continues its execution without waiting for the printing process

Vote: 
Vote up!
Vote down!

Points: 0

You voted ‘up’


John Ferlazzo
Hi Nicola,My recommendation

Hi Nicola,

My recommendation would be to play around with the async methods and await keyword (This is what I use).

However, if you are comfortable with the way you are currently using Tasks I would recommend that you implement a Task.ContinueWith method. The main thread will continue execution while the background task runs. When the Task is completed, it will execute the ContinueWith action (You may need to check and specify that whatever is in this method runs on the main thread if you need it to).

As an example:

Task.Run(() =>

{

     // Do work on background here

})

.ContinueWith(() =>

{

     // Do work when task is completed here such as show a dialog on UI that printing is complete

},

TaskScheduler.FromCurrentSynchronizationContext());

Documentation:

https://msdn.microsoft.com/en-us/library/dd270696%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

Vote: 
Vote up!
Vote down!

Points: 0

You voted ‘up’


Log in to post comments