You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ntool-biz/nmodbus/protocol/packer_rtu.go

81 lines
2.0 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}