190 lines
4.2 KiB
Go
190 lines
4.2 KiB
Go
package modbus
|
|
|
|
import (
|
|
"testing"
|
|
"io"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
func TestAssembleRTUFrame(t *testing.T) {
|
|
var rt *rtuTransport
|
|
var frame []byte
|
|
|
|
rt = &rtuTransport{}
|
|
|
|
frame = rt.assembleRTUFrame(&pdu{
|
|
unitId: 0x33,
|
|
functionCode: 0x11,
|
|
payload: []byte{0x22, 0x33, 0x44, 0x55},
|
|
})
|
|
// expect 1 byte of unit id, 1 byte of function code, 4 bytes of payload and
|
|
// 2 bytes of CRC
|
|
if len(frame) != 8 {
|
|
t.Errorf("expected 8 bytes, got %v", len(frame))
|
|
}
|
|
for i, b := range []byte{
|
|
0x33, 0x11, // unit id and function code
|
|
0x22, 0x33, // payload
|
|
0x44, 0x55, // payload
|
|
0xf0, 0x93, // CRC
|
|
} {
|
|
if frame[i] != b {
|
|
t.Errorf("expected 0x%02x at position %v, got 0x%02x", b, i, frame[i])
|
|
}
|
|
}
|
|
|
|
frame = rt.assembleRTUFrame(&pdu{
|
|
unitId: 0x31,
|
|
functionCode: 0x06,
|
|
payload: []byte{0x12, 0x34},
|
|
})
|
|
// expect 1 byte of unit if, 1 byte of function code, 2 bytes of payload and
|
|
// 2 bytes of CRC
|
|
if len(frame) != 6 {
|
|
t.Errorf("expected 6 bytes, got %v", len(frame))
|
|
}
|
|
for i, b := range []byte{
|
|
0x31, 0x06, // unit id and function code
|
|
0x12, 0x34, // payload
|
|
0xe3, 0xae, // CRC
|
|
} {
|
|
if frame[i] != b {
|
|
t.Errorf("expected 0x%02x at position %v, got 0x%02x", b, i, frame[i])
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
|
|
func TestRTUTransportReadRTUFrame(t *testing.T) {
|
|
var rt *rtuTransport
|
|
var p1, p2 net.Conn
|
|
var txchan chan []byte
|
|
var err error
|
|
var res *pdu
|
|
|
|
txchan = make(chan []byte, 2)
|
|
p1, p2 = net.Pipe()
|
|
go feedTestPipe(t, txchan, p1)
|
|
|
|
|
|
rt = newRTUTransport(p2, "", 9600, 10 * time.Millisecond, nil)
|
|
|
|
// read a valid response (illegal data address)
|
|
txchan <- []byte{
|
|
0x31, 0x82, // unit id and response code
|
|
0x02, // exception code
|
|
0xc1, 0x6e, // CRC
|
|
}
|
|
res, err = rt.readRTUFrame()
|
|
if err != nil {
|
|
t.Errorf("readRTUFrame() should have succeeded, got %v", err)
|
|
}
|
|
if res.unitId != 0x31 {
|
|
t.Errorf("expected 0x31 as unit id, got 0x%02x", res.unitId)
|
|
}
|
|
if res.functionCode != 0x82 {
|
|
t.Errorf("expected 0x82 as function code, got 0x%02x", res.functionCode)
|
|
}
|
|
if len(res.payload) != 1 {
|
|
t.Errorf("expected a length of 1, got %v", len(res.payload))
|
|
}
|
|
if res.payload[0] != 0x02 {
|
|
t.Errorf("expected {0x02} as payload, got {0x%02x}",
|
|
res.payload[0])
|
|
}
|
|
|
|
// read a frame with a bad crc
|
|
txchan <- []byte{
|
|
0x30, 0x82, // unit id and response code
|
|
0x12, // exception code
|
|
0xc0, 0xa2, // CRC
|
|
}
|
|
res, err = rt.readRTUFrame()
|
|
if err != ErrBadCRC {
|
|
t.Errorf("readRTUFrame() should have returned ErrBadCrc, got %v", err)
|
|
}
|
|
|
|
// read a longer, valid response
|
|
txchan <- []byte{
|
|
0x31, 0x03, // unit id and response code
|
|
0x04, // length
|
|
0x11, 0x22, // register #1
|
|
0x33, 0x44, // register #2
|
|
0x7b, 0xc5, // CRC
|
|
}
|
|
res, err = rt.readRTUFrame()
|
|
if err != nil {
|
|
t.Errorf("readRTUFrame() should have succeeded, got %v", err)
|
|
}
|
|
if res.unitId != 0x31 {
|
|
t.Errorf("expected 0x31 as unit id, got 0x%02x", res.unitId)
|
|
}
|
|
if res.functionCode != 0x03 {
|
|
t.Errorf("expected 0x03 as function code, got 0x%02x", res.functionCode)
|
|
}
|
|
if len(res.payload) != 5 {
|
|
t.Errorf("expected a length of 5, got %v", len(res.payload))
|
|
}
|
|
for i, b := range []byte{
|
|
0x04,
|
|
0x11, 0x22,
|
|
0x33, 0x44,
|
|
} {
|
|
if res.payload[i] != b {
|
|
t.Errorf("expected 0x%02x at position %v, got 0x%02x",
|
|
b, i, res.payload[i])
|
|
}
|
|
}
|
|
|
|
p1.Close()
|
|
p2.Close()
|
|
|
|
return
|
|
}
|
|
|
|
func feedTestPipe(t *testing.T, in chan []byte, out io.WriteCloser) {
|
|
var err error
|
|
var txbuf []byte
|
|
|
|
for {
|
|
// grab a slice of bytes from the channel
|
|
txbuf = <-in
|
|
|
|
// write this slice to the pipe
|
|
_, err = out.Write(txbuf)
|
|
if err != nil {
|
|
t.Errorf("failed to write to test pipe: %v", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func TestModbusRTUSerialCharTime(t *testing.T) {
|
|
var d time.Duration
|
|
|
|
d = serialCharTime(38400)
|
|
// expect 11 bits at 38400bps: 11 * (1/38400) = 286.458uS
|
|
if d != time.Duration(286458) * time.Nanosecond {
|
|
t.Errorf("unexpected serial char duration: %v", d)
|
|
}
|
|
|
|
d = serialCharTime(19200)
|
|
// expect 11 bits at 19200bps: 11 * (1/19200) = 572.916uS
|
|
if d != time.Duration(572916) * time.Nanosecond {
|
|
t.Errorf("unexpected serial char duration: %v", d)
|
|
}
|
|
|
|
d = serialCharTime(9600)
|
|
// expect 11 bits at 9600bps: 11 * (1/9600) = 1.145833ms
|
|
if d != time.Duration(1145833) * time.Nanosecond {
|
|
t.Errorf("unexpected serial char duration: %v", d)
|
|
}
|
|
|
|
return
|
|
}
|