I have an Epson TM-T88III pos printer on a Linux machine hooked up on a USB port. All is working relative good, It gets recognised, I can open the device, I can echo "Hello World" on the commandline to the printer and it prints without problem.
However in golang when I open the device with os.OpenFile and write some test sequences either as byteslice or string it only prints that sequence after I do another write.
Can somebody explain if I miss something in what I need to do? I am a relative beginner in golang but I do program in other languages.
I open with:
f, err := os.OpenFile("/dev/usb/lppos",os.O_RDWR,0755)
if err != nil {
panic(err)
}
defer f.Close()
Then I define some esc commands and catch them in a byteslice (i use the escpos package of panjjo for that):
p := escposc.New()
p.Init()
p.SetSmooth(1)
p.SetFontSize(2, 3)
p.SetFont("A")
p.Write("test ")
p.SetFont("B")
p.Write("test2 ")
p.Formfeed()
p.SetFont("B")
p.SetFontSize(1, 1)
p.SetEmphasize(1)
p.Write("halle")
p.Formfeed()
p.SetUnderline(1)
p.SetFontSize(4, 4)
p.Write("halle")
p.SetReverse(1)
p.SetFontSize(2, 4)
p.Write("halle")
p.Formfeed()
p.FormfeedN(5)
p.Cut()
_,b:=p.Readbyte()
p.End()
Then I write the catched slice b to the device:
n,err:=f.Write(b)
if err != nil {
panic(err)
}
At this point nothing happens, and it took me a while to find out that if I do a last:
f.WriteString(" ")
Then all sequences get printed as should, with all the styling, linefeeds and cut. And all is well, but not without that last WriteString. Oh yes, It does need the space or other character, writing an empty string does not work.
I also tried to write a string of commands instead of a byteslice, but I need the same 2nd WriteString or it wont output on the paper roll.
You have to do f.Sync()
. From the docs: Sync commits the current contents of the file to stable storage.
(https://golang.org/src/os/file_posix.go?s=3352:3379#L11). And after you end using the device, you may have to do f.Close()
.
Your problem is that you call
p.End()
after
p.Readbyte()
While you should do it before. I beleve your printer treats " "(space) as an invalid command and automatically finishes a preceding sequence of valid commands.
Looks like you have captured the byte slice before you were finished writing to it.
p.Cut()
_,b:=p.Readbyte()
p.End()
The byte from the call to p.End()
never gets added to your output data, so the printer waits forever for it...
As shown in the example, this should be instead:
p.Cut()
p.End()
_,b:=p.Readbyte()
I am going to answer my own question. Last few days I spent writing my own implemententation of escpos in golang. I learned a few things along the way. Main thing is that the thermal printer will decide itself what to buffer and how to do that. It means you need to open the device and without buffering you write commands to it.
In the golang escpos packages around on github (which, in my opinion, are incomplete) io.Writer is used to stream the commands. Instead of that you need to use *os.File and use its Write method to stream the command directly to the printer. This works immediately and flawless on my Epson TM-T88III thermal printer.
Basicly I changed the following core of the escpos code:
type Escpos struct {
enc *encoding.Encoder
w io.Writer
}
func NewEscpos(w io.Writer) *Escpos {
return &Escpos{
enc: charmap.CodePage437.NewEncoder(),
w: w,
}
}
func (e *Escpos) write(b []byte) error {
_, err := e.w.Write(b)
return err
}
Into this new code where I can open a device and give the pointer to the file handle as parameter to the Escpos type reference, when the command sequence is done I can close the device. Meanwhile it outputs the receipt and the printing I want on it.
type Escpos struct {
enc *encoding.Encoder
f *os.File
}
func NewEscpos(f *os.File) *Escpos {
return &Escpos{
enc: charmap.CodePage437.NewEncoder(),
f: f,
}
}
func (e *Escpos) write(b []byte) error {
_, err := e.f.Write(b)
return err
}