6 Commits

2 changed files with 42 additions and 27 deletions

View File

@@ -465,7 +465,8 @@ func (rt *rtuTransport) readRTUFrameWithRes() (res *pdu, err error) {
// 标准modbus响应已读取完成现在读取自定义数据 // 标准modbus响应已读取完成现在读取自定义数据
// 设置5秒超时来读取自定义数据 // 设置5秒超时来读取自定义数据
customDataTimeout := 5 * time.Second customDataTimeout := 5 * time.Second
err = rt.link.SetDeadline(time.Now().Add(customDataTimeout)) deadline := time.Now().Add(customDataTimeout)
err = rt.link.SetDeadline(deadline)
if err != nil { if err != nil {
return return
} }
@@ -477,6 +478,16 @@ func (rt *rtuTransport) readRTUFrameWithRes() (res *pdu, err error) {
var lastErr error // 记录最后一次非超时错误 var lastErr error // 记录最后一次非超时错误
for { for {
// 检查是否已经超时
if time.Now().After(deadline) {
// 超时时间到,退出循环
// 如果有之前记录的错误使用它否则err保持为nil超时是正常的
if lastErr != nil {
err = lastErr
}
break
}
// 检查缓冲区是否还有空间 // 检查缓冲区是否还有空间
if startPos+totalRead+len(tempBuf) > len(rxbuf) { if startPos+totalRead+len(tempBuf) > len(rxbuf) {
// 如果缓冲区不够,扩展它 // 如果缓冲区不够,扩展它
@@ -497,7 +508,7 @@ func (rt *rtuTransport) readRTUFrameWithRes() (res *pdu, err error) {
if readErr != nil { if readErr != nil {
if os.IsTimeout(readErr) { if os.IsTimeout(readErr) {
// 超时时间到,退出循环 // 超时时间到,退出循环
// 如果有之前记录的错误,使用它;否则使用超时错误 // 如果有之前记录的错误,使用它;否则err保持为nil超时是正常的
if lastErr != nil { if lastErr != nil {
err = lastErr err = lastErr
} }

View File

@@ -1,6 +1,6 @@
package modbus package modbus
import ( import (
"time" "time"
"github.com/goburrow/serial" "github.com/goburrow/serial"
@@ -10,43 +10,46 @@ import (
// 1) satisfy the rtuLink interface and // 1) satisfy the rtuLink interface and
// 2) add Read() deadline/timeout support. // 2) add Read() deadline/timeout support.
type serialPortWrapper struct { type serialPortWrapper struct {
conf *serialPortConfig conf *serialPortConfig
port serial.Port port serial.Port
deadline time.Time deadline time.Time
} }
type serialPortConfig struct { type serialPortConfig struct {
Device string Device string
Speed uint Speed uint
DataBits uint DataBits uint
Parity uint Parity uint
StopBits uint StopBits uint
} }
func newSerialPortWrapper(conf *serialPortConfig) (spw *serialPortWrapper) { func newSerialPortWrapper(conf *serialPortConfig) (spw *serialPortWrapper) {
spw = &serialPortWrapper{ spw = &serialPortWrapper{
conf: conf, conf: conf,
} }
return return
} }
func (spw *serialPortWrapper) Open() (err error) { func (spw *serialPortWrapper) Open() (err error) {
var parity string var parity string
switch spw.conf.Parity { switch spw.conf.Parity {
case PARITY_NONE: parity = "N" case PARITY_NONE:
case PARITY_EVEN: parity = "E" parity = "N"
case PARITY_ODD: parity = "O" case PARITY_EVEN:
parity = "E"
case PARITY_ODD:
parity = "O"
} }
spw.port, err = serial.Open(&serial.Config{ spw.port, err = serial.Open(&serial.Config{
Address: spw.conf.Device, Address: spw.conf.Device,
BaudRate: int(spw.conf.Speed), BaudRate: int(spw.conf.Speed),
DataBits: int(spw.conf.DataBits), DataBits: int(spw.conf.DataBits),
Parity: parity, Parity: parity,
StopBits: int(spw.conf.StopBits), StopBits: int(spw.conf.StopBits),
Timeout: 10 * time.Millisecond, Timeout: 100 * time.Millisecond,
}) })
return return
@@ -64,11 +67,12 @@ func (spw *serialPortWrapper) Close() (err error) {
// attempting to read from the serial port. // attempting to read from the serial port.
// If Read() is called before the deadline, a read attempt to the serial port // If Read() is called before the deadline, a read attempt to the serial port
// is made. At this point, one of two things can happen: // is made. At this point, one of two things can happen:
// - the serial port's receive buffer has one or more bytes and port.Read() // - the serial port's receive buffer has one or more bytes and port.Read()
// returns immediately (partial or full read), // returns immediately (partial or full read),
// - the serial port's receive buffer is empty: port.Read() blocks for // - the serial port's receive buffer is empty: port.Read() blocks for
// up to 10ms and returns serial.ErrTimeout. The serial timeout error is // up to 10ms and returns serial.ErrTimeout. The serial timeout error is
// masked and Read() returns with no data. // masked and Read() returns with no data.
//
// As the higher-level methods use io.ReadFull(), Read() will be called // As the higher-level methods use io.ReadFull(), Read() will be called
// as many times as necessary until either enough bytes have been read or an // as many times as necessary until either enough bytes have been read or an
// error is returned (ErrRequestTimedOut or any other i/o error). // error is returned (ErrRequestTimedOut or any other i/o error).