| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- package modbus
- import (
- "encoding/binary"
- "fmt"
- )
- // ProtocolDataUnit (PDU) is independent of underlying communication layers.
- type ProtocolDataUnit struct {
- FuncCode byte
- Data []byte
- }
- func EncodeRTUFrame(slaveID byte, pdu ProtocolDataUnit) ([]byte, error) {
- length := len(pdu.Data) + 4
- if length > rtuAduMaxSize {
- return nil, fmt.Errorf("modbus: length of data '%v' must not be bigger than '%v'",
- length, rtuAduMaxSize)
- }
- requestAdu := make([]byte, 0, length)
- requestAdu = append(requestAdu, slaveID, pdu.FuncCode)
- requestAdu = append(requestAdu, pdu.Data...)
- checksum := CRC16(requestAdu)
- requestAdu = append(requestAdu, byte(checksum), byte(checksum>>8))
- return requestAdu, nil
- }
- // DecodeRTUFrame decode extracts slaveID and PDU from RTU frame and verify CRC.
- func DecodeRTUFrame(adu []byte) (uint8, []byte, error) {
- if len(adu) < rtuAduMinSize { // Minimum size (including address, funcCode and CRC)
- return 0, nil, fmt.Errorf("modbus: response length '%v' does not meet minimum '%v'",
- len(adu), rtuAduMinSize)
- }
- // Calculate checksum
- crc := CRC16(adu[0 : len(adu)-2])
- expect := binary.LittleEndian.Uint16(adu[len(adu)-2:])
- if crc != expect {
- return 0, nil, fmt.Errorf("modbus: response crc '%x' does not match expected '%x'",
- expect, crc)
- }
- // slaveID & PDU but pass crc
- return adu[0], adu[1 : len(adu)-2], nil
- }
- // Verify verify confirms valid data(including slaveID,funcCode,response data)
- //其中rspPDU = ProtocolDataUnit{pdu[0], pdu[1:]}
- func Verify(reqSlaveID, rspSlaveID uint8, reqPDU, rspPDU ProtocolDataUnit) error {
- switch {
- case reqSlaveID != rspSlaveID: // Check slaveID same
- return fmt.Errorf("modbus: response slave id '%v' does not match request '%v'",
- rspSlaveID, reqSlaveID)
- case rspPDU.FuncCode != reqPDU.FuncCode: // Check correct function code returned (exception)
- return responseError(rspPDU)
- case rspPDU.Data == nil || len(rspPDU.Data) == 0: // check Empty response
- return fmt.Errorf("modbus: response data is empty")
- }
- return nil
- }
- // responseError response error
- func responseError(response ProtocolDataUnit) error {
- mbError := &ExceptionError{}
- if response.Data != nil && len(response.Data) > 0 {
- mbError.ExceptionCode = response.Data[0]
- }
- return mbError
- }
|