Compare commits
8 Commits
v1.0.2
...
cfy-feat-d
| Author | SHA1 | Date | |
|---|---|---|---|
| ccfc7f0736 | |||
| 67b5a4df7f | |||
| 50add55c87 | |||
| fb90bbf207 | |||
| 343292b9b2 | |||
| a635b8af4e | |||
| 7ba768b8c2 | |||
| 1df66eccd1 |
@@ -1212,8 +1212,8 @@ func (mc *ModbusClient) readRegistersWithFunctionCode(addr uint16, quantity uint
|
||||
return
|
||||
}
|
||||
|
||||
// 16 * 16 * 40
|
||||
if quantity > 10240 {
|
||||
// 16 * 40
|
||||
if quantity > 640 {
|
||||
err = ErrUnexpectedParameters
|
||||
mc.logger.Error("quantity of registers exceeds 10240")
|
||||
return
|
||||
|
||||
@@ -188,55 +188,6 @@ func (rt *rtuTransport) WriteResponse(res *pdu) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func calculateModbusCRC16(data []byte) uint16 {
|
||||
// 初始值 (标准 Modbus RTU)
|
||||
var crc uint16 = 0xFFFF
|
||||
|
||||
// 遍历所有需要校验的字节
|
||||
for _, b := range data {
|
||||
// 1. 当前 CRC 异或当前字节 (注意:字节 b 转换为 uint16)
|
||||
crc = crc ^ uint16(b)
|
||||
|
||||
// 2. 8 次迭代进行位运算
|
||||
for i := 0; i < 8; i++ {
|
||||
// 检查最低有效位 (LSB)
|
||||
if crc&0x0001 != 0 {
|
||||
// 如果 LSB 是 1: 右移一位,然后异或多项式 0xA001
|
||||
// 0xA001 是 0x8005 反射后的结果
|
||||
crc = (crc >> 1) ^ 0xA001
|
||||
} else {
|
||||
// 如果 LSB 是 0: 直接右移一位
|
||||
crc = crc >> 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 返回最终的 CRC 值
|
||||
return crc
|
||||
}
|
||||
|
||||
// 示例用法:使用此函数替换您原来的 crc.add/crc.value 逻辑
|
||||
|
||||
// 假设您的数据帧已完整接收到 rxbuf 中
|
||||
func checkCRC(rxbuf []byte, totalFrameSize int) bool {
|
||||
// 1. 确定校验范围 (地址到数据结束)
|
||||
crcEndIndex := totalFrameSize - 2
|
||||
dataToVerify := rxbuf[0:crcEndIndex]
|
||||
|
||||
// 2. 使用模拟从机的函数计算 CRC
|
||||
calculatedCRC := calculateModbusCRC16(dataToVerify)
|
||||
|
||||
// 3. 提取接收到的 CRC (Little-Endian 顺序)
|
||||
recvCRCLow := rxbuf[crcEndIndex]
|
||||
recvCRCHigh := rxbuf[crcEndIndex+1]
|
||||
|
||||
// 4. 重组接收到的 CRC
|
||||
receivedCRC := (uint16(recvCRCHigh) << 8) | uint16(recvCRCLow)
|
||||
|
||||
// 5. 比较
|
||||
return calculatedCRC == receivedCRC
|
||||
}
|
||||
|
||||
// Waits for, reads and decodes a frame from the rtu link.
|
||||
func (rt *rtuTransport) readRTUFrame() (res *pdu, err error) {
|
||||
var rxbuf []byte
|
||||
|
||||
54
serial.go
54
serial.go
@@ -1,6 +1,6 @@
|
||||
package modbus
|
||||
|
||||
import (
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/goburrow/serial"
|
||||
@@ -10,43 +10,46 @@ import (
|
||||
// 1) satisfy the rtuLink interface and
|
||||
// 2) add Read() deadline/timeout support.
|
||||
type serialPortWrapper struct {
|
||||
conf *serialPortConfig
|
||||
port serial.Port
|
||||
deadline time.Time
|
||||
conf *serialPortConfig
|
||||
port serial.Port
|
||||
deadline time.Time
|
||||
}
|
||||
|
||||
type serialPortConfig struct {
|
||||
Device string
|
||||
Speed uint
|
||||
DataBits uint
|
||||
Parity uint
|
||||
StopBits uint
|
||||
Device string
|
||||
Speed uint
|
||||
DataBits uint
|
||||
Parity uint
|
||||
StopBits uint
|
||||
}
|
||||
|
||||
func newSerialPortWrapper(conf *serialPortConfig) (spw *serialPortWrapper) {
|
||||
spw = &serialPortWrapper{
|
||||
conf: conf,
|
||||
conf: conf,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (spw *serialPortWrapper) Open() (err error) {
|
||||
var parity string
|
||||
var parity string
|
||||
|
||||
switch spw.conf.Parity {
|
||||
case PARITY_NONE: parity = "N"
|
||||
case PARITY_EVEN: parity = "E"
|
||||
case PARITY_ODD: parity = "O"
|
||||
case PARITY_NONE:
|
||||
parity = "N"
|
||||
case PARITY_EVEN:
|
||||
parity = "E"
|
||||
case PARITY_ODD:
|
||||
parity = "O"
|
||||
}
|
||||
|
||||
spw.port, err = serial.Open(&serial.Config{
|
||||
Address: spw.conf.Device,
|
||||
BaudRate: int(spw.conf.Speed),
|
||||
DataBits: int(spw.conf.DataBits),
|
||||
Parity: parity,
|
||||
StopBits: int(spw.conf.StopBits),
|
||||
Timeout: 10 * time.Millisecond,
|
||||
Address: spw.conf.Device,
|
||||
BaudRate: int(spw.conf.Speed),
|
||||
DataBits: int(spw.conf.DataBits),
|
||||
Parity: parity,
|
||||
StopBits: int(spw.conf.StopBits),
|
||||
Timeout: 100 * time.Millisecond,
|
||||
})
|
||||
|
||||
return
|
||||
@@ -64,11 +67,12 @@ func (spw *serialPortWrapper) Close() (err error) {
|
||||
// attempting to read from the serial port.
|
||||
// If Read() is called before the deadline, a read attempt to the serial port
|
||||
// is made. At this point, one of two things can happen:
|
||||
// - the serial port's receive buffer has one or more bytes and port.Read()
|
||||
// returns immediately (partial or full read),
|
||||
// - the serial port's receive buffer is empty: port.Read() blocks for
|
||||
// up to 10ms and returns serial.ErrTimeout. The serial timeout error is
|
||||
// masked and Read() returns with no data.
|
||||
// - the serial port's receive buffer has one or more bytes and port.Read()
|
||||
// returns immediately (partial or full read),
|
||||
// - the serial port's receive buffer is empty: port.Read() blocks for
|
||||
// up to 10ms and returns serial.ErrTimeout. The serial timeout error is
|
||||
// masked and Read() returns with no data.
|
||||
//
|
||||
// As the higher-level methods use io.ReadFull(), Read() will be called
|
||||
// as many times as necessary until either enough bytes have been read or an
|
||||
// error is returned (ErrRequestTimedOut or any other i/o error).
|
||||
|
||||
@@ -154,8 +154,13 @@ func (tt *tcpTransport) readMBAPFrame() (p *pdu, txnId uint16, err error) {
|
||||
// the byte count includes the unit ID field, which we already have
|
||||
bytesNeeded--
|
||||
|
||||
maxTCPFrameLen := maxTCPFrameLength
|
||||
if rxbuf[1] == fcCustomize {
|
||||
maxTCPFrameLen = 647
|
||||
}
|
||||
|
||||
// never read more than the max allowed frame length
|
||||
if bytesNeeded+mbapHeaderLength > maxTCPFrameLength {
|
||||
if bytesNeeded+mbapHeaderLength > maxTCPFrameLen {
|
||||
err = ErrProtocolError
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user