serial.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package service
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "syscall"
  7. "unsafe"
  8. "github.com/tarm/serial"
  9. )
  10. // SerialPrinter 串口打印机
  11. type SerialPrinter struct {
  12. Port *serial.Port
  13. }
  14. func NewSerialPrinter(portName string, baudRate int) (*SerialPrinter, error) {
  15. if baudRate <= 0 {
  16. baudRate = 9600
  17. }
  18. if len(portName) < 3 || portName[:3] != "COM" {
  19. return nil, fmt.Errorf("非串口设备: %s", portName)
  20. }
  21. c := &serial.Config{Name: portName, Baud: baudRate}
  22. port, err := serial.OpenPort(c)
  23. if err != nil {
  24. return nil, fmt.Errorf("打开串口失败 %s: %w", portName, err)
  25. }
  26. return &SerialPrinter{Port: port}, nil
  27. }
  28. func (p *SerialPrinter) Write(data []byte) error { _, err := p.Port.Write(data); return err }
  29. func (p *SerialPrinter) Close() error { return p.Port.Close() }
  30. // === Windows RAW 打印机 ===
  31. var winspool = syscall.NewLazyDLL("winspool.drv")
  32. type DOC_INFO_1 struct {
  33. pDocName *uint16
  34. pOutputFile *uint16
  35. pDataType *uint16
  36. }
  37. func PrintRaw(printerName string, data []byte) error {
  38. namePtr, _ := syscall.UTF16PtrFromString(printerName)
  39. rawType, _ := syscall.UTF16PtrFromString("RAW")
  40. var handle syscall.Handle
  41. ret, _, _ := winspool.NewProc("OpenPrinterW").Call(
  42. uintptr(unsafe.Pointer(namePtr)),
  43. uintptr(unsafe.Pointer(&handle)), 0)
  44. if ret == 0 {
  45. return fmt.Errorf("OpenPrinter 失败: %s", printerName)
  46. }
  47. defer winspool.NewProc("ClosePrinter").Call(uintptr(handle))
  48. docName, _ := syscall.UTF16PtrFromString("Ticket")
  49. di := DOC_INFO_1{pDocName: docName, pDataType: rawType}
  50. jobID, _, _ := winspool.NewProc("StartDocPrinterW").Call(
  51. uintptr(handle), 1, uintptr(unsafe.Pointer(&di)))
  52. if jobID == 0 {
  53. return fmt.Errorf("StartDocPrinter 失败")
  54. }
  55. winspool.NewProc("StartPagePrinter").Call(uintptr(handle))
  56. var written uint32
  57. winspool.NewProc("WritePrinter").Call(
  58. uintptr(handle), uintptr(unsafe.Pointer(&data[0])),
  59. uintptr(len(data)), uintptr(unsafe.Pointer(&written)))
  60. winspool.NewProc("EndPagePrinter").Call(uintptr(handle))
  61. winspool.NewProc("EndDocPrinter").Call(uintptr(handle))
  62. return nil
  63. }
  64. func copyToPrinter(printerName string, data []byte) error {
  65. tmpFile, err := os.CreateTemp("", "tkt_*.bin")
  66. if err != nil {
  67. return err
  68. }
  69. tmpPath := tmpFile.Name()
  70. defer os.Remove(tmpPath)
  71. if _, err := tmpFile.Write(data); err != nil {
  72. tmpFile.Close()
  73. return err
  74. }
  75. tmpFile.Close()
  76. cmd := exec.Command("cmd", "/C", "copy", "/B", tmpPath, fmt.Sprintf("\\\\127.0.0.1\\%s", printerName))
  77. out, err := cmd.CombinedOutput()
  78. if err == nil {
  79. return nil
  80. }
  81. _ = out
  82. return PrintRaw(printerName, data)
  83. }
  84. var _ = os.Stderr