Zebra Printer Calibration - c#

I'm using Zebra printer model ZQ520 and connecting to it through application in C#.
string zpl = "^XA^FO20,20^A0N,25,25^FDThis is a ZPL test.^FS^XZ";
try
{
connection.Open();
string setLang = "! U1 setvar \"device.languages\" \"zpl\"\r\n";
string calibrate = "~jc^xa^jus^xz\r\n";
connection.Write(Encoding.UTF8.GetBytes(setLang));
connection.Write(Encoding.UTF8.GetBytes(calibrate));
connection.Write(Encoding.UTF8.GetBytes(zpl));
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("Exception:" + e.Message);
}
The issue is the printer is printing out an excessive amount of paper. It doesn't print "This is a ZPL test." until I press the line feed button on the printer, and then it printer more excess paper after the desired message.
Any idea what issue might be?

Have you checked the ^LL (Label Length) command. Look it up in your Zebra Programming Language guide.
I also know when I was doing Zebra (and also Intermec), the device itself had machine settings / display using buttons and arrows to change such default settings as page sizes, if thermal, what burn strength 0-30, etc., so you did not have to invoke those on every label submit.
I was also communicating directly with serial port using USB to RS232 connector cable, but it has been a while.

You may try to use the following code to communicate with the printer:
using (var tcpClient = new TcpClient())
{
try
{
var ipAddress = "127.0.0.1";
var printerPort = 9001;
tcpClient.Connect(ipAddress, printerPort);
using (var tcpClientStream = new StreamWriter(tcpClient.GetStream()))
{
var deviceLang = "! U1 setvar \"device.languages\" \"zpl\"\r\n");
tcpClientStream.Write(deviceLang );
tcpClientStream.Flush();
var calibrate = "~jc^xa^jus^xz";
tcpClientStream.Write(calibrate);
tcpClientStream.Flush();
Thread.Sleep(500);
string zpl = "^XA^FO20,20^A0N,25,25^FDThis is a ZPL test.^FS^XZ";
// with ^LL: string zpl = "^XA^LL400^FO20,20^A0N,25,25^FDThis is a ZPL test.^FS^XZ";
tcpClientStream.Write(zpl);
tcpClientStream.Flush();
tcpClientStream.Close();
}
tcpClient.Close();
}
catch (Exception ex)
{
Logger.Error(ex); // replace with your own logger or console
}
}
This should print the expected text immediately. Other than that, for continuous media (i.e. no gaps). I'm not familiar with this particular model but according to this:
https://supportcommunity.zebra.com/s/article/Calibrating-Zebra-QLn-Series-Mobile-Printers?language=en_US
You need to send the following command: ! U1 setvar "media.type" "journal" then set the label length somehow, for example ^LL400.
Also you may try to comment the deviceLang and calibrate commands, not 100% sure those are really required (on the ZT610 they're definitely not, as you can calibrate the printer using buttons).

Related

Cannot print on printer Olivetti PR 4 SL

I'm trying to print on Olivetti PR 4 SL. In of out .NET application ("Print Test Page", Word, ...) it works. But in my .NET application, it doesn't.
This is my simplified code:
using (var serialPort = new SerialPort())
{
serialPort.PortName = "COM1"; // Where the printer is installed.
serialPort.Open();
serialPort.Write("Hello world!");
}
The error message is:
The given port name does not start with COM/com or does not resolve to
a valid serial port. Parameter name: portName
Would anyone help me to solve this problem?
You need to finalize the character stream which are sent to the printer by NEW_LINE (ASCII code is 10).
You can use the following line of code in order to print;
serialPort.Write(new byte[] { 10 });

Using Silverlight to send ZPL commands to a Zebra printer works only for limited numbers of labels

I developed an in-browser Silverlight application that consist in a button. When it pressed it open a Socket to send ZPL commands to a Zebra Printer (model RZ400).
I made all the required actions to allow in-browser app to open connection to other hosts.
The printer works well except that it print only a limited number of labels (27) even if the socket send right all the data to the printer (that consist in 48 labels, about 440 bytes each).
To be sure, I check the buffer size of the socket that is 65536 bytes. The amount of data that I send to the printer through the socket is only 21282 bytes.
foreach (Label l in args.Labels)
{
saea = new SocketAsyncEventArgs();
printCommand = GetPrintCommandFromLabelAndPRN(l, args.SelectedPrinter.prn);
buffer = Encoding.UTF8.GetBytes(printCommand);
saea.SetBuffer(buffer, 0, buffer.Length);
willRaiseEvent = args.ConnectionSocket.SendAsync(saea);
totBytes += buffer.Length;
Log("Pack " + l.data + " inviato al socket di stampa");
}
The method GetPrintCommandFromLabelAndPRN build the PRN command for a single label:
private string GetPrintCommandFromLabelAndPRN(Label l, string prn)
{
// Codice e RFID
string aux = prn.Replace("{code}", l.code).Replace("{epc}", l.data);
// Meta
foreach (labelMeta meta in l.meta)
{
if (meta.key != null && !meta.key.Equals(String.Empty))
{
aux = aux.Replace("{" + meta.key + "}", meta.value);
}
}
return aux;
}
And this is the PRN template:
^XA
~SD25
^FO10,70^XGE:LOGO.GRF,1,1^FS
^FT275,65^A0N,29,28^FH\^FDArticolo:^FS
^FT375,65^A0N,29,28^FH\^FD{code}^FS
^FT509,65^A0N,25,24^FH\^FD{description1}^FS
^FT275,99^A0N,25,24^FH\^FD{description2}^FS
^BY2,3,57^FT275,166^BCN,50,Y,N,N^FD>:{code}^FS
^FT50,225^A0N,29,28^FH\^FDLotto:^FS
^BY2,3,35^FT130,225^BCN,30,Y,N,N^FD>:{lotCode}^FS
^PQ1,0,1,Y
^RR2
^RS8,300,50,2,N
^RW20,20
^RFW,H
^FD{epc}^FS
~RVE
^XZ
I try to do the same in Java, with the same PRN, using PrintWriter and it works correctly. So I exclude that is a printer issue.
I would bet that the printer is queuing up your labels and that is what causes it to stop at 27. Have you tried sending one at a time just to test to see if you might need to let the printer 'catch up' with the print jobs you are sending? We used to have an issue similar to this - when we slowed down the loop to the printer it allowed the printer to work at it's own rate just fine, but labels came out at a slower rate.

Sending PDF to Thermal Printer (Zebra) using c#

I am trying to send a PDF to a thermal printer using c#. I have looked at the RawPrinterHelper class here http://support.microsoft.com/kb/322091 but the SendFileToPrinter is not printing the file.
There is no error and the file appears to be printing from the print queue but nothing happens.
The printer works fine as I have been able to print other items on it.
Does anyone know how I can send a PDF to print or how I can possibly use the SendFileToPrinter to work for me.
I am working on Windows 7.
Here is a sample of the code I am using to call the SendFileToPrinter method.
try
{
RawPrinterHelper.SendFileToPrinter(PrinterName,#"C:\test.pdf");
}
catch (Exception ex)
{
Console.WriteLine(" EXCEPTION: {0}", ex.Message);
}
Update:
Ok, maybe I spoke too soon. I am able to print the PDF to the thermal printer but the issue now is that this is taking a couple of seconds to print and I am looking for something that is "quick". The reason it is slow is that Adobe needs to open up first.
Anyone have any ideas on how to get around this?
Ok, actaully got it sorted.
I was able to do the following and it works perfectly.
string tempFile = #"C:\test.pdf";
try
{
ProcessStartInfo gsProcessInfo;
Process gsProcess;
string printerName = PrinterName;
gsProcessInfo = new ProcessStartInfo();
gsProcessInfo.Verb = "PrintTo";
gsProcessInfo.WindowStyle = ProcessWindowStyle.Hidden;
gsProcessInfo.FileName = tempFile;
gsProcessInfo.Arguments = "\"" + printerName + "\"";
gsProcess = Process.Start(gsProcessInfo);
if (gsProcess.HasExited == false)
{
gsProcess.Kill();
}
gsProcess.EnableRaisingEvents = true;
gsProcess.Close();
}
catch (Exception)
{
}
#DavidCrowell, thats for the assistance.
Noel.

C# and serial communication how to flush the device to read same data again?

Okay so I am stuck for almost 20 days now in the same problem of a serial communication device. I have a hardware sensor which read tags and returns the tag code number on every read through serial com port 1 or 3.Any of these I use doesn't matter. I am using a program I wrote in c# to play with the incoming data.
Now problem is that if forexample:
my sensor reads tag with code "e2 0 10 1 83 10 1 23 7 0 d0 c0 1 be"
It will not read this tag again unless I switch of the sensor and turn it on again (Power reset) . So I can't figure out how to make my sensor forget all the data it read till I closed the port. ANY ONE CAN HELP PLEASE I AM DESPERATE NOW
Some one told me that we need to write to device with some commands but he didn't know more than that.
Here is the current code:
void IntializeSensor()
{
try
{
if (mySerialPort==null)
{
mySerialPort = new SerialPort("COM3");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.ReadTimeout = 2000;
mySerialPort.Handshake = Handshake.None;
LoglistBox.Items.Add("--Port Intilalized at COM1--");
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void OpenPort()
{
try
{
str = "";
if (mySerialPort.IsOpen)
{
ClosePort();
Thread.Sleep(6000);
}
mySerialPort.Open();
LoglistBox.Items.Add("--Port Opened at COM1 Success--");
}
catch (Exception ex)
{
LoglistBox.Items.Add("--Port Opened Failed--Error: "+ex.Message);
}
}
void ClosePort()
{
try
{
mySerialPort.Write("ABCABCABCABCABC");
mySerialPort.DiscardInBuffer();
mySerialPort.DiscardOutBuffer();
mySerialPort.Dispose();
mySerialPort.Close();
LoglistBox.Items.Add("--Port Closed at COM1 Success--");
}
catch (Exception ex)
{
LoglistBox.Items.Add("--Port Closed Failed--Error: " + ex.Message);
MessageBox.Show(ex.Message);
}
}
private void DataReceivedHandler(object sender,SerialDataReceivedEventArgs e)
{
try
{
if (e.EventType != SerialData.Chars) return;
SerialPort COMPort = (SerialPort)sender;
int bytes = COMPort.BytesToRead;
//create a byte array to hold the awaiting data
byte[] comBuffer = new byte[bytes];
//read the data and store it
COMPort.Read(comBuffer, 0, bytes);
// System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
str = ByteArrayToHexString(comBuffer);
holdfirstvalue += str;
//str = str +" "+ str;
//MessageBox.Show("after concat "+str);
if (str.Contains("FF") || str.Contains("F F") || str.Contains("F"))
{
SetText(holdfirstvalue.ToString());// ONE TAG CODE SENT TO BE SET IN LIST
str = "";
holdfirstvalue = "";
}
}
catch (Exception ex)
{
// LoglistBox.Items.Add("--Port Opened Failed--Error: " + ex.InnerException);
MessageBox.Show(ex.Message+" "+ex.InnerException);
}
}
As I understood from your comments, even the program that is shipped with it does not read the same bar-code twice in a row. Am I right?
To me it seems that "the tag reader manufacturer" may have put that mechanism intentionally to prevent user mistakenly scan an item twice at check-out. because it happens a lot that a same stays on the scanner or be crossed against the scanner couple of times when moving things around.
Unless you have access to the scanner Firmware and are able to make changes yourself, I'd say contact the manufacturer. I would contact the manufacturer and ask about this directly. There should be a command that tells the scanner to "Get out of lock mode and restart scanning again" for the special case of scanning a same item several times (e.g. buying multiple similar things.)
They should provide you with a manual with the list of all the commands you can send to your device and you use this commands to build up your system.
One more thing to try! can you scope out your serial port using "Real Term" or any other terminal monitoring application to see if the scanner sends the code to the PC after you scan the same item again or not? This helps you to isolate the problem to make sure if it is the Scanner Firmware or the desktop software. (it seems to me that it is the scanner Firmware ignoring the item because you say it works fine when you reset it)
edit: also I see you are reading your serial port based on DataREadyEvent, again, if it was me, I would add another thread with a very short delay say 20ms or 50ms to keep reading the serial port constantly. there are plenty of examples on how to implement this on the net, one simple and quick way of this is described here:
Read com ports using threading in c#
Hope it helps.
Ok so I finally found the code in hex which actually resets the sensor.
So to help anyone out there who bought Middle Range UHF RFID Reader or any type of this model.
What we did is we hacked into the wires of serial port by soldering copper wire on data pins. Then we attached the other end of those copper wires to my laptop and used the terminal reader "Putty" to see what is actually being sent by the PC to the Reader on RESET HEAD button click.
This way we found the hex code , converted it to byte array and here is the C# code to write it to reader device by serial port and resets the device:
{
mySerialPort.Open();
byte[] bytesToSend = StringToByteArray("A00265F9");// correct command to reset READER
mySerialPort.Write(bytesToSend, 0, 4);
}
public static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}

Unable to read from Serial Port using C# Mono (RaspberryPi)

I'm attempting to write a C# library which looks at all available USB serial ports on a Raspberry Pi so that I can enumerate, identify and communicate with a set of Arduinos connected to the Pi via a USB hub.
I am able to make this work on my windows machine (several Arduinos connected to my desktop computer) and have even been able to make it work on my Pi however, I am struggling to understand how to generalize the fix.
If I attempt to run the program by itself on the Pi, I am able to open the serial port and send data however, I cannot receive anything from the Arduinos: I get timeout exceptions. I understand that Mono's implementation of SerialPort is limited and I must use SerialPort.ReadByte() instead of Readline() and the data received events (my solution is based on code from HowToSystemIOPorts). My Serial port enumeration is using a method outlined in another stack exchange response here.
My timeout is currently set to 4 seconds, which is several orders of magnitude longer than I expect to receive the message.
After a lot of googling, I came across mention of using minicom to initialize the serial port here, which to my surprise allowed me to receive data from the Arduino. The biggest drawback is that I need to initialize the port using minicom and leave the process opening each time I boot the Pi. I also can't seem to figure out how to make this work with multiple Arduinos.
Here is what I have tried so far:
Updated the Pi firmware and software to their latest versions
Attempted to use both an Arduino MEGA 2560 R3 and Arduino UNO
Changed the owner of the tty* ports (ttyACM0 and ttyUSB0 in this case) to both my user and group
Successfully configured the port via minicom, left the process running and start the program and read/wrote data. A manual process which only seems to work for one Arduino at a time
Successfully run the program in Windows without fault
Verified the Arduinos are recognized by the Pi running "dmesg | grep tty"
Here is what I hope to solve:
Automatic setup/initialization of the Arduino serial ports. Whether through a shell script run before the main program or within Mono code so that the code below can run as intended.
Here is my connection code:
public bool StartArduinoComms()
{
string[] ports = GetPortNames();
foreach (string port in ports)
{
mLogger.LogMessage(ProsthesisCore.Utility.Logger.LoggerChannels.Arduino, string.Format("Found serial port {0}", port));
}
bool foundCorrectArduino = false;
var idPacket = new ArduinoMessageBase();
idPacket.ID = ArduinoMessageValues.kIdentifyValue;
string jsonOutput = Newtonsoft.Json.JsonConvert.SerializeObject(idPacket);
foreach (string port in ports)
{
SerialPort serialPort = new SerialPort(port, kArduinoCommsBaudRate);
serialPort.Parity = Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
//Only check unopened ports
if (!serialPort.IsOpen)
{
serialPort.Open();
//Disable telemtry just incase
var toggle = new { ID = ArduinoMessageValues.kTelemetryEnableValue, EN = false };
string disableTelem = Newtonsoft.Json.JsonConvert.SerializeObject(toggle);
serialPort.Write(disableTelem);
//Discard any built up data
serialPort.DiscardInBuffer();
serialPort.Write(jsonOutput);
serialPort.ReadTimeout = kIDTimeoutMilliseconds;
string response = string.Empty;
for (int i = 0; i < kNumRetries; ++i)
{
try
{
//This is guaranteed to timeout if not configured through minicom
response = ReadLine(serialPort);
break;
}
//Catch case where the serial port is unavailable. MOve to next port
catch (TimeoutException)
{
continue;
}
}
if (!string.IsNullOrEmpty(response))
{
//Perform response validation
}
else
{
//Got no response
}
if (!foundCorrectArduino)
{
serialPort.Close();
}
}
}
return foundCorrectArduino;
}
/// <summary>
/// From https://stackoverflow.com/questions/434494/serial-port-rs232-in-mono-for-multiple-platforms
/// </summary>
/// <returns></returns>
private static string[] GetPortNames()
{
int p = (int)Environment.OSVersion.Platform;
List<string> serial_ports = new List<string>();
// Are we on Unix?
if (p == 4 || p == 128 || p == 6)
{
string[] ttys = System.IO.Directory.GetFiles("/dev/", "tty*");
foreach (string dev in ttys)
{
//Arduino MEGAs show up as ttyACM due to their different USB<->RS232 chips
if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM"))
{
serial_ports.Add(dev);
}
}
}
else
{
serial_ports.AddRange(SerialPort.GetPortNames());
}
return serial_ports.ToArray();
}
Have a look at stty command. It will let you set/read teminal settings
http://linux.about.com/od/lna_guide/a/gdelna38t01.htm will give a rundown on it's use.
It would be easier to call out to than minicom, and the settings stay on the device.
I have done something like the same as you before.
I had to read and write data through USB Serial adapter, and didnt use minicom.
It may not be god code but i found that inorder to read the data I could create a new thread and have that check for data, my code include a lot of stuff but basicly i did this:
System.Threading.Thread newThread;
newThread = new System.Threading.Thread(this.check_get_data);
and the check_get_data method
public void check_get_data ()
{
byte tmpByte = 0;
while (m_objSerialPort.BytesToRead != 0) {
tmpByte = (byte)m_objSerialPort.ReadByte ();
DoSomethingWithByte(tmpByte);
Thread.Sleep(20);
}
}
this is currently running with two usbserials. dont know if it helps but hope you find your solution

Categories

Resources