|
|
package protocol
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
"encoding/binary"
|
|
|
"fmt"
|
|
|
"git.noahlan.cn/noahlan/nnet/packet"
|
|
|
"git.noahlan.cn/noahlan/ntool-biz/nmodbus/util"
|
|
|
"git.noahlan.cn/noahlan/ntool/nlog"
|
|
|
)
|
|
|
|
|
|
type RTUPacker struct {
|
|
|
buf *bytes.Buffer
|
|
|
byteOrder binary.ByteOrder
|
|
|
}
|
|
|
|
|
|
func NewRTUPacker(byteOrder binary.ByteOrder) *RTUPacker {
|
|
|
p := &RTUPacker{
|
|
|
buf: bytes.NewBuffer(nil),
|
|
|
byteOrder: byteOrder,
|
|
|
}
|
|
|
|
|
|
return p
|
|
|
}
|
|
|
|
|
|
func (d *RTUPacker) Pack(header interface{}, data []byte) ([]byte, error) {
|
|
|
modbusHeader, ok := header.(*ModbusHeader)
|
|
|
if !ok {
|
|
|
return nil, packet.ErrWrongPacketType
|
|
|
}
|
|
|
bs := make([]byte, 2)
|
|
|
bs[0] = modbusHeader.Address
|
|
|
bs[1] = modbusHeader.Function
|
|
|
bs = append(bs, data...)
|
|
|
|
|
|
// calc CRC
|
|
|
pLen := len(bs)
|
|
|
crc := util.Checksum(bs[0:pLen])
|
|
|
bs = append(bs, []byte{0, 0}...)
|
|
|
d.byteOrder.PutUint16(bs[pLen:pLen+2], crc)
|
|
|
return bs, nil
|
|
|
}
|
|
|
|
|
|
func (d *RTUPacker) Unpack(data []byte) ([]packet.IPacket, error) {
|
|
|
d.buf.Write(data)
|
|
|
|
|
|
nlog.Debugf("接收RTU数据: %x", data)
|
|
|
|
|
|
var (
|
|
|
packets []packet.IPacket
|
|
|
err error
|
|
|
)
|
|
|
pLen := d.buf.Len()
|
|
|
|
|
|
if pLen < 5 {
|
|
|
return packets, fmt.Errorf("RTU Frame error: packet less than 5 bytes")
|
|
|
}
|
|
|
// ModbusRTU 串口通讯 发送端在发送报文时,一帧结束后必须有3.5个字符周期的间隔时间(4.01ms)
|
|
|
// 本质上不会发生粘包的情况,故此可以直接读取一个完整的包
|
|
|
// 否则无法处理粘包状况,这是由于协议帧没有描述具体包长度的字节
|
|
|
|
|
|
bs := d.buf.Next(d.buf.Len())
|
|
|
// check crc 取[0:len-2]进行计算,与最后一个字节对比(最后一个字节为crc校验码)
|
|
|
crcExpect := d.byteOrder.Uint16(bs[pLen-2 : pLen])
|
|
|
crcCalc := util.Checksum(bs[0 : pLen-2])
|
|
|
if crcCalc != crcExpect {
|
|
|
return nil, fmt.Errorf("RTU Frame error: CRC (expected 0x%x, got 0x%x)", crcExpect, crcCalc)
|
|
|
}
|
|
|
|
|
|
p := NewRTUPacket()
|
|
|
p.Address = bs[0]
|
|
|
p.Function = bs[1]
|
|
|
p.Data = bs[2 : pLen-2]
|
|
|
p.CRC = crcExpect
|
|
|
|
|
|
packets = append(packets, p)
|
|
|
|
|
|
d.buf.Reset()
|
|
|
return packets, err
|
|
|
}
|