From d5e9ce78d9ebc81b451044f80f099be355d1e119 Mon Sep 17 00:00:00 2001 From: PopCorn Date: Thu, 13 Nov 2025 22:28:48 +0800 Subject: [PATCH] 0x41 --- client.go | 13 ++---- modbus.go | 2 +- rtu_transport.go | 103 +++++++++++++++++++++++++---------------------- 3 files changed, 60 insertions(+), 58 deletions(-) diff --git a/client.go b/client.go index 5e5ebc8..8679c1b 100644 --- a/client.go +++ b/client.go @@ -1188,15 +1188,9 @@ func (mc *ModbusClient) readRegistersWithFunctionCode(addr uint16, quantity uint unitId: mc.unitId, } - // if functionCode != fcCustomize { - // err = ErrUnexpectedParameters - // mc.logger.Errorf("unexpected function code (%d)", functionCode) - // return - // } - - if functionCode == 0 { + if functionCode != fcCustomize { err = ErrUnexpectedParameters - mc.logger.Errorf("unexpected register type (%v)", functionCode) + mc.logger.Errorf("unexpected function code (%d)", functionCode) return } @@ -1208,7 +1202,8 @@ func (mc *ModbusClient) readRegistersWithFunctionCode(addr uint16, quantity uint return } - if quantity > 1024 { + // 16 * 16 * 40 + if quantity > 10240 { err = ErrUnexpectedParameters mc.logger.Error("quantity of registers exceeds 1024") return diff --git a/modbus.go b/modbus.go index f527f77..e7021a2 100644 --- a/modbus.go +++ b/modbus.go @@ -41,7 +41,7 @@ const ( fcWriteFileRecord uint8 = 0x15 // customize - fcCustomize uint8 = 0x29 + fcCustomize uint8 = 0x41 // exception codes exIllegalFunction uint8 = 0x01 diff --git a/rtu_transport.go b/rtu_transport.go index fe1190f..08da0aa 100644 --- a/rtu_transport.go +++ b/rtu_transport.go @@ -8,7 +8,7 @@ import ( ) const ( - maxRTUFrameLength int = 256 + maxRTUFrameLength int = 256 ) type rtuTransport struct { @@ -21,10 +21,10 @@ type rtuTransport struct { } type rtuLink interface { - Close() (error) - Read([]byte) (int, error) - Write([]byte) (int, error) - SetDeadline(time.Time) (error) + Close() error + Read([]byte) (int, error) + Write([]byte) (int, error) + SetDeadline(time.Time) error } // Returns a new RTU transport. @@ -58,11 +58,11 @@ func (rt *rtuTransport) Close() (err error) { // Runs a request across the rtu link and returns a response. func (rt *rtuTransport) ExecuteRequest(req *pdu) (res *pdu, err error) { var ts time.Time - var t time.Duration - var n int + var t time.Duration + var n int // set an i/o deadline on the link - err = rt.link.SetDeadline(time.Now().Add(rt.timeout)) + err = rt.link.SetDeadline(time.Now().Add(rt.timeout)) if err != nil { return } @@ -78,7 +78,7 @@ func (rt *rtuTransport) ExecuteRequest(req *pdu) (res *pdu, err error) { // build an RTU ADU out of the request object and // send the final ADU+CRC on the wire - n, err = rt.link.Write(rt.assembleRTUFrame(req)) + n, err = rt.link.Write(rt.assembleRTUFrame(req)) if err != nil { return } @@ -112,7 +112,7 @@ func (rt *rtuTransport) ExecuteRequest(req *pdu) (res *pdu, err error) { // Reads a request from the rtu link. func (rt *rtuTransport) ReadRequest() (req *pdu, err error) { // reading requests from RTU links is currently unsupported - err = fmt.Errorf("unimplemented") + err = fmt.Errorf("unimplemented") return } @@ -123,7 +123,7 @@ func (rt *rtuTransport) WriteResponse(res *pdu) (err error) { // build an RTU ADU out of the request object and // send the final ADU+CRC on the wire - n, err = rt.link.Write(rt.assembleRTUFrame(res)) + n, err = rt.link.Write(rt.assembleRTUFrame(res)) if err != nil { return } @@ -135,16 +135,16 @@ func (rt *rtuTransport) WriteResponse(res *pdu) (err error) { // Waits for, reads and decodes a frame from the rtu link. func (rt *rtuTransport) readRTUFrame() (res *pdu, err error) { - var rxbuf []byte - var byteCount int - var bytesNeeded int - var crc crc + var rxbuf []byte + var byteCount int + var bytesNeeded int + var crc crc - rxbuf = make([]byte, maxRTUFrameLength) + rxbuf = make([]byte, 10243) // read the serial ADU header: unit id (1 byte), function code (1 byte) and // PDU length/exception code (1 byte) - byteCount, err = io.ReadFull(rt.link, rxbuf[0:3]) + byteCount, err = io.ReadFull(rt.link, rxbuf[0:3]) if (byteCount > 0 || err == nil) && byteCount != 3 { err = ErrShortFrame return @@ -160,15 +160,15 @@ func (rt *rtuTransport) readRTUFrame() (res *pdu, err error) { } // we need to read 2 additional bytes of CRC after the payload - bytesNeeded += 2 + bytesNeeded += 2 // never read more than the max allowed frame length - if byteCount + bytesNeeded > maxRTUFrameLength { - err = ErrProtocolError + if byteCount+bytesNeeded > maxRTUFrameLength { + err = ErrProtocolError return } - byteCount, err = io.ReadFull(rt.link, rxbuf[3:3 + bytesNeeded]) + byteCount, err = io.ReadFull(rt.link, rxbuf[3:3+bytesNeeded]) if err != nil && err != io.ErrUnexpectedEOF { return } @@ -180,19 +180,19 @@ func (rt *rtuTransport) readRTUFrame() (res *pdu, err error) { // compute the CRC on the entire frame, excluding the CRC crc.init() - crc.add(rxbuf[0:3 + bytesNeeded - 2]) + crc.add(rxbuf[0 : 3+bytesNeeded-2]) // compare CRC values - if !crc.isEqual(rxbuf[3 + bytesNeeded - 2], rxbuf[3 + bytesNeeded - 1]) { + if !crc.isEqual(rxbuf[3+bytesNeeded-2], rxbuf[3+bytesNeeded-1]) { err = ErrBadCRC return } - res = &pdu{ - unitId: rxbuf[0], - functionCode: rxbuf[1], + res = &pdu{ + unitId: rxbuf[0], + functionCode: rxbuf[1], // pass the byte count + trailing data as payload, withtout the CRC - payload: rxbuf[2:3 + bytesNeeded - 2], + payload: rxbuf[2 : 3+bytesNeeded-2], } return @@ -200,18 +200,18 @@ func (rt *rtuTransport) readRTUFrame() (res *pdu, err error) { // Turns a PDU object into bytes. func (rt *rtuTransport) assembleRTUFrame(p *pdu) (adu []byte) { - var crc crc + var crc crc - adu = append(adu, p.unitId) - adu = append(adu, p.functionCode) - adu = append(adu, p.payload...) + adu = append(adu, p.unitId) + adu = append(adu, p.functionCode) + adu = append(adu, p.payload...) // run the ADU through the CRC generator crc.init() crc.add(adu) // append the CRC to the ADU - adu = append(adu, crc.value()...) + adu = append(adu, crc.value()...) return } @@ -220,24 +220,31 @@ func (rt *rtuTransport) assembleRTUFrame(p *pdu) (adu []byte) { func expectedResponseLenth(responseCode uint8, responseLength uint8) (byteCount int, err error) { switch responseCode { case fcReadHoldingRegisters, - fcReadInputRegisters, - fcReadCoils, - fcReadDiscreteInputs: byteCount = int(responseLength) + fcReadInputRegisters, + fcReadCoils, + fcReadDiscreteInputs, + 0x41: + byteCount = int(responseLength) case fcWriteSingleRegister, - fcWriteMultipleRegisters, - fcWriteSingleCoil, - fcWriteMultipleCoils: byteCount = 3 - case fcMaskWriteRegister: byteCount = 5 + fcWriteMultipleRegisters, + fcWriteSingleCoil, + fcWriteMultipleCoils: + byteCount = 3 + case fcMaskWriteRegister: + byteCount = 5 case fcReadHoldingRegisters | 0x80, - fcReadInputRegisters | 0x80, - fcReadCoils | 0x80, - fcReadDiscreteInputs | 0x80, - fcWriteSingleRegister | 0x80, - fcWriteMultipleRegisters | 0x80, - fcWriteSingleCoil | 0x80, - fcWriteMultipleCoils | 0x80, - fcMaskWriteRegister | 0x80: byteCount = 0 - default: err = ErrProtocolError + fcReadInputRegisters | 0x80, + fcReadCoils | 0x80, + fcReadDiscreteInputs | 0x80, + fcWriteSingleRegister | 0x80, + fcWriteMultipleRegisters | 0x80, + fcWriteSingleCoil | 0x80, + fcWriteMultipleCoils | 0x80, + fcMaskWriteRegister | 0x80, + 0x41 | 0x80: + byteCount = 0 + default: + err = ErrProtocolError } return