优化代码
This commit is contained in:
@@ -91,61 +91,6 @@ class RS485Manager:
|
||||
crc >>= 1
|
||||
return crc
|
||||
|
||||
@staticmethod
|
||||
def _parse_modbus_rtu_float_default(response_bytes):
|
||||
"""
|
||||
默认解析 Modbus RTU 响应中的 32 位 IEEE 754 单精度浮点数。
|
||||
假定为大端 (ABCD) 字节序。
|
||||
"""
|
||||
# 最小预期长度: 从站ID(1) + 功能码(1) + 字节计数(1) + 4字节数据 + CRC(2) = 9字节
|
||||
min_response_len = 9
|
||||
expected_data_byte_count = 4 # 32位浮点数占用4字节
|
||||
|
||||
if not response_bytes or len(response_bytes) < min_response_len:
|
||||
log(f"警告: 响应字节过短或为空,无法解析为浮点数。响应: {response_bytes.hex() if response_bytes else 'None'}")
|
||||
return None
|
||||
|
||||
# 提取响应组件
|
||||
# 注意: Modbus RTU CRC是LSB在前,所以这里需要调整
|
||||
# response_bytes[:-2] 是用于CRC计算的数据部分
|
||||
# response_bytes[-2:] 是CRC本身
|
||||
data_for_crc = response_bytes[:-2]
|
||||
received_crc = (response_bytes[-1] << 8) | response_bytes[-2] # CRC的低字节在前,高字节在后
|
||||
|
||||
# 1. CRC 校验
|
||||
calculated_crc = RS485Manager._calculate_crc16_modbus(data_for_crc)
|
||||
if calculated_crc != received_crc:
|
||||
log(f"错误: CRC校验失败。接收CRC: {received_crc:04X}, 计算CRC: {calculated_crc:04X}. 响应: {response_bytes.hex()}")
|
||||
return None
|
||||
|
||||
function_code = response_bytes[1]
|
||||
byte_count = response_bytes[2]
|
||||
data_bytes = response_bytes[3:3 + expected_data_byte_count]
|
||||
|
||||
# 2. 功能码检查 (假设读取保持寄存器0x03或输入寄存器0x04)
|
||||
if function_code not in [0x03, 0x04]:
|
||||
log(f"警告: 响应功能码 {function_code:02X} 不符合预期 (期望0x03或0x04)。响应: {response_bytes.hex()}")
|
||||
return None
|
||||
|
||||
# 3. 字节计数检查
|
||||
if byte_count != expected_data_byte_count:
|
||||
log(f"警告: 响应字节计数 {byte_count} 不符合预期 (期望{expected_data_byte_count})。响应: {response_bytes.hex()}")
|
||||
return None
|
||||
|
||||
# 4. 提取的数据字节长度检查 (与字节计数检查有重叠,但更安全)
|
||||
if len(data_bytes) != expected_data_byte_count:
|
||||
log(f"错误: 提取的数据字节长度不正确。期望{expected_data_byte_count}, 实际{len(data_bytes)}. 响应: {response_bytes.hex()}")
|
||||
return None
|
||||
|
||||
# 5. 转换为浮点数 (大端, ABCD)
|
||||
try:
|
||||
parsed_float = struct.unpack('>f', data_bytes)[0]
|
||||
log(f"成功解析浮点数: {parsed_float}")
|
||||
return parsed_float
|
||||
except Exception as e:
|
||||
log(f"错误: 浮点数转换失败: {e}. 数据字节: {data_bytes.hex()}. 响应: {response_bytes.hex()}")
|
||||
return None
|
||||
|
||||
def execute_raw_command(self, bus_id, command):
|
||||
"""
|
||||
【契约】执行一个“发后不理”的原始指令。
|
||||
@@ -203,8 +148,9 @@ class RS485Manager:
|
||||
bus_id = command_info.get("bus_number")
|
||||
command_bytes = command_info.get("command_bytes")
|
||||
|
||||
if bus_id is None or command_bytes is None:
|
||||
log("错误: Raw485Command 缺少 'bus_number' 或 'command_bytes' 字段。")
|
||||
# 增加对命令有效性的检查
|
||||
if bus_id is None or not command_bytes or len(command_bytes) < 2:
|
||||
log(f"错误: CollectTask 的 'command' 字段无效。bus_id: {bus_id}, command_bytes: {command_bytes}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
@@ -220,46 +166,54 @@ class RS485Manager:
|
||||
rts_pin = port_info['rts_pin']
|
||||
lock = port_info['lock']
|
||||
|
||||
response_buffer = bytearray() # 改:用缓冲累积
|
||||
response_bytes = None # 在锁外部初始化,确保其作用域
|
||||
response_buffer = bytearray()
|
||||
with lock:
|
||||
try:
|
||||
# II. 线程安全与指令发送
|
||||
rts_pin.value(1) # 设置为发送模式 (DE/RE = HIGH)
|
||||
time.sleep_us(100) # 短暂延时,确保方向切换完成
|
||||
rts_pin.value(1)
|
||||
time.sleep_us(100)
|
||||
uart.write(command_bytes)
|
||||
uart.flush()
|
||||
time.sleep_us(100) # 短暂延时,确保数据完全发出
|
||||
rts_pin.value(0) # 切换回接收模式 (DE/RE = LOW)
|
||||
time.sleep_us(100)
|
||||
rts_pin.value(0)
|
||||
log(f"总线 {bus_id} 原始命令发送成功: {command_bytes.hex()}")
|
||||
|
||||
# III. 接收响应(修复:超时循环 + 小块读)
|
||||
# III. 接收响应
|
||||
start_time = time.ticks_ms()
|
||||
response_timeout = self.default_timeouts.get('rs485_response', 500)
|
||||
while time.ticks_diff(time.ticks_ms(), start_time) < response_timeout:
|
||||
if uart.any():
|
||||
chunk = uart.read(32) # 小块读
|
||||
chunk = uart.read(32)
|
||||
if chunk:
|
||||
response_buffer.extend(chunk)
|
||||
start_time = time.ticks_ms() # 重置超时
|
||||
start_time = time.ticks_ms() # 收到数据就重置超时
|
||||
time.sleep_ms(5)
|
||||
|
||||
if response_buffer:
|
||||
# 新增:搜索有效帧,跳前缀
|
||||
response_bytes = self._find_modbus_frame(response_buffer, bus_id, 4)
|
||||
if response_bytes:
|
||||
log(f"总线 {bus_id} 收到有效响应: {response_bytes.hex()}")
|
||||
# 动态地从请求命令中获取预期的从站ID和功能码
|
||||
expected_slave_id = command_bytes[0]
|
||||
expected_func_code = command_bytes[1]
|
||||
|
||||
found_frame = self._find_modbus_frame(response_buffer, expected_slave_id, expected_func_code)
|
||||
if found_frame:
|
||||
log(f"总线 {bus_id} 收到有效响应: {found_frame.hex()}")
|
||||
response_bytes = found_frame # 将找到的帧赋值给外部变量
|
||||
else:
|
||||
log(f"警告: 总线 {bus_id} 响应中无有效帧。收到响应: {response_buffer.hex()}")
|
||||
return None
|
||||
else:
|
||||
log(f"警告: 总线 {bus_id} 未收到响应。")
|
||||
|
||||
except Exception as e:
|
||||
log(f"错误: 在总线 {bus_id} 上执行采集命令失败: {e}")
|
||||
return None
|
||||
|
||||
# IV. 统一处理和解析
|
||||
# 无论是因为超时、未找到有效帧还是发生异常,只要 response_bytes 仍为 None,就任务失败
|
||||
if response_bytes is None:
|
||||
return None
|
||||
|
||||
# IV. 解析(用修复版)
|
||||
parsed_value = RS485Manager._parse_modbus_rtu_default(response_bytes) # 改名,支持动态
|
||||
# 使用找到的有效帧进行解析
|
||||
parsed_value = RS485Manager._parse_modbus_rtu_default(response_bytes)
|
||||
|
||||
return parsed_value
|
||||
|
||||
|
||||
@@ -49,10 +49,18 @@ class Processor:
|
||||
|
||||
# 根据指令类型,分发到不同的业务处理方法
|
||||
if 'raw_485_command' in instruction:
|
||||
self._process_exec_command(instruction['raw_485_command'])
|
||||
cmd = instruction['raw_485_command']
|
||||
if cmd:
|
||||
self._process_exec_command(cmd)
|
||||
else:
|
||||
log("警告:'raw_485_command' 指令内容为空。")
|
||||
|
||||
elif 'batch_collect_command' in instruction:
|
||||
self._process_collect_command(instruction['batch_collect_command'])
|
||||
cmd = instruction['batch_collect_command']
|
||||
if cmd:
|
||||
self._process_collect_command(cmd)
|
||||
else:
|
||||
log("警告:'batch_collect_command' 指令内容为空。")
|
||||
|
||||
else:
|
||||
log(f"警告:收到未知或不适用于此设备的指令类型: {instruction}")
|
||||
|
||||
Reference in New Issue
Block a user