serial.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package service
  2. import (
  3. "fmt"
  4. "os"
  5. "syscall"
  6. "github.com/tarm/serial"
  7. )
  8. // SerialPrinter 通用打印机接口(串口或 Windows USB)
  9. type Printer interface {
  10. Write(data []byte) error
  11. Close() error
  12. }
  13. type SerialPrinter struct {
  14. Port *serial.Port
  15. }
  16. func NewSerialPrinter(portName string, baudRate int) (*SerialPrinter, error) {
  17. if baudRate <= 0 {
  18. baudRate = 9600
  19. }
  20. // 非 COM 端口 → 尝试 Windows 打印机路径
  21. if len(portName) >= 3 && portName[:3] != "COM" {
  22. return nil, fmt.Errorf("非串口设备,请使用 USB 驱动安装虚拟 COM 口,或连接真实 COM 口")
  23. }
  24. c := &serial.Config{Name: portName, Baud: baudRate}
  25. port, err := serial.OpenPort(c)
  26. if err != nil {
  27. return nil, fmt.Errorf("打开串口失败 %s: %w", portName, err)
  28. }
  29. return &SerialPrinter{Port: port}, nil
  30. }
  31. func (p *SerialPrinter) Write(data []byte) error {
  32. _, err := p.Port.Write(data)
  33. return err
  34. }
  35. func (p *SerialPrinter) Close() error {
  36. return p.Port.Close()
  37. }
  38. // USBPrinter Windows USB 打印机(原生 API 发送 RAW 数据)
  39. type USBPrinter struct {
  40. handle syscall.Handle
  41. }
  42. func NewUSBPrinter(printerName string) (*USBPrinter, error) {
  43. path := fmt.Sprintf("\\\\.\\%s", printerName)
  44. pathPtr, err := syscall.UTF16PtrFromString(path)
  45. if err != nil {
  46. return nil, err
  47. }
  48. handle, err := syscall.CreateFile(
  49. pathPtr,
  50. syscall.GENERIC_WRITE,
  51. syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE,
  52. nil,
  53. syscall.OPEN_EXISTING,
  54. syscall.FILE_ATTRIBUTE_NORMAL,
  55. 0,
  56. )
  57. if err != nil {
  58. // 尝试通过 UNC 路径
  59. uncPath := fmt.Sprintf("\\127.0.0.1\\%s", printerName)
  60. uncPtr, _ := syscall.UTF16PtrFromString(uncPath)
  61. handle, err = syscall.CreateFile(uncPtr, syscall.GENERIC_WRITE,
  62. syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, nil,
  63. syscall.OPEN_EXISTING, 0, 0)
  64. if err != nil {
  65. return nil, fmt.Errorf("无法打开打印机 %s: %w", printerName, err)
  66. }
  67. }
  68. return &USBPrinter{handle: handle}, nil
  69. }
  70. func (p *USBPrinter) Write(data []byte) error {
  71. var written uint32
  72. return syscall.WriteFile(p.handle, data, &written, nil)
  73. }
  74. func (p *USBPrinter) Close() error {
  75. return syscall.CloseHandle(p.handle)
  76. }
  77. var _ = os.Stderr // keep os import