forked from tbrandon/mbserver
-
Notifications
You must be signed in to change notification settings - Fork 2
/
framertu.go
89 lines (73 loc) · 2.04 KB
/
framertu.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
package mbserver
import (
"encoding/binary"
"fmt"
)
// RTUFrame is the Modbus TCP frame.
type RTUFrame struct {
Address uint8
Function uint8
Data []byte
CRC uint16
}
// NewRTUFrame converts a packet to a Modbus TCP frame.
func NewRTUFrame(packet []byte) (*RTUFrame, error) {
// Check the that the packet length.
if len(packet) < 5 {
return nil, fmt.Errorf("RTU Frame error: packet less than 5 bytes: %v", packet)
}
// Check the CRC.
pLen := len(packet)
crcExpect := binary.LittleEndian.Uint16(packet[pLen-2 : pLen])
crcCalc := crcModbus(packet[0 : pLen-2])
if crcCalc != crcExpect {
return nil, fmt.Errorf("RTU Frame error: CRC (expected 0x%x, got 0x%x)", crcExpect, crcCalc)
}
frame := &RTUFrame{
Address: uint8(packet[0]),
Function: uint8(packet[1]),
Data: packet[2 : pLen-2],
}
return frame, nil
}
// Copy the RTUFrame.
func (frame *RTUFrame) Copy() Framer {
copy := *frame
return ©
}
// Bytes returns the Modbus byte stream based on the RTUFrame fields
func (frame *RTUFrame) Bytes() []byte {
bytes := make([]byte, 2)
bytes[0] = frame.Address
bytes[1] = frame.Function
bytes = append(bytes, frame.Data...)
// Calculate the CRC.
pLen := len(bytes)
crc := crcModbus(bytes[0:pLen])
// Add the CRC.
bytes = append(bytes, []byte{0, 0}...)
binary.LittleEndian.PutUint16(bytes[pLen:pLen+2], crc)
return bytes
}
// GetFunction returns the Modbus function code.
func (frame *RTUFrame) GetAddress() uint8 {
return frame.Address
}
// GetFunction returns the Modbus function code.
func (frame *RTUFrame) GetFunction() uint8 {
return frame.Function
}
// GetData returns the RTUFrame Data byte field.
func (frame *RTUFrame) GetData() []byte {
return frame.Data
}
// SetData sets the RTUFrame Data byte field and updates the frame length
// accordingly.
func (frame *RTUFrame) SetData(data []byte) {
frame.Data = data
}
// SetException sets the Modbus exception code in the frame.
func (frame *RTUFrame) SetException(exception *Exception) {
frame.Function = frame.Function | 0x80
frame.Data = []byte{byte(*exception)}
}