调整以适应esp32

This commit is contained in:
2025-10-13 14:35:20 +08:00
parent 961b0c170b
commit 902c90cf19
15 changed files with 56 additions and 63 deletions

View File

@@ -7,9 +7,7 @@ RS485 总线管理器实现
此模块实现了 IBusManager 接口用于管理 RS485 总线通信
"""
from .bus_interface import IBusManager
from typing import Dict, Any
from main.logs.logger import log
from ..logs.logger import log
# 导入 MicroPython 的 UART 和 Pin 库
from machine import UART, Pin
@@ -18,26 +16,26 @@ import _thread # 用于线程同步
import struct # 用于浮点数转换
class RS485Manager(IBusManager):
class RS485Manager:
"""
RS485 总线管理器
负责 RS485 设备的指令发送响应接收和数据解析
"""
def __init__(self, bus_config: Dict[int, Dict[str, Any]], default_timeouts: Dict[str, int]):
def __init__(self, bus_config, default_timeouts):
"""
构造函数注入配置
根据传入的配置初始化 RS485 总线对应的 UART 管理器
Args:
bus_config (Dict[int, Dict[str, Any]]): 包含所有总线配置的字典
bus_config: 包含所有总线配置的字典
键是总线ID值是该总线的详细配置
default_timeouts (Dict[str, int]): 包含各种默认超时设置的字典
default_timeouts: 包含各种默认超时设置的字典
"""
self.bus_config = bus_config
self.default_timeouts = default_timeouts
# 存储以总线号为key的UART管理器实例、RTS引脚和锁
self.bus_ports: Dict[int, Dict[str, Any]] = {}
self.bus_ports = {}
log("RS485Manager 已使用配置初始化。")
log(f"总线配置: {self.bus_config}")
@@ -77,7 +75,8 @@ class RS485Manager(IBusManager):
else:
log(f"总线 {bus_id} 的协议不是 RS485跳过初始化。")
def _calculate_crc16_modbus(self, data: bytes) -> int:
@staticmethod
def _calculate_crc16_modbus(data):
"""
计算 Modbus RTU CRC16 校验码
"""
@@ -85,23 +84,24 @@ class RS485Manager(IBusManager):
for byte in data:
crc ^= byte
for _ in range(8):
if (crc & 0x0001):
if crc & 0x0001:
crc >>= 1
crc ^= 0xA001
else:
crc >>= 1
return crc
def _parse_modbus_rtu_float_default(self, response_bytes: bytes) -> float | None:
@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字节
min_response_len = 9
expected_data_byte_count = 4 # 32位浮点数占用4字节
if not response_bytes or len(response_bytes) < MIN_RESPONSE_LEN:
if not response_bytes or len(response_bytes) < min_response_len:
log(f"警告: 响应字节过短或为空,无法解析为浮点数。响应: {response_bytes.hex() if response_bytes else 'None'}")
return None
@@ -113,15 +113,14 @@ class RS485Manager(IBusManager):
received_crc = (response_bytes[-1] << 8) | response_bytes[-2] # CRC的低字节在前高字节在后
# 1. CRC 校验
calculated_crc = self._calculate_crc16_modbus(data_for_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
slave_id = response_bytes[0]
function_code = response_bytes[1]
byte_count = response_bytes[2]
data_bytes = response_bytes[3:3 + EXPECTED_DATA_BYTE_COUNT]
data_bytes = response_bytes[3:3 + expected_data_byte_count]
# 2. 功能码检查 (假设读取保持寄存器0x03或输入寄存器0x04)
if function_code not in [0x03, 0x04]:
@@ -129,13 +128,13 @@ class RS485Manager(IBusManager):
return None
# 3. 字节计数检查
if byte_count != EXPECTED_DATA_BYTE_COUNT:
log(f"警告: 响应字节计数 {byte_count} 不符合预期 (期望{EXPECTED_DATA_BYTE_COUNT})。响应: {response_bytes.hex()}")
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()}")
if len(data_bytes) != expected_data_byte_count:
log(f"错误: 提取的数据字节长度不正确。期望{expected_data_byte_count}, 实际{len(data_bytes)}. 响应: {response_bytes.hex()}")
return None
# 5. 转换为浮点数 (大端, ABCD)
@@ -147,7 +146,7 @@ class RS485Manager(IBusManager):
log(f"错误: 浮点数转换失败: {e}. 数据字节: {data_bytes.hex()}. 响应: {response_bytes.hex()}")
return None
def execute_raw_command(self, bus_id: int, command: bytes) -> None:
def execute_raw_command(self, bus_id, command):
"""
契约执行一个发后不理的原始指令
@@ -176,7 +175,7 @@ class RS485Manager(IBusManager):
except Exception as e:
log(f"错误: 在总线 {bus_id} 上执行原始命令失败: {e}")
def execute_collect_task(self, task: dict) -> float | None:
def execute_collect_task(self, task):
"""
契约执行一个完整的采集任务并直接返回最终的数值
@@ -188,11 +187,11 @@ class RS485Manager(IBusManager):
- 返回最终的float数值或在任何失败情况下返回None
Args:
task (dict): 从Protobuf解码出的单个CollectTask消息字典
task: 从Protobuf解码出的单个CollectTask消息字典
期望结构: {"command": {"bus_number": int, "command_bytes": bytes}}
Returns:
float | None: 成功解析则返回数值否则返回None
成功解析则返回数值否则返回None
"""
# I. 任务参数解析与初步验证
try:
@@ -248,7 +247,7 @@ class RS485Manager(IBusManager):
# IV. 响应解析与数据提取 (默认 Modbus RTU 浮点数)
# TODO: 根据CollectTask的Protobuf定义此处需要根据parser_type来选择具体的解析逻辑和类型。
# 目前默认使用Modbus RTU大端浮点数解析。
parsed_value = self._parse_modbus_rtu_float_default(response_bytes)
parsed_value = RS485Manager._parse_modbus_rtu_float_default(response_bytes)
# V. 返回结果
return parsed_value

View File

@@ -22,8 +22,8 @@ LORA_CONFIG = {
# LoRa模块连接的GPIO引脚
'pins': {
'tx': 17, # UART TX
'rx': 16, # UART RX
'tx': 5, # UART TX
'rx': 4, # UART RX
},
# LoRa Mesh 模块发送模式(EC: 透传; ED: 完整数据包)
@@ -60,9 +60,9 @@ BUS_CONFIG = {
# 该总线使用的GPIO引脚
'pins': {
'tx': 4, # RS485 TX
'rx': 5, # RS485 RX
'rts': 2, # RS485 DE/RE 方向控制引脚
'tx': 16, # RS485 TX
'rx': 17, # RS485 RX
'rts': 15, # RS485 DE/RE 方向控制引脚
}
},

View File

@@ -5,7 +5,7 @@
一个简单的可配置的日志记录器模块
"""
from main.config.config import *
from app.config.config import *
def log(message: str):

View File

@@ -8,13 +8,12 @@ LoRa模块的具体实现 (UART Passthrough for LoRa Mesh)
这个实现针对的是通过UART进行透传的LoRa Mesh模块
"""
from .lora_interface import ILoraManager
from main.logs.logger import log
from ..logs.logger import log
from machine import UART
import time
class LoRaMeshUartPassthroughManager(ILoraManager):
class LoRaMeshUartPassthroughManager:
"""
通过UART与LoRa Mesh模块通信的处理器实现 (ED模式)
实现了自动分片与重组逻辑

View File

@@ -8,15 +8,12 @@
- 编排业务流程解码指令并将业务任务分发给相应的管理器
- 完全不关心总线通信和数据解析的技术实现细节
"""
# 导入我们定义的“契约”(接口)
from lora.lora_interface import ILoraManager
from bus.bus_interface import IBusManager
from app.lora.lora_mesh_uart_passthrough_manager import LoRaMeshUartPassthroughManager
from app.bus.rs485_manager import RS485Manager
# 导入Protobuf解析代码
from proto import client_pb
from app.proto import client_pb
from logs.logger import log
from app.logs.logger import log
class Processor:
@@ -25,7 +22,7 @@ class Processor:
它依赖于抽象的面向业务的接口
"""
def __init__(self, lora_handler: ILoraManager, bus_manager: IBusManager):
def __init__(self, lora_handler: LoRaMeshUartPassthroughManager, bus_manager: RS485Manager):
"""
构造函数 (依赖注入)

View File

@@ -10,12 +10,12 @@
- 从队列中取出任务并交给Processor进行耗时处理
"""
import uqueue
from processor import Processor
from logs.logger import log
from app.uqueue import Queue
from app.processor import Processor
from app.logs.logger import log
def worker_task(task_queue: uqueue.Queue, processor: Processor):
def worker_task(task_queue: Queue, processor: Processor):
"""
工作线程的主函数

View File

@@ -15,25 +15,23 @@
import time
import _thread
from config import config
import uqueue # 导入我们自己创建的本地uqueue模块
from app.config import config
from app.uqueue import Queue # 导入我们自己创建的本地uqueue模块
# 导入接口和实现
from lora.lora_interface import ILoraManager
from bus.bus_interface import IBusManager
from lora.lora_mesh_uart_passthrough_manager import LoRaMeshUartPassthroughManager
from bus.rs485_manager import RS485Manager
from processor import Processor
from app.lora.lora_mesh_uart_passthrough_manager import LoRaMeshUartPassthroughManager
from app.bus.rs485_manager import RS485Manager
from app.processor import Processor
# 导入工作线程的执行函数
from worker import worker_task
from logs.logger import log
from app.worker import worker_task
from app.logs.logger import log
# --- 模块级变量定义 (带有类型提示) ---
lora_manager: ILoraManager | None = None
bus_manager: IBusManager | None = None
lora_manager: LoRaMeshUartPassthroughManager | None = None
bus_manager: RS485Manager | None = None
processor: Processor | None = None
task_queue: uqueue.Queue | None = None
task_queue: Queue | None = None
def setup():
@@ -52,7 +50,7 @@ def setup():
# 2. 从配置文件读取队列长度,并创建线程安全的队列
queue_size = config.SYSTEM_PARAMS.get('task_queue_max_size', 10)
task_queue = uqueue.Queue(maxsize=queue_size)
task_queue = Queue(maxsize=queue_size)
log(f"任务队列已创建,最大容量: {queue_size}")
# 3. 启动工作线程