-
Notifications
You must be signed in to change notification settings - Fork 2
/
rtu_packager.go
125 lines (120 loc) · 3.57 KB
/
rtu_packager.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package modbus
import (
"bytes"
"encoding/hex"
"fmt"
)
const (
rtuMinSize = 4
rtuMaxSize = 256
)
// rtuPackager rtu包解析器
type rtuPackager struct {
slaveID byte
}
func (p *rtuPackager) Encode(pdu protocolDataUnit) (adu ApplicationDataUnit, err error) {
length := len(pdu.GetData()) + rtuMinSize
if length > rtuMaxSize {
err = fmt.Errorf("modbus: length of data '%v' must not be bigger than '%v'", length, rtuMaxSize)
return
}
buf := bytes.NewBuffer([]byte{})
buf.WriteByte(p.slaveID)
buf.WriteByte(pdu.GetFunctionCode())
buf.Write(pdu.GetData())
checksum := CRC16(buf.Bytes())
checksumByte := CRC16ToBytes(checksum)
buf.Write(checksumByte)
adu = applicationDataUnit{
slaveID: p.slaveID,
pdu: pdu,
checkSum: checksum,
checkSumByte: checksumByte,
data: buf.Bytes(),
length: buf.Len(),
mode: RTU,
}
return
}
func (p *rtuPackager) Decode(results []byte) (adu ApplicationDataUnit, err error) {
length := len(results)
if length > rtuMaxSize {
err = fmt.Errorf("modbus: response data size '%v' exceeds the maximum limit of '%v'", length, rtuMaxSize)
return
}
if length < rtuMinSize {
err = fmt.Errorf("modbus: response data size '%v' less than maximum limit of '%v'", length, rtuMinSize)
return
}
slaveID := results[0]
functionCode := results[1]
var pduLength int
var pdu protocolDataUnit
switch functionCode {
//read
case FuncCodeReadDiscreteInputs, FuncCodeReadCoils, FuncCodeReadInputRegisters, FuncCodeReadHoldingRegisters:
pduLength = int(results[2])
pduData := results[3 : length-2]
pdu = protocolDataUnit{
functionCode: functionCode,
data: pduData,
length: pduLength,
}
default:
pduData := results[2 : length-2]
pdu = protocolDataUnit{
functionCode: functionCode,
data: pduData,
length: len(pduData),
}
}
checkSumByte := results[length-2:]
adu = applicationDataUnit{
slaveID: slaveID,
pdu: pdu,
checkSumByte: checkSumByte,
checkSum: CRC16ToUint(checkSumByte),
data: results,
mode: RTU,
length: length,
}
return
}
func (p *rtuPackager) Verify(aduRequest ApplicationDataUnit, aduResponse ApplicationDataUnit) (err error) {
if aduRequest.GetSlaveId() != aduResponse.GetSlaveId() {
err = fmt.Errorf("modbus: aduRequest slaveId '%v' and aduResponse slaveId '%v' are inconsistent", aduRequest.GetSlaveId(), aduResponse.GetSlaveId())
return
}
if aduRequest.GetFunctionCode() != aduResponse.GetFunctionCode() {
if aduResponse.GetFunctionCode() == aduRequest.GetFunctionCode()+0x80 {
err = fmt.Errorf("modbus: error errorCode '%X'", aduResponse.GetFunctionCode())
data := aduResponse.GetPDU().GetData()
if len(data) == 0 {
return
}
text, exist := faults[data[0]]
if !exist {
return
}
err = fmt.Errorf("modbus: error errorCode: '%X' %s", aduResponse.GetFunctionCode(), text)
return
}
err = fmt.Errorf("modbus: aduRequest functionCode '%v' and aduResponse functionCode '%v' are inconsistent", aduRequest.GetFunctionCode(), aduResponse.GetFunctionCode())
return
}
data := aduResponse.GetData()
length := len(data)
checksum := CRC16(aduResponse.GetData()[:length-2])
if checksum != aduResponse.GetCheckSum() {
sumByte := make([]byte, 2)
sumByte[0] = byte(checksum >> 8)
sumByte[1] = byte(checksum)
err = fmt.Errorf("modbus: crc validation failed source:'%v' reality:'%v' ", hex.EncodeToString(aduResponse.GetCheckSumByte()), hex.EncodeToString(sumByte))
return
}
return
}
func NewRtuPackager(slaveID byte) (p Packager) {
p = &rtuPackager{slaveID: slaveID}
return
}