Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
go modbus [![Build Status](https://travis-ci.org/goburrow/modbus.svg?branch=master)](https://travis-ci.org/goburrow/modbus) [![GoDoc](https://godoc.org/github.com/goburrow/modbus?status.svg)](https://godoc.org/github.com/goburrow/modbus)
=========
Fault-tolerant, fail-fast implementation of Modbus protocol in Go.
This is a fork of https://github.com/gburrow/modbus (possibly abandoned),
a Fault-tolerant, fail-fast implementation of Modbus protocol in Go.

Bug fixes
-------------------
* Add a read buffer flush for tcp clients just prior to launching the next call. This
resolves transaction ID mismatches that cause the connection to never work
again.

Supported functions
-------------------
Expand Down
37 changes: 37 additions & 0 deletions tcpclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,18 @@ func (mb *tcpTransporter) Send(aduRequest []byte) (aduResponse []byte, err error
// Set timer to close when idle
mb.lastActivity = time.Now()
mb.startCloseTimer()

/*
* If an answer to a previously timed-out request is already in teh buffer, this will result
* in a transaction ID mismatch from which we will never recover. To prevent this, just
* flush any previous reponses before launching the next poll. That's throwing away
* possibly useful data, but the previous request was already satisfied with a timeout
* error so that probably makes the most sense here.
*
* Be aware that this call resets the read deadline.
*/
mb.flushAll()

// Set write and read timeout
var timeout time.Time
if mb.Timeout > 0 {
Expand Down Expand Up @@ -252,6 +264,31 @@ func (mb *tcpTransporter) flush(b []byte) (err error) {
return
}

/**
* This function implements a non-blocking read flush. Be warned it resets
* the read deadline.
*/
func (mb *tcpTransporter) flushAll() (int, error) {
if err := mb.conn.SetReadDeadline(time.Now()); err != nil {
return 0, err
}

count := 0
buffer := make([]byte, 1024)

for {
n, err := mb.conn.Read(buffer)

if err != nil {
return count + n, err
} else if n > 0 {
count = count + n
} else {
/* didn't flush any new bytes, return */
return count, err
}
}
}
func (mb *tcpTransporter) logf(format string, v ...interface{}) {
if mb.Logger != nil {
mb.Logger.Printf(format, v...)
Expand Down