package ADL200 import ( "encoding/binary" "fmt" "github.com/sigurn/crc16" ) // ReadHoldingRegistersBuilder 构造读取保持寄存器命令 (功能码 0x03) func ReadHoldingRegistersBuilder(address byte, startAddr, quantity uint16) []byte { // 构造 Modbus-RTU 请求帧 request := make([]byte, 6) request[0] = address // 从站地址 request[1] = 0x03 // 功能码: 读取保持寄存器 binary.BigEndian.PutUint16(request[2:4], startAddr) // 起始地址 (大端) binary.BigEndian.PutUint16(request[4:6], quantity) // 寄存器数量 (大端) // 计算 CRC16 Modbus 校验 crcTable := crc16.MakeTable(crc16.CRC16_MODBUS) crc := crc16.Checksum(request[:6], crcTable) // 添加 CRC,低字节在前 request = append(request, byte(crc&0xFF), byte(crc>>8)) return request } // ReadHoldingRegisterParse 解析保持寄存器响应数据 func ReadHoldingRegisterParse(result []byte, address byte, quantity uint16) ([]uint16, error) { // 检查响应最小长度 if len(result) < 5 { return nil, fmt.Errorf("响应���度不足: %d bytes", len(result)) } // 提取数据和 CRC data := result[:len(result)-2] receivedCRC := binary.LittleEndian.Uint16(result[len(result)-2:]) // 解析 CRC (小端) // 校验 CRC crcTable := crc16.MakeTable(crc16.CRC16_MODBUS) calculatedCRC := crc16.Checksum(data, crcTable) if calculatedCRC != receivedCRC { return nil, fmt.Errorf("CRC校验失败,计算值: %x,接收值: %x", calculatedCRC, receivedCRC) } // 验证地址和功能码 if data[0] != address { return nil, fmt.Errorf("响应地址不符,期望: %x,实际: %x", address, data[0]) } switch data[1] { case 0x03: // 正常响应 byteCount := data[2] if len(data) < 3+int(byteCount) { return nil, fmt.Errorf("响应数据不完整") } if int(byteCount) != 2*int(quantity) { return nil, fmt.Errorf("数据长度不符,期望: %d,实际: %d", 2*quantity, byteCount) } // 解析寄存器值 (大端序) registers := make([]uint16, quantity) for i := 0; i < int(quantity); i++ { registers[i] = binary.BigEndian.Uint16(data[3+2*i : 5+2*i]) } return registers, nil case 0x83: // 异常响应 if len(data) < 3 { return nil, fmt.Errorf("异常响应格式错误") } return nil, fmt.Errorf("Modbus异常码: %x", data[2]) default: return nil, fmt.Errorf("未知功能码: %x", data[1]) } } // WriteMultipleRegistersBuilder 构造写入多个保持寄存器命令 (功能码 0x10) func WriteMultipleRegistersBuilder(address byte, startAddr uint16, data []uint16) (writeData []byte, quantity uint16) { // 构造 Modbus-RTU 请求帧 quantity = uint16(len(data)) byteCount := 2 * quantity request := make([]byte, 7+byteCount) request[0] = address // 从站地址 request[1] = 0x10 // 功能码: 写多个寄存器 binary.BigEndian.PutUint16(request[2:4], startAddr) // 起始地址 binary.BigEndian.PutUint16(request[4:6], quantity) // 寄存器数量 request[6] = byte(byteCount) // 字节数 // 填充数据 (大端序) for i, value := range data { binary.BigEndian.PutUint16(request[7+2*i:9+2*i], value) } // 计算 CRC 校验 crcTable := crc16.MakeTable(crc16.CRC16_MODBUS) crc := crc16.Checksum(request[:7+byteCount], crcTable) // 添加 CRC (低字节在前) request = append(request, byte(crc&0xFF), byte(crc>>8)) return request, quantity } // WriteMultipleRegistersParse 解析写入多个保持���存器响应 func WriteMultipleRegistersParse(address byte, startAddr uint16, quantity uint16, response []byte) error { // 检查响应最小长度 if len(response) < 6 { return fmt.Errorf("响应长度不足: %d bytes", len(response)) } // 提取数据和 CRC respData := response[:len(response)-2] receivedCRC := binary.LittleEndian.Uint16(response[len(response)-2:]) // 校验 CRC crcTable := crc16.MakeTable(crc16.CRC16_MODBUS) calculatedCRC := crc16.Checksum(respData, crcTable) if calculatedCRC != receivedCRC { return fmt.Errorf("CRC校验失败,计算值: %x,接收值: %x", calculatedCRC, receivedCRC) } // 验证地址和功能码 if respData[0] != address { return fmt.Errorf("响应地址不符,期望: %x,实际: %x", address, respData[0]) } // 处理正常/异常响应 switch respData[1] { case 0x10: // 验证写入的地址和数量 respStart := binary.BigEndian.Uint16(respData[2:4]) respQuantity := binary.BigEndian.Uint16(respData[4:6]) if respStart != startAddr || respQuantity != quantity { return fmt.Errorf("响应参数不匹配,地址期望: %x 实际: %x,数量期望: %d 实际: %d", startAddr, respStart, quantity, respQuantity) } return nil // 写入成功 case 0x90: // 异常响应 if len(respData) < 3 { return fmt.Errorf("异常响应格式错误") } return fmt.Errorf("Modbus异常码: %x", respData[2]) default: return fmt.Errorf("未知功能码: %x", respData[1]) } }