Improve error handling

This commit is contained in:
2023-02-25 11:08:53 +01:00
parent 9a92e47837
commit ce537e1373
2 changed files with 55 additions and 8 deletions

View File

@@ -35,9 +35,18 @@ func (m *Mbclient) closer() {
<-m.t.C <-m.t.C
m.conn.Close() m.conn.Close()
m.transactionCounter = 0
m.wg.Done() m.wg.Done()
} }
// closeConn can be called when a tcp communication failure require the current
// connection to be closed, it should only be used when closer routine is running
// and the timer is stopped.
func (m *Mbclient) closeConn() {
m.t.Reset(0)
m.wg.Wait()
}
func (m *Mbclient) ReadRegisters(first uint16, numRegs uint16) ([]uint16, error) { func (m *Mbclient) ReadRegisters(first uint16, numRegs uint16) ([]uint16, error) {
var err error var err error
// If The timer is expired, conn is closed and needs to be reopened // If The timer is expired, conn is closed and needs to be reopened
@@ -52,7 +61,6 @@ func (m *Mbclient) ReadRegisters(first uint16, numRegs uint16) ([]uint16, error)
m.wg.Add(1) m.wg.Add(1)
go m.closer() go m.closer()
} }
defer m.t.Reset(m.keepAliveDuration)
const requestLength = 12 const requestLength = 12
m.transactionCounter++ m.transactionCounter++
@@ -70,31 +78,47 @@ func (m *Mbclient) ReadRegisters(first uint16, numRegs uint16) ([]uint16, error)
m.conn.SetDeadline(time.Now().Add(5 * time.Second)) m.conn.SetDeadline(time.Now().Add(5 * time.Second))
byteswritten, err := m.conn.Write(req) byteswritten, err := m.conn.Write(req)
if err != nil { if err != nil {
m.closeConn()
return nil, err return nil, err
} }
if byteswritten != requestLength { if byteswritten != requestLength {
m.closeConn()
return nil, fmt.Errorf("failed to send request") return nil, fmt.Errorf("failed to send request")
} }
m.conn.SetDeadline(time.Now().Add(5 * time.Second)) m.conn.SetDeadline(time.Now().Add(5 * time.Second))
_, err = io.ReadFull(m.conn, m.header[:]) _, err = io.ReadFull(m.conn, m.header[:])
if err != nil { if err != nil {
m.closeConn()
return nil, err return nil, err
} }
responseHeader.unMarshal(m.header) responseHeader.unMarshal(m.header)
expectedDataLength := responseHeader.length - 1 expectedDataLength := responseHeader.length - 1
if m.transactionCounter != responseHeader.transactionID {
m.t.Reset(0)
return nil, fmt.Errorf("modbus transaction mismatch %v != %v", m.transactionCounter, responseHeader.transactionID)
}
response := make([]byte, expectedDataLength) response := make([]byte, expectedDataLength)
_, err = m.conn.Read(response) bytesRead, err := io.ReadFull(m.conn, response)
if err != nil { if err != nil {
m.closeConn()
return nil, err return nil, err
} }
if uint16(bytesRead) != expectedDataLength {
m.t.Reset(m.keepAliveDuration)
return nil, fmt.Errorf("failed to read complete package")
}
err = mbpayload.unMarshal(response) err = mbpayload.unMarshal(response)
if mbpayload.functionCode != 3 { if mbpayload.functionCode != 3 {
return nil, fmt.Errorf("modbus exception %v", mbpayload.functionCode&0x7F) m.t.Reset(m.keepAliveDuration)
return nil, fmt.Errorf("modbus exception %v req: %v", mbpayload.functionCode&0x7F, req)
} }
if err != nil { if err != nil {
m.t.Reset(m.keepAliveDuration)
return nil, err return nil, err
} }
m.t.Reset(m.keepAliveDuration) m.t.Reset(m.keepAliveDuration)
return mbpayload.registers, nil return mbpayload.registers, nil
} }
@@ -106,10 +130,6 @@ type mbapHeader struct {
unitIdentifier byte unitIdentifier byte
} }
// func (m *mbapHeader) marshalBinary() ([]byte, error) {
// }
func (m *mbapHeader) unMarshal(data [7]byte) error { func (m *mbapHeader) unMarshal(data [7]byte) error {
m.transactionID = binary.BigEndian.Uint16(data[0:2]) m.transactionID = binary.BigEndian.Uint16(data[0:2])
m.protocolIdentifier = binary.BigEndian.Uint16(data[2:4]) m.protocolIdentifier = binary.BigEndian.Uint16(data[2:4])
@@ -129,7 +149,7 @@ func (d *mbPDU) unMarshal(data []byte) error {
d.functionCode = data[0] d.functionCode = data[0]
d.length = data[1] d.length = data[1]
if d.length+2 != uint8(len(data)) { if d.length+2 != uint8(len(data)) {
return fmt.Errorf("lenght mismatch in modbus payload") return fmt.Errorf("length mismatch in modbus payload")
} }
d.registers = make([]uint16, d.length/2) d.registers = make([]uint16, d.length/2)
var n uint8 var n uint8

View File

@@ -66,3 +66,30 @@ func TestReadOneRegisterShortKeepAlive(t *testing.T) {
} }
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
func TestReadALot(t *testing.T) {
c, err := New("IAM_248000012514.solver.nu:502", 1, 100*time.Millisecond)
t.Log("Connect")
assert.NoError(t, err)
for n := 0; n < 500; n++ {
t.Log(n)
_, err := c.ReadRegisters(12401, 2)
if err != nil {
t.Log(err)
}
_, err = c.ReadRegisters(12102, 2)
if err != nil {
t.Log(err)
}
_, err = c.ReadRegisters(12544, 1)
if err != nil {
t.Log(err)
}
_, err = c.ReadRegisters(12136, 1)
if err != nil {
t.Log(err)
}
}
time.Sleep(200 * time.Millisecond)
}