serial.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package main
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. zgpf_core "git.swzry.com/zry/zry-go-program-framework/core"
  7. "github.com/tarm/serial"
  8. "sync"
  9. )
  10. var _ zgpf_core.ISubService = (*SerialSubSvc)(nil)
  11. type SerialSubSvc struct {
  12. serialCfg *serial.Config
  13. serialPort *serial.Port
  14. subSvcContext context.Context
  15. subSvcCancel context.CancelFunc
  16. TxChan chan []byte
  17. RxChan chan []byte
  18. }
  19. func NewSerialSubSvc() *SerialSubSvc {
  20. s := &SerialSubSvc{
  21. TxChan: make(chan []byte),
  22. RxChan: make(chan []byte),
  23. }
  24. return s
  25. }
  26. func (s *SerialSubSvc) Prepare(ctx *zgpf_core.SubServiceContext) error {
  27. sd, ss, sp, err := GetDnSnP(Config.Serial.DataBits, Config.Serial.StopBits, Config.Serial.Parity)
  28. if err != nil {
  29. ctx.Error("invalid serial port config: ", err)
  30. return errors.New("invalid serial port config")
  31. }
  32. s.serialCfg = &serial.Config{
  33. Name: Config.Serial.ComPort,
  34. Baud: Config.Serial.Baudrate,
  35. Size: sd,
  36. Parity: sp,
  37. StopBits: ss,
  38. }
  39. return nil
  40. }
  41. func (s *SerialSubSvc) Run(ctx *zgpf_core.SubServiceContext) error {
  42. s.subSvcContext, s.subSvcCancel = context.WithCancel(ctx.GetParentContext())
  43. sport, err := serial.OpenPort(s.serialCfg)
  44. if err != nil {
  45. ctx.ErrorF("failed open serial port '%s': %v", s.serialCfg.Name, err)
  46. return errors.New("failed open serial port")
  47. }
  48. s.serialPort = sport
  49. ctx.InfoF("serial port '%s' opened", s.serialCfg.Name)
  50. defer s.serialPort.Close()
  51. wg := sync.WaitGroup{}
  52. wg.Add(2)
  53. go func() {
  54. defer wg.Done()
  55. readbuf := make([]byte, Config.Performance.RxBufferSize)
  56. for {
  57. n, xerr := s.serialPort.Read(readbuf)
  58. if xerr != nil {
  59. ctx.Error("error in read serial port: ", xerr)
  60. return
  61. }
  62. s.RxChan <- readbuf[:n]
  63. }
  64. }()
  65. go func() {
  66. defer wg.Done()
  67. for {
  68. select {
  69. case <-s.subSvcContext.Done():
  70. return
  71. case txdata := <-s.TxChan:
  72. _, xerr := s.serialPort.Write(txdata)
  73. if xerr != nil {
  74. ctx.Error("error in write serial port: ", xerr)
  75. return
  76. }
  77. }
  78. }
  79. }()
  80. wg.Wait()
  81. ctx.Info("serial sub service end.")
  82. return nil
  83. }
  84. func (s *SerialSubSvc) Stop(ctx *zgpf_core.SubServiceContext) {
  85. if s.subSvcCancel != nil {
  86. s.subSvcCancel()
  87. }
  88. if s.serialPort != nil {
  89. err := s.serialPort.Close()
  90. if err != nil {
  91. ctx.Warn("error in closing serial port: ", err)
  92. }
  93. }
  94. }
  95. func GetDnSnP(d int, s float32, p string) (byte, serial.StopBits, serial.Parity, error) {
  96. if d < 0 {
  97. return 0, 0, 0, fmt.Errorf("invalid databits: value %d is less than 0", d)
  98. }
  99. if d > 255 {
  100. return 0, 0, 0, fmt.Errorf("invalid databits: value %d is more than 255", d)
  101. }
  102. sd := byte(d)
  103. var ss serial.StopBits
  104. switch s {
  105. case 1:
  106. ss = serial.Stop1
  107. break
  108. case 1.5:
  109. ss = serial.Stop1Half
  110. case 2:
  111. ss = serial.Stop2
  112. default:
  113. return 0, 0, 0, fmt.Errorf("invalid stopbits: %f (should be 1/1.5/2)", s)
  114. }
  115. var sp serial.Parity
  116. switch p {
  117. case "N":
  118. sp = serial.ParityNone
  119. break
  120. case "O":
  121. sp = serial.ParityOdd
  122. break
  123. case "E":
  124. sp = serial.ParityEven
  125. break
  126. case "M":
  127. sp = serial.ParityMark
  128. break
  129. case "S":
  130. sp = serial.ParitySpace
  131. break
  132. default:
  133. return 0, 0, 0, fmt.Errorf("invalid parity: '%s' (should be N/O/E/M/S)", p)
  134. }
  135. return sd, ss, sp, nil
  136. }