serial.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package service
  2. import (
  3. "fmt"
  4. "os"
  5. "syscall"
  6. "unsafe"
  7. "github.com/tarm/serial"
  8. )
  9. // SerialPrinter 串口打印机
  10. type SerialPrinter struct {
  11. Port *serial.Port
  12. }
  13. func NewSerialPrinter(portName string, baudRate int) (*SerialPrinter, error) {
  14. if baudRate <= 0 {
  15. baudRate = 9600
  16. }
  17. if len(portName) < 3 || portName[:3] != "COM" {
  18. return nil, fmt.Errorf("非串口设备: %s", portName)
  19. }
  20. c := &serial.Config{Name: portName, Baud: baudRate}
  21. port, err := serial.OpenPort(c)
  22. if err != nil {
  23. return nil, fmt.Errorf("打开串口失败 %s: %w", portName, err)
  24. }
  25. return &SerialPrinter{Port: port}, nil
  26. }
  27. func (p *SerialPrinter) Write(data []byte) error {
  28. _, err := p.Port.Write(data)
  29. return err
  30. }
  31. func (p *SerialPrinter) Close() error {
  32. return p.Port.Close()
  33. }
  34. // === Windows RAW 打印机(WritePrinter API)===
  35. var (
  36. winspool = syscall.NewLazyDLL("winspool.drv")
  37. procOpenPrinter = winspool.NewProc("OpenPrinterW")
  38. procClosePrinter = winspool.NewProc("ClosePrinter")
  39. procStartDoc = winspool.NewProc("StartDocPrinterW")
  40. procStartPage = winspool.NewProc("StartPagePrinter")
  41. procWritePrinter = winspool.NewProc("WritePrinter")
  42. procEndPage = winspool.NewProc("EndPagePrinter")
  43. procEndDoc = winspool.NewProc("EndDocPrinter")
  44. )
  45. type DOC_INFO_1 struct {
  46. pDocName *uint16
  47. pOutputFile *uint16
  48. pDataType *uint16
  49. }
  50. func PrintRaw(printerName string, data []byte) error {
  51. namePtr, _ := syscall.UTF16PtrFromString(printerName)
  52. var handle syscall.Handle
  53. ret, _, _ := procOpenPrinter.Call(uintptr(unsafe.Pointer(namePtr)),
  54. uintptr(unsafe.Pointer(&handle)), 0)
  55. if ret == 0 {
  56. return fmt.Errorf("OpenPrinter 失败: %s", printerName)
  57. }
  58. defer procClosePrinter.Call(uintptr(handle))
  59. docName, _ := syscall.UTF16PtrFromString("Parking Ticket")
  60. dataType, _ := syscall.UTF16PtrFromString("RAW")
  61. di := DOC_INFO_1{pDocName: docName, pDataType: dataType}
  62. procStartDoc.Call(uintptr(handle), 1, uintptr(unsafe.Pointer(&di)))
  63. procStartPage.Call(uintptr(handle))
  64. var written uint32
  65. procWritePrinter.Call(uintptr(handle), uintptr(unsafe.Pointer(&data[0])),
  66. uintptr(len(data)), uintptr(unsafe.Pointer(&written)))
  67. procEndPage.Call(uintptr(handle))
  68. procEndDoc.Call(uintptr(handle))
  69. return nil
  70. }
  71. var _ = os.Stderr // keep import