github.com/simpleiot/simpleiot@v0.18.3/modbus/rtu.go (about) 1 package modbus 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "io" 7 ) 8 9 // RtuADU defines an ADU for RTU packets 10 type RtuADU struct { 11 PDU 12 Address byte 13 CRC uint16 14 } 15 16 // RTU defines an RTU connection 17 type RTU struct { 18 port io.ReadWriteCloser 19 } 20 21 // NewRTU creates a new RTU transport 22 func NewRTU(port io.ReadWriteCloser) *RTU { 23 return &RTU{ 24 port: port, 25 } 26 } 27 28 func (r *RTU) Read(p []byte) (int, error) { 29 return r.port.Read(p) 30 } 31 32 func (r *RTU) Write(p []byte) (int, error) { 33 return r.port.Write(p) 34 } 35 36 // Close closes the serial port 37 func (r *RTU) Close() error { 38 return r.port.Close() 39 } 40 41 // Encode encodes a RTU packet 42 func (r *RTU) Encode(id byte, pdu PDU) ([]byte, error) { 43 ret := make([]byte, len(pdu.Data)+2+2) 44 ret[0] = id 45 ret[1] = byte(pdu.FunctionCode) 46 copy(ret[2:], pdu.Data) 47 crc := RtuCrc(ret[:len(ret)-2]) 48 binary.BigEndian.PutUint16(ret[len(ret)-2:], crc) 49 return ret, nil 50 } 51 52 // Decode decodes a RTU packet 53 func (r *RTU) Decode(packet []byte) (byte, PDU, error) { 54 err := CheckRtuCrc(packet) 55 if err != nil { 56 return 0, PDU{}, err 57 } 58 59 ret := PDU{} 60 61 ret.FunctionCode = FunctionCode(packet[1]) 62 63 if len(packet) < 4 { 64 return 0, PDU{}, fmt.Errorf("short packet, got %d bytes", len(packet)) 65 } 66 67 id := packet[0] 68 69 ret.Data = packet[2 : len(packet)-2] 70 71 return id, ret, nil 72 } 73 74 // Type returns TransportType 75 func (r *RTU) Type() TransportType { 76 return TransportTypeRTU 77 }