forked from emilevs/label_printer
115 lines
2.2 KiB
Go
115 lines
2.2 KiB
Go
package printer
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
type Printer interface {
|
|
io.Reader
|
|
io.Writer
|
|
io.Closer
|
|
}
|
|
|
|
type usbPrinter struct {
|
|
*os.File
|
|
}
|
|
|
|
const (
|
|
FlagNone = 0
|
|
FlagDebug = 1 << 0
|
|
)
|
|
|
|
func OpenUSBPrinter(path string, flags int) (Printer, error) {
|
|
file, err := os.OpenFile(path, os.O_RDWR, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var printer Printer = usbPrinter{file}
|
|
if flags&FlagDebug != 0 {
|
|
printer = withDebugger(printer)
|
|
}
|
|
return printer, nil
|
|
}
|
|
|
|
func (usb usbPrinter) Write(p []byte) (int, error) {
|
|
// The printer often doens't like it if we use multiple write syscalls to
|
|
// transmit the data. usb.File.Write() doesn't seem to guarantee that it
|
|
// will only use a single syscall, so we manually call write instead.
|
|
return unix.Write(int(usb.Fd()), p)
|
|
}
|
|
|
|
type debugger struct {
|
|
Printer
|
|
lastError error
|
|
}
|
|
|
|
func withDebugger(printer Printer) Printer {
|
|
return &debugger{
|
|
Printer: printer,
|
|
lastError: nil,
|
|
}
|
|
}
|
|
|
|
func (d *debugger) Read(p []byte) (n int, err error) {
|
|
n, err = d.Printer.Read(p)
|
|
|
|
if err == io.EOF {
|
|
return
|
|
}
|
|
|
|
// don't spam the terminal with the same error again and again
|
|
if err != nil && d.lastError != nil && err.Error() == d.lastError.Error() {
|
|
return
|
|
}
|
|
d.lastError = err
|
|
|
|
var builder strings.Builder
|
|
fmt.Fprint(&builder, " \033[31m")
|
|
for i, b := range p[:n] {
|
|
if i > 0 {
|
|
fmt.Fprint(&builder, " ")
|
|
}
|
|
fmt.Fprintf(&builder, "%08b", b)
|
|
}
|
|
if err != nil {
|
|
if n > 0 {
|
|
fmt.Fprint(&builder, " ")
|
|
}
|
|
fmt.Fprintf(&builder, "read error: %v", err)
|
|
}
|
|
fmt.Fprintf(&builder, "\033[0m\n")
|
|
|
|
fmt.Fprint(os.Stderr, builder.String())
|
|
|
|
return
|
|
}
|
|
|
|
func (d *debugger) Write(p []byte) (n int, err error) {
|
|
n, err = d.Printer.Write(p)
|
|
|
|
printSize := len(p)
|
|
max := 20 * 8 * 2
|
|
if printSize > max {
|
|
printSize = max
|
|
}
|
|
fmt.Fprintf(os.Stderr, "\033[36m%s\033[0m", hex.Dump(p[:printSize]))
|
|
if len(p) > printSize {
|
|
fmt.Fprintf(os.Stderr, " \033[36m[%d bytes omitted]\033[0m\n", len(p)-printSize)
|
|
}
|
|
|
|
if err == nil && n == len(p) {
|
|
log.Printf("wrote %d bytes to printer\n", n)
|
|
} else {
|
|
log.Printf("only wrote %d/%d bytes to printer: %v\n", n, len(p), err)
|
|
}
|
|
|
|
return
|
|
}
|