diff --git a/servertu.go b/servertu.go index 80e050d..457bee5 100644 --- a/servertu.go +++ b/servertu.go @@ -1,15 +1,33 @@ package mbserver import ( + "errors" "io" "log" + "syscall" + "time" "github.com/goburrow/serial" ) +type ListenRTUOption func(options *rtuOptions) +type rtuOptions struct { + notifyExit chan error +} + +func NotifyExit(ch chan error) ListenRTUOption { + return func(s *rtuOptions) { + s.notifyExit = ch + } +} + // ListenRTU starts the Modbus server listening to a serial device. // For example: err := s.ListenRTU(&serial.Config{Address: "/dev/ttyUSB0"}) -func (s *Server) ListenRTU(serialConfig *serial.Config) (err error) { +func (s *Server) ListenRTU(serialConfig *serial.Config, options ...ListenRTUOption) (err error) { + var opts rtuOptions + for _, option := range options { + option(&opts) + } port, err := serial.Open(serialConfig) if err != nil { log.Fatalf("failed to open %s: %v\n", serialConfig.Address, err) @@ -19,29 +37,39 @@ func (s *Server) ListenRTU(serialConfig *serial.Config) (err error) { s.portsWG.Add(1) go func() { defer s.portsWG.Done() - s.acceptSerialRequests(port) + err := s.acceptSerialRequests(port) + if opts.notifyExit != nil { + opts.notifyExit <- err + } }() return err } -func (s *Server) acceptSerialRequests(port serial.Port) { - SkipFrameError: +func (s *Server) acceptSerialRequests(port serial.Port) error { +SkipFrameError: for { select { case <-s.portsCloseChan: - return + return nil default: } buffer := make([]byte, 512) bytesRead, err := port.Read(buffer) + if errors.Is(err, serial.ErrTimeout) { + continue + } if err != nil { + if errors.Is(err, serial.ErrTimeout) || errors.Is(err, syscall.EWOULDBLOCK) { + time.Sleep(10 * time.Millisecond) + continue + } if err != io.EOF { log.Printf("serial read error %v\n", err) } - return + return err } if bytesRead != 0 {