修bug
This commit is contained in:
@@ -220,7 +220,7 @@ class RS485Manager:
|
||||
rts_pin = port_info['rts_pin']
|
||||
lock = port_info['lock']
|
||||
|
||||
response_bytes = None
|
||||
response_buffer = bytearray() # 改:用缓冲累积
|
||||
with lock:
|
||||
try:
|
||||
# II. 线程安全与指令发送
|
||||
@@ -232,22 +232,115 @@ class RS485Manager:
|
||||
rts_pin.value(0) # 切换回接收模式 (DE/RE = LOW)
|
||||
log(f"总线 {bus_id} 原始命令发送成功: {command_bytes.hex()}")
|
||||
|
||||
# III. 接收响应
|
||||
response_bytes = uart.read()
|
||||
if response_bytes:
|
||||
log(f"总线 {bus_id} 收到响应: {response_bytes.hex()}")
|
||||
# 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) # 小块读
|
||||
if chunk:
|
||||
response_buffer.extend(chunk)
|
||||
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()}")
|
||||
else:
|
||||
log(f"警告: 总线 {bus_id} 响应中无有效帧。收到响应: {response_buffer.hex()}")
|
||||
return None
|
||||
else:
|
||||
log(f"警告: 总线 {bus_id} 未收到响应或响应超时。")
|
||||
return None
|
||||
log(f"警告: 总线 {bus_id} 未收到响应。")
|
||||
|
||||
except Exception as e:
|
||||
log(f"错误: 在总线 {bus_id} 上执行采集命令失败: {e}")
|
||||
return None
|
||||
|
||||
# IV. 响应解析与数据提取 (默认 Modbus RTU 浮点数)
|
||||
# TODO: 根据CollectTask的Protobuf定义,此处需要根据parser_type来选择具体的解析逻辑和类型。
|
||||
# 目前默认使用Modbus RTU大端浮点数解析。
|
||||
parsed_value = RS485Manager._parse_modbus_rtu_float_default(response_bytes)
|
||||
# IV. 解析(用修复版)
|
||||
parsed_value = RS485Manager._parse_modbus_rtu_default(response_bytes) # 改名,支持动态
|
||||
|
||||
# V. 返回结果
|
||||
return parsed_value
|
||||
|
||||
def _find_modbus_frame(self, buffer: bytearray, expected_slave: int, func_code: int) -> bytes | None:
|
||||
"""
|
||||
修复版:加调试;优先头检查;CRC 字节序标准 Modbus (低字节在前)。
|
||||
"""
|
||||
log(f"搜索帧: buffer 长度 {len(buffer)}, hex {buffer.hex()}")
|
||||
i = 0
|
||||
while i < len(buffer) - 6: # 最小 7 字节,-6 安全
|
||||
if buffer[i] == expected_slave and buffer[i + 1] == func_code:
|
||||
byte_count = buffer[i + 2]
|
||||
frame_len = 3 + byte_count + 2
|
||||
if len(buffer) - i >= frame_len:
|
||||
frame = bytes(buffer[i:i + frame_len])
|
||||
# CRC 预校验(标准 Modbus:CRC 低字节在前)
|
||||
core = frame[:-2]
|
||||
calc_crc = self._calculate_crc16_modbus(core)
|
||||
low_crc = frame[-2]
|
||||
high_crc = frame[-1]
|
||||
recv_crc = (high_crc << 8) | low_crc # 高<<8 | 低
|
||||
log(f"候选帧 at {i}: {frame.hex()}, calc CRC {calc_crc:04X}, recv {recv_crc:04X}")
|
||||
if calc_crc == recv_crc:
|
||||
log(f"找到有效帧: {frame.hex()}")
|
||||
return frame
|
||||
else:
|
||||
log(f"CRC 不匹配,跳过 (calc {calc_crc:04X} != recv {recv_crc:04X})")
|
||||
i += 1
|
||||
log("无有效帧")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _parse_modbus_rtu_default(response_bytes): # 改名,支持整数/浮点
|
||||
"""
|
||||
修复版:动态数据长;CRC 只用核心。
|
||||
"""
|
||||
if not response_bytes or len(response_bytes) < 7:
|
||||
log(f"警告: 响应过短。响应: {response_bytes.hex() if response_bytes else 'None'}")
|
||||
return None
|
||||
|
||||
# CRC 校验(只核心)
|
||||
data_for_crc = response_bytes[:-2]
|
||||
received_crc = (response_bytes[-1] << 8) | response_bytes[-2]
|
||||
|
||||
calculated_crc = RS485Manager._calculate_crc16_modbus(data_for_crc)
|
||||
if calculated_crc != received_crc:
|
||||
log(f"错误: CRC失败。接收: {received_crc:04X}, 计算: {calculated_crc:04X}. 响应: {response_bytes.hex()}")
|
||||
return None
|
||||
|
||||
function_code = response_bytes[1]
|
||||
byte_count = response_bytes[2]
|
||||
data_bytes = response_bytes[3:3 + byte_count]
|
||||
|
||||
if function_code not in [0x03, 0x04]:
|
||||
log(f"警告: 功能码 {function_code:02X} 不符。")
|
||||
return None
|
||||
|
||||
if len(data_bytes) != byte_count:
|
||||
log(f"错误: 数据长 {len(data_bytes)} != {byte_count}")
|
||||
return None
|
||||
|
||||
# 动态解析
|
||||
if byte_count == 2:
|
||||
# 整数 (e.g., 温度)
|
||||
try:
|
||||
value = int.from_bytes(data_bytes, 'big') # 或 signed '>h'
|
||||
parsed_value = value
|
||||
log(f"成功解析整数: {parsed_value}")
|
||||
return parsed_value
|
||||
except Exception as e:
|
||||
log(f"整数解析失败: {e}")
|
||||
return None
|
||||
elif byte_count == 4:
|
||||
# 浮点
|
||||
try:
|
||||
parsed_value = struct.unpack('>f', data_bytes)[0]
|
||||
log(f"成功解析浮点: {parsed_value}")
|
||||
return parsed_value
|
||||
except Exception as e:
|
||||
log(f"浮点失败: {e}")
|
||||
return None
|
||||
else:
|
||||
log(f"警告: 未知字节数 {byte_count}")
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user