usb_layout.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package service
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. type usbPrintOpKind uint8
  7. const (
  8. usbOpWrite usbPrintOpKind = iota
  9. usbOpFeed
  10. usbOpQRCode
  11. usbOpCut
  12. )
  13. type usbPrintOp struct {
  14. kind usbPrintOpKind
  15. data []byte
  16. count int
  17. qrData string
  18. qrWidth int
  19. }
  20. type usbTicketData struct {
  21. lotName, channelCode, plateNo string
  22. entryTime, slipNo, ticketNo string
  23. }
  24. var (
  25. usbSizeNormal = []byte{GS, '!', 0x00}
  26. usbDoubleWidth = []byte{GS, '!', 0x10}
  27. usbFontA = []byte{ESC, 'M', 0}
  28. usbFontB = []byte{ESC, 'M', 1}
  29. usbDirectionOff = []byte{ESC, '{', 0}
  30. )
  31. func buildUSBTicketLayout(data usbTicketData) []usbPrintOp {
  32. var ops []usbPrintOp
  33. write := func(data ...byte) {
  34. ops = append(ops, usbPrintOp{kind: usbOpWrite, data: append([]byte(nil), data...)})
  35. }
  36. text := func(value string) {
  37. write(append([]byte(value), '\n')...)
  38. }
  39. feed := func(count int) {
  40. ops = append(ops, usbPrintOp{kind: usbOpFeed, count: count})
  41. }
  42. write(ESC, '@')
  43. write(usbDirectionOff...)
  44. write(ESC, 'a', 1)
  45. write(usbFontA...)
  46. write(usbDoubleWidth...)
  47. write(BoldOnCmd...)
  48. text("Parking Ticket")
  49. write(usbSizeNormal...)
  50. write(BoldOffCmd...)
  51. write(usbFontB...)
  52. text(data.lotName)
  53. text(strings.Repeat("-", 42))
  54. text("")
  55. text("PARK AT YOUR OWN RISK")
  56. write(ESC, 'a', 0)
  57. lotAndType := "A-General Car"
  58. if data.lotName != "" {
  59. lotAndType = data.lotName + " A-General Car"
  60. }
  61. text(lotAndType)
  62. write(usbFontA...)
  63. text("In-Time::" + data.entryTime)
  64. if data.channelCode != "" {
  65. text("InGate::" + data.channelCode)
  66. }
  67. text("Slip No::" + data.slipNo)
  68. if data.plateNo != "" {
  69. write(usbDoubleWidth...)
  70. write(BoldOnCmd...)
  71. text("Veh No::" + data.plateNo)
  72. write(usbSizeNormal...)
  73. write(BoldOffCmd...)
  74. }
  75. write(ESC, 'a', 1)
  76. feed(1)
  77. ops = append(ops, usbPrintOp{kind: usbOpQRCode, qrData: data.ticketNo, qrWidth: 12})
  78. feed(1)
  79. // Pos_EscQrcode can change text state. Restore the settings used by the
  80. // centered payment footer before writing any more text.
  81. write(usbDirectionOff...)
  82. write(ESC, 'a', 1)
  83. write(usbFontB...)
  84. text("SCAN AND PAY WITH NEW")
  85. text("THE CANADIA BANK APP")
  86. feed(8)
  87. ops = append(ops, usbPrintOp{kind: usbOpCut})
  88. return ops
  89. }
  90. type usbPrintDevice interface {
  91. Write([]byte) int
  92. FeedLines(int)
  93. QRCode(string, int) bool
  94. FullCut()
  95. }
  96. func executeUSBLayout(device usbPrintDevice, ops []usbPrintOp) error {
  97. for _, op := range ops {
  98. switch op.kind {
  99. case usbOpWrite:
  100. written := device.Write(op.data)
  101. if written != len(op.data) {
  102. return fmt.Errorf("USB打印短写: 写入%d/%d字节", written, len(op.data))
  103. }
  104. case usbOpFeed:
  105. device.FeedLines(op.count)
  106. case usbOpQRCode:
  107. if !device.QRCode(op.qrData, op.qrWidth) {
  108. return fmt.Errorf("USB二维码打印失败")
  109. }
  110. case usbOpCut:
  111. device.FullCut()
  112. }
  113. }
  114. return nil
  115. }