tmt88v

package module
v0.0.0-...-7ec63a1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 7, 2026 License: MIT Imports: 20 Imported by: 0

README

tm-t88v

Go library and CLI for the Epson TM-T88V (M244A) thermal receipt printer. It provides:

  • A low-level ESC/POS command builder (escpos package)
  • A high-level Printer API and receipt builder (tmt88v package)
  • USB and file-based transports
  • A CLI tool for quick printing and status checks

Requirements

  • Go 1.24+
  • Linux access to the printer device (usually /dev/usb/lp0)
  • Optional: libusb-1.0 when using the USB transport (-tags libusb)

Installation

go get github.com/AkatukiSora/tm-t88v

Quick Start

File transport (default)
package main

import (
    "log"

    "github.com/AkatukiSora/tm-t88v"
)

func main() {
    p, err := tmt88v.Open("/dev/usb/lp0")
    if err != nil {
        log.Fatal(err)
    }
    defer p.Close()

    if err := p.Init(); err != nil {
        log.Fatal(err)
    }

    if err := p.PrintText("Hello TM-T88V\n"); err != nil {
        log.Fatal(err)
    }

    if err := p.FeedAndCut(); err != nil {
        log.Fatal(err)
    }
}
USB transport (libusb)
transport, err := tmt88v.OpenUSB()
if err != nil {
    // Build with: go build -tags libusb ./...
    log.Fatal(err)
}
defer transport.Close()

p, err := tmt88v.New(transport)
if err != nil {
    log.Fatal(err)
}
defer p.Close()

Receipt Builder

if err := p.Receipt().
    Header("My Shop").
    Text("Item 1").
    LineItem("Coffee", "$3.50").
    QRCode("https://example.com").
    Cut().
    Print(); err != nil {
    log.Fatal(err)
}

Image Printing

// Uses paper width and dithering options when converting to raster.
printer, _ := tmt88v.New(transport, tmt88v.WithPaperWidth(576), tmt88v.WithDithering(true))
_ = printer.PrintImage(img)

Status Monitoring

monitor := tmt88v.NewStatusMonitor(transport, func(s tmt88v.Status) {
    log.Printf("status: %+v", s)
})

if err := monitor.Start(context.Background()); err != nil {
    log.Fatal(err)
}
defer monitor.Stop()

CLI

Build the CLI:

go build ./cmd/tmt88v/

Examples:

./tmt88v status
./tmt88v test-print
./tmt88v print-text "Hello"
./tmt88v print-image ./examples/image/sample.png
./tmt88v print-barcode code128 "12345"
./tmt88v print-qr "https://example.com"
./tmt88v cut
./tmt88v drawer

# Use USB transport instead of /dev/usb/lp0
./tmt88v -u status

Run ./tmt88v help <subcommand> for full command usage.

Libusb-First Strict Verification

When using the USB transport (-u flag or OpenUSB()), the library enforces a strict success definition: a print operation is only considered successful when:

  1. The print data was written and flushed to the printer.
  2. A DLE EOT status query was sent and a response was received.
  3. The response indicates no fault conditions (online, no cover open, no paper end, no errors).
Strict Success Checklist
# 1. Build with libusb support
go build -tags libusb ./cmd/tmt88v/

# 2. Check USB readiness (optional pre-flight)
./tmt88v -u status

# 3. Print with strict post-print verification
./tmt88v -u print-text "Hello"
# Exit 0 = print completed AND status verified OK
# Exit 1 = print failed OR status fault detected (reason code in stderr)
Status Command

The status command requires the USB transport (-u) when the device path is a usblp path (/dev/usb/lp*). The usblp kernel driver does not support bidirectional reads, so DLE EOT status queries cannot be used over it.

# Correct: use USB transport for status
./tmt88v -u status

# Wrong: will fail with guidance
./tmt88v -d /dev/usb/lp0 status
# Error: status requires USB transport: device "/dev/usb/lp0" is a usblp path; re-run with -u flag and a libusb build
Failure Codes and Troubleshooting

When a USB open fails, the CLI emits a canonical failure code:

Error: open USB transport code=<code>: <detail>
Code Meaning Linux Remediation
permission_denied No access to USB device sudo chmod a+rw /dev/bus/usb/XXX/YYY or add a udev rule: SUBSYSTEM=="usb", ATTR{idVendor}=="04b8", MODE="0666"
device_not_found Printer not found at expected VID:PID Check USB cable; verify printer is powered on; run lsusb | grep 04b8
interface_busy usblp driver has claimed the interface sudo modprobe -r usblp
timeout USB transfer timed out Check USB cable quality; try a different USB port; check dmesg for USB errors
unknown Unclassified error Check dmesg -w for USB errors; try sudo udevadm trigger
Post-Print Status Fault Codes

When a print operation completes but the strict status check fails, the error contains a machine-readable reason code:

Reason Code Meaning
offline Printer is offline
cover_open Printer cover is open
paper_end Paper is out
recoverable_error Recoverable error (e.g. paper jam)
autocutter_error Autocutter error
unrecoverable_error Unrecoverable hardware error
auto_recoverable_error Auto-recoverable error

Note: paper_near_end is a warning only and does not cause a fault.

Examples

go run ./examples/basic
go run ./examples/receipt
go run ./examples/barcode
go run ./examples/image
go run ./examples/status

Tests

go test ./...

Integration tests (requires printer access):

TMT88V_DEVICE=/dev/usb/lp0 go test -tags integration ./... -v

Libusb integration tests (requires printer + libusb build):

go test -tags integration,libusb ./... -v

Non-cgo libusb build verification:

CGO_ENABLED=0 go test -tags libusb ./...

Notes

  • Default device is /dev/usb/lp0 (usblp driver). Ensure your user has access.
  • USB transport requires libusb-1.0 and build tag libusb.
  • Status queries require the USB transport (-u); usblp does not support bidirectional reads.
  • The USB transport enforces strict post-print status verification when used via the CLI.

License

MIT

Documentation

Overview

Package tmt88v provides a comprehensive Go library for the Epson TM-T88V (M244A) thermal receipt printer. It supports all ESC/POS commands supported by the TM-T88V, with both a low-level command builder API and a high-level receipt builder API.

Connection

Connect to the printer via USB (/dev/usb/lp0) using FileTransport, or via direct USB bulk transfer using USBTransport (requires libusb-1.0).

Usage

p, err := tmt88v.Open("/dev/usb/lp0")
if err != nil {
    log.Fatal(err)
}
defer p.Close()

p.Receipt().
    Header("My Shop").
    Text("Item 1").
    Cut().
    Print()

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMonitorAlreadyStarted = errors.New("status monitor already started")
)

Functions

func EvaluateStatus

func EvaluateStatus(s Status) (ok bool, reason string)

EvaluateStatus returns ok=true when the printer reports no fault conditions. If ok is false, reason contains a stable machine-readable identifier. PaperNearEnd is treated as a warning only and does not cause ok=false.

func USBPreflightCode

func USBPreflightCode(err error) string

Types

type ErrorCode

type ErrorCode int

ErrorCode represents a specific printer error condition.

const (
	ErrNone ErrorCode = iota
	ErrCoverOpen
	ErrPaperEnd
	ErrPaperNearEnd
	ErrCutterJam
	ErrOffline
	ErrUnrecoverable
)

func (ErrorCode) String

func (c ErrorCode) String() string

type FileTransport

type FileTransport struct {
	// contains filtered or unexported fields
}

FileTransport implements Transport using a file descriptor (e.g., /dev/usb/lp0). It uses buffered writes for efficiency and supports bidirectional communication via the usblp kernel driver.

func OpenFile

func OpenFile(path string, opts ...Option) (*FileTransport, error)

OpenFile opens a file-based transport to the printer device. path is typically "/dev/usb/lp0" for USB-connected printers.

func (*FileTransport) Close

func (t *FileTransport) Close() error

Close flushes and closes the file descriptor.

func (*FileTransport) Flush

func (t *FileTransport) Flush() error

Flush flushes the write buffer to the device.

func (*FileTransport) Read

func (t *FileTransport) Read(p []byte) (int, error)

Read reads data directly from the file (for status responses).

func (*FileTransport) Write

func (t *FileTransport) Write(p []byte) (int, error)

Write writes data to the printer device.

type MonitorMode

type MonitorMode int
const (
	MonitorModeASB MonitorMode = iota
	MonitorModePoll
)

type MonitorOption

type MonitorOption func(*monitorConfig)

func WithMonitorASBMask

func WithMonitorASBMask(mask byte) MonitorOption

func WithMonitorMode

func WithMonitorMode(mode MonitorMode) MonitorOption

func WithMonitorPollInterval

func WithMonitorPollInterval(interval time.Duration) MonitorOption

type Option

type Option func(*config)

Option is a functional option for configuring the printer or transport.

func WithBufferSize

func WithBufferSize(n int) Option

WithBufferSize sets the write buffer size for FileTransport.

func WithDithering

func WithDithering(enabled bool) Option

WithDithering controls whether Floyd-Steinberg dithering is used when converting image.Image to raster data via PrintImage. Default is false (threshold-based conversion).

func WithFileNoSyscallWrite

func WithFileNoSyscallWrite() Option

WithFileNoSyscallWrite disables syscall.Write in FileTransport.

func WithFileOpenMode

func WithFileOpenMode(flags int) Option

WithFileOpenMode sets os.OpenFile flags used by FileTransport. Use os.O_WRONLY for write-only devices like /dev/usb/lp0.

func WithFileSyscallWrite

func WithFileSyscallWrite() Option

WithFileSyscallWrite forces FileTransport to use syscall.Write.

func WithFileWriteOnly

func WithFileWriteOnly() Option

WithFileWriteOnly is a shorthand for WithFileOpenMode(os.O_WRONLY).

func WithPaperWidth

func WithPaperWidth(dots int) Option

WithPaperWidth sets the maximum paper width in dots used when converting image.Image to raster data via PrintImage. Default is 576 (80mm at 203 dpi).

func WithSerial

func WithSerial(serial string) Option

WithSerial selects a USB device serial number.

func WithTextEncoding

func WithTextEncoding(name string) Option

func WithUSBConfig

func WithUSBConfig(number int) Option

WithUSBConfig sets the USB configuration number.

func WithUSBEndpoints

func WithUSBEndpoints(outAddress, inAddress uint8) Option

WithUSBEndpoints sets USB endpoint addresses used by USBTransport.

func WithUSBInterface

func WithUSBInterface(number, altSetting int) Option

WithUSBInterface sets the USB interface and alt-setting numbers.

func WithUSBTransferTimeout

func WithUSBTransferTimeout(timeout time.Duration) Option

WithUSBTransferTimeout sets read/write transfer timeout for USBTransport.

func WithVIDPID

func WithVIDPID(vid, pid uint16) Option

WithVIDPID sets USB vendor/product IDs used by USBTransport.

type Printer

type Printer struct {
	// contains filtered or unexported fields
}

func New

func New(transport Transport, opts ...Option) (*Printer, error)

func Open

func Open(path string, opts ...Option) (*Printer, error)

func (*Printer) Close

func (p *Printer) Close() error

func (*Printer) Cut

func (p *Printer) Cut() error

func (*Printer) Feed

func (p *Printer) Feed(lines int) error

func (*Printer) FeedDots

func (p *Printer) FeedDots(dots int) error

func (*Printer) Flush

func (p *Printer) Flush() error

func (*Printer) Init

func (p *Printer) Init() error

func (*Printer) OpenDrawer

func (p *Printer) OpenDrawer() error

func (*Printer) OpenDrawerPin

func (p *Printer) OpenDrawerPin(pin escpos.DrawerPin) error

OpenDrawerPin kicks the cash drawer using the specified pin. Use escpos.DrawerPin2 or escpos.DrawerPin5 to select the connector pin.

func (*Printer) PartialCut

func (p *Printer) PartialCut() error

func (*Printer) PrintBarcode

func (p *Printer) PrintBarcode(system escpos.BarcodeSystem, data []byte) error

func (*Printer) PrintImage

func (p *Printer) PrintImage(img image.Image) error

PrintImage converts an image.Image to a raster image and prints it. It uses the paper width and dithering settings configured via WithPaperWidth and WithDithering.

func (*Printer) PrintImageFromRaster

func (p *Printer) PrintImageFromRaster(r imaging.Raster, mode escpos.ImageMode) error

func (*Printer) PrintQRCode

func (p *Printer) PrintQRCode(data []byte) error

func (*Printer) PrintRaster

func (p *Printer) PrintRaster(data []byte, width, height int, mode escpos.ImageMode) error

func (*Printer) PrintText

func (p *Printer) PrintText(text string) error

func (*Printer) PrinterID

func (p *Printer) PrinterID() (string, error)

func (*Printer) Raw

func (p *Printer) Raw(data []byte) error

func (*Printer) Receipt

func (p *Printer) Receipt() *ReceiptBuilder

func (*Printer) SetAlignment

func (p *Printer) SetAlignment(alignment escpos.Alignment) error

func (*Printer) SetBold

func (p *Printer) SetBold(enabled bool) error

func (*Printer) SetCharSize

func (p *Printer) SetCharSize(width, height uint8) error

func (*Printer) SetFont

func (p *Printer) SetFont(f escpos.Font) error

func (*Printer) SetUnderline

func (p *Printer) SetUnderline(mode escpos.Underline) error

func (*Printer) Status

func (p *Printer) Status() (Status, error)

type PrinterError

type PrinterError struct {
	Code    ErrorCode
	Status  Status
	Message string
}

PrinterError represents an error returned by the printer.

func (*PrinterError) Error

func (e *PrinterError) Error() string

Error implements the error interface.

type ReceiptBuilder

type ReceiptBuilder struct {
	// contains filtered or unexported fields
}

func (*ReceiptBuilder) Barcode

func (rb *ReceiptBuilder) Barcode(system escpos.BarcodeSystem, data string) *ReceiptBuilder

func (*ReceiptBuilder) Bold

func (rb *ReceiptBuilder) Bold(text string) *ReceiptBuilder

func (*ReceiptBuilder) Center

func (rb *ReceiptBuilder) Center(text string) *ReceiptBuilder

func (*ReceiptBuilder) Cut

func (rb *ReceiptBuilder) Cut() *ReceiptBuilder

func (*ReceiptBuilder) Feed

func (rb *ReceiptBuilder) Feed(lines int) *ReceiptBuilder

func (*ReceiptBuilder) Header

func (rb *ReceiptBuilder) Header(text string) *ReceiptBuilder

func (*ReceiptBuilder) Image

func (rb *ReceiptBuilder) Image(img image.Image) *ReceiptBuilder

func (*ReceiptBuilder) LineItem

func (rb *ReceiptBuilder) LineItem(name string, price string) *ReceiptBuilder

func (*ReceiptBuilder) Print

func (rb *ReceiptBuilder) Print() error

func (*ReceiptBuilder) QRCode

func (rb *ReceiptBuilder) QRCode(data string) *ReceiptBuilder

func (*ReceiptBuilder) Separator

func (rb *ReceiptBuilder) Separator(char string) *ReceiptBuilder

func (*ReceiptBuilder) Text

func (rb *ReceiptBuilder) Text(text string) *ReceiptBuilder

type Status

type Status struct {
	// Printer status (DLE EOT n=1)
	Online     bool // true if printer is online
	DrawerOpen bool // true if cash drawer is open (pin 3 high)

	// Offline status (DLE EOT n=2)
	CoverOpen        bool // true if printer cover is open
	PaperFeedButton  bool // true if paper feed button is pressed
	WaitingForOnline bool // true if waiting to go online

	// Error status (DLE EOT n=3)
	RecoverableError     bool // true if recoverable error occurred
	AutocutterError      bool // true if autocutter error occurred
	UnrecoverableError   bool // true if unrecoverable error occurred
	AutoRecoverableError bool // true if auto-recoverable error occurred

	// Paper sensor status (DLE EOT n=4)
	PaperNearEnd bool // true if paper is near end
	PaperEnd     bool // true if paper is out
}

Status represents the current status of the printer. Fields are populated from DLE EOT status responses.

func ParseErrorStatus

func ParseErrorStatus(b byte) Status

ParseErrorStatus parses the DLE EOT n=3 response byte. Bit layout:

bit 2: recoverable error (1=error)
bit 3: autocutter error (1=error)
bit 5: unrecoverable error (1=error)
bit 6: auto-recoverable error (1=error)

func ParseOfflineStatus

func ParseOfflineStatus(b byte) Status

ParseOfflineStatus parses the DLE EOT n=2 response byte. Bit layout:

bit 2: cover open (1=open)
bit 3: paper feed button (1=pressed)
bit 6: waiting for online (1=waiting)

func ParsePaperStatus

func ParsePaperStatus(b byte) Status

ParsePaperStatus parses the DLE EOT n=4 response byte. Bit layout:

bit 2-3: paper near-end sensor (11=near end)
bit 5-6: paper end sensor (11=paper end)

func ParsePrinterStatus

func ParsePrinterStatus(b byte) Status

ParsePrinterStatus parses the DLE EOT n=1 response byte. Bit layout per ESC/POS spec:

bit 2: drawer kick-out connector pin 3 (1=high)
bit 3: online (0=online, 1=offline)

type StatusMonitor

type StatusMonitor struct {
	// contains filtered or unexported fields
}

func NewStatusMonitor

func NewStatusMonitor(t Transport, callback func(Status), opts ...MonitorOption) *StatusMonitor

func (*StatusMonitor) LastStatus

func (m *StatusMonitor) LastStatus() Status

func (*StatusMonitor) Start

func (m *StatusMonitor) Start(ctx context.Context) error

func (*StatusMonitor) Stop

func (m *StatusMonitor) Stop()

type Transport

type Transport interface {
	io.ReadWriteCloser
	// Flush sends any buffered data to the printer.
	Flush() error
}

Transport represents a connection to a printer. It provides bidirectional communication for sending ESC/POS commands and receiving status responses.

type USBReadinessResult

type USBReadinessResult struct {
	Ready bool
	Code  string // canonical preflight code if not ready; empty when Ready=true
}

USBReadinessResult holds the result of a USB readiness probe.

func ProbeUSBReadiness

func ProbeUSBReadiness(opts ...Option) USBReadinessResult

ProbeUSBReadiness attempts to open the USB context and device to check readiness. It returns Ready=true if the device can be opened, or Ready=false with a canonical code from USBPreflightCode if it cannot. Resources are always cleaned up.

type USBTransport

type USBTransport struct {
	// contains filtered or unexported fields
}

USBTransport implements Transport using USB bulk endpoints.

func OpenUSB

func OpenUSB(opts ...Option) (*USBTransport, error)

OpenUSB opens a USB transport.

func (*USBTransport) Close

func (t *USBTransport) Close() error

Close releases interface, config, device, and context resources.

func (*USBTransport) Flush

func (t *USBTransport) Flush() error

Flush is a no-op for USB bulk transfers.

func (*USBTransport) Read

func (t *USBTransport) Read(p []byte) (int, error)

func (*USBTransport) Write

func (t *USBTransport) Write(p []byte) (int, error)

Directories

Path Synopsis
cmd
tmt88v command
Package encoding provides character encoding support for the Epson TM-T88V printer.
Package encoding provides character encoding support for the Epson TM-T88V printer.
Package escpos provides low-level ESC/POS command building for the Epson TM-T88V printer.
Package escpos provides low-level ESC/POS command building for the Epson TM-T88V printer.
examples
barcode command
basic command
image command
receipt command
status command
Package imaging provides image processing and printing support for the Epson TM-T88V printer.
Package imaging provides image processing and printing support for the Epson TM-T88V printer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL