How to send ESC/POS commands to thermal printer in Linux

30.9k views Asked by At

I am trying to send ESC/POS commands on a thermal printer. But whenever i send them thermal printer prints them as a text instead of executing them as commands. I am writing these commands in a .prn file and whenever i executes lp command to print a file these .prn file also get printed but as a text.

I tried following method to write ESC/POS command in .prn file :

1) PRINT #1, CHR$(&H1D);"h";CHR$(80);
   PRINT #1, CHR$(&H1D);"k";CHR$(2);
   PRINT #1, "48508007";CHR$(0);
   PRINT #1, CHR$(&HA);
   PRINT #1, CHR$(&H1D);"k";CHR$(67);CHR$(12);
   PRINT #1, "48508007";

2) <ESC>(0x1B) <L>(0x4C)
   <GS>(0x1D) <k>(0x6B) 73 2 4 5 6 7 8 9 NUL
   <FF>(0x0c)

3) <ESC L>
   <GS k 73 2 4 5 6 7 8 9 NUL>

4) "ESC L" "GS k 73 2 4 5 6 7 8 9 NUL" "FF" I also tried sending ESC/POS command using C program as:

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>

int main() {
   int fd,ret;
   char buf[] = "HELLO"

   fd = open("/dev/bus/usb/003/007",O_WRONLY);
   if(fd < 3) {
      perror(open failed);
   }

   ret = write(fd,&buf,sizeof(buf));
   if(ret == -1) {
      perror("write failed");
   }
}

Upon execution the above code gives error as:

write failed: invalid arguments
3

There are 3 answers

0
mike42 On

There are actually two issues here: data transport, and the data being transported.

Data transport: Use usblp

For getting the data to the printer, check that usblp is loaded. It allows you to expose the printer as a file in the lp group, so that you can open it as /dev/usb/lp0.

Once this works, as a regular user you can write:

echo "Hello" > /dev/usb/lp0

I wrote a blog post on the topic which covers the permissions side of this.

Data format

Secondly, the data itself needs to be sent in the correct binary format. A printer will not understand this human-readable .prn (print?) file directly, so it needs to be converted to the correct binary format.

To interpret a few things from your question:

  • ESC means \x1b, an ASCII escape
  • k means ``, the actual ASCII letter k
  • CHR$(80) means \x50, which is how the number 80 is sent to the printer.
  • CHR$(&H1D); means \x1d, an ASCII group separator (GS)

You can write some basic commands directly on the CLI using echo -e. Maybe the simplest non-text example is a CODE39 barcode that says '000'.

This same command in human-readable form, then hex, then as a terminal command would be:

  • GS k 4 0 0 0 NUL
  • 1d 6b 04 30 30 30 00
  • echo -e '\x1d\x6b\x04000\x00' > /dev/usb/lp0

Your best reference for this format is your printer's programming manual, but hopefully this helps you to interpret it.

Be aware that the commands you are trying to execute contain errors, and one of them will even will trap you in page mode.

Aside, the answers by @scruss and @abartek are completely accurate: Check that CUPS hasn't claimed the port by using the lsusb command, and use a hex editor to review your output, or a library to generate known-good commands.

3
abartek On

If you sure about the hex codes, you can use your favourite hex editor to make a proper command prn file. Or you can pick one from here: Need a good hex editor for Linux
Why hex editor? Because all other way including some hidden content (like new line 0x0d) and the printer cannot understand the command sequency. Probably other problem is the program what you use to deliver a command - some program sometimes add other content or make some conversation when sending it to the printer (like extra page down). Be sure - your program cannot do this.
My way of problem solving this time:

  • be sure, the escape sequencies are correct. (Some printer use special escape sequency, to mark - the next bitstream will be command, not data)
  • be sure, the file what you would like to send to the printer is correct (no additional code in the file - easy way to check is mc viewer - hex mode view (F4))
  • be sure, the delivery to the printer is bitvise correct - the delivery program not manipulate the command file (use man to check it) - like convert non printable characters to hex code
0
scruss On

If the thermal printer is connected via USB, there's a good chance that CUPS will have claimed the port. Consequently, you won't be able to send data to it as a normal user.

To send the raw bytes via cups, use either lpr -l file or lp -o raw file. To inspect the bytes you're going to send, use the xxd hex viewer. These printers typically take CRLF at the end of line, so be sure to send \r\n.

I don't have a C library for you, but I've had success with python-escpos