From b69805063d2bee9dccc0ef805e1663dd7e1239c4 Mon Sep 17 00:00:00 2001 From: huang <1724659546@qq.com> Date: Mon, 13 Oct 2025 16:11:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lora_mesh_uart_passthrough_manager.py | 66 +++++++++++++------ app/processor.py | 1 + main.py | 1 - 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/app/lora/lora_mesh_uart_passthrough_manager.py b/app/lora/lora_mesh_uart_passthrough_manager.py index 53caa54..7387b96 100644 --- a/app/lora/lora_mesh_uart_passthrough_manager.py +++ b/app/lora/lora_mesh_uart_passthrough_manager.py @@ -47,7 +47,7 @@ class LoRaMeshUartPassthroughManager: self._reassembly_cache = {} # 分片重组缓冲区 { chunk_index: chunk_data } self._expected_chunks = 0 # 当前会话期望的总分片数 - log(f"LoRaMeshUartPassthroughManager: 配置加载完成. UART ID: {self.uart_id}, Baudrate: {self.baudrate}") + log(f"LoRaMeshUartPassthroughManager: 配置加载完成. UART ID: {self.uart_id}, Baudrate: {self.baudrate}, 针脚: {self.pins}") def send_packet(self, payload: bytes) -> bool: """ @@ -103,12 +103,22 @@ class LoRaMeshUartPassthroughManager: """ # 1. 从硬件读取数据到缓冲区 if self.uart.any(): - self._rx_buffer.extend(self.uart.read()) + new_data = self.uart.read() + if new_data: + log(f"LoRa: UART收到原始数据 (长度 {len(new_data)}): {new_data.hex()}") + self._rx_buffer.extend(new_data) + + # 如果缓冲区为空,没有必要继续处理 + if not self._rx_buffer: + return None + + # 2. 只要缓冲区有数据就持续尝试从缓冲区解析包 + while len(self._rx_buffer) > 0: + log(f"LoRa: --- 开始新一轮解析, 缓冲区 (长度 {len(self._rx_buffer)}): {self._rx_buffer.hex()} ---") - # 2. 循环尝试从缓冲区解析包 - while True: # 2.1 检查头部和长度字段是否存在 if len(self._rx_buffer) < 2: + log("LoRa: 缓冲区数据不足 (小于2字节),无法读取包头。等待更多数据...") return None # 数据不足,无法读取长度 # 2.2 检查帧头是否正确 @@ -116,64 +126,82 @@ class LoRaMeshUartPassthroughManager: log(f"LoRa: 接收到错误帧头: {hex(self._rx_buffer[0])},正在寻找下一个ED...") next_ed = self._rx_buffer.find(b'\xed', 1) if next_ed == -1: + log("LoRa: 缓冲区无有效帧头,已清空。") self._rx_buffer[:] = b'' + return None # 清空后没有数据了, 直接返回 else: + log(f"LoRa: 在位置 {next_ed} 找到下一个有效帧头,丢弃之前的数据。") self._rx_buffer = self._rx_buffer[next_ed:] - continue + continue # 继续循环,用新的缓冲区数据重新开始解析 # 2.3 检查包是否完整 payload_len = self._rx_buffer[1] + # 这里的 total_packet_len 计算方式存疑,它假设 payload_len 是 length 字段之后所有数据的长度。 + # 这与 send_packet 中的 length 计算方式可能不一致。 total_packet_len = 1 + 1 + payload_len + log(f"LoRa: 帧头正确(ED)。声明的后续包长(payload_len): {payload_len}。计算出的总包长: {total_packet_len}。") + if len(self._rx_buffer) < total_packet_len: + log(f"LoRa: '半包'情况,需要 {total_packet_len} 字节,但缓冲区只有 {len(self._rx_buffer)} 字节。等待更多数据...") return None # "半包"情况,等待更多数据 # 3. 提取和解析一个完整的物理包 + log(f"LoRa: 发现完整物理包 (长度 {total_packet_len}),正在提取...") packet = self._rx_buffer[:total_packet_len] self._rx_buffer = self._rx_buffer[total_packet_len:] + log(f"LoRa: 提取的包: {packet.hex()}。剩余缓冲区 (长度 {len(self._rx_buffer)}): {self._rx_buffer.hex()}") + + # --- 包结构解析 --- + # 根据代码 `chunk_data = packet[6:-2]` 推断,包结构为: + # 1 (帧头) + 1 (长度) + 2 (目标地址) + 1 (总分片) + 1 (当前分片) + N (数据) + 2 (源地址) + # 因此,一个合法的包至少需要 1+1+2+1+1+2 = 8个字节 + if len(packet) < 8: + log(f"LoRa: 包长度 {len(packet)} 小于协议最小长度8, 判定为坏包,已丢弃。") + continue addr = int.from_bytes(packet[2:4], 'big') total_chunks = packet[4] current_chunk = packet[5] # 提取数据块,排除末尾的2字节源地址 chunk_data = packet[6:-2] - - # --- 长度反向校验 --- - # 根据协议,Length字段 = 2 (自定义头) + N (数据块) - expected_payload_len = 2 + len(chunk_data) - if payload_len != expected_payload_len: - log(f"LoRa: 收到损坏的数据包!声明长度 {payload_len} 与实际计算长度 {expected_payload_len} 不符。已丢弃。") - # 包已从缓冲区移除,直接continue进入下一次循环,尝试解析缓冲区的后续内容 - continue - # --- 校验结束 --- + source_addr = int.from_bytes(packet[-2:], 'big') + log(f"LoRa: 解析包: 源地址={source_addr}, 目标地址={addr}, 总分片={total_chunks}, 当前分片={current_chunk}, 数据块长度={len(chunk_data)}") # 4. 重组逻辑 if total_chunks == 1: - log(f"LoRa: 收到单包消息,来自地址 {addr},长度 {len(chunk_data)}") + log(f"LoRa: 收到单包消息,来自地址 {source_addr},长度 {len(chunk_data)}") + self._reassembly_cache.clear() + self._expected_chunks = 0 return chunk_data # 对于多包消息,只有当收到第一个分片时才清空缓存并设置期望分片数 if current_chunk == 0: - log(f"LoRa: 开始接收新的多包会话 ({total_chunks}个分片)...") + log(f"LoRa: 开始接收新的多包会话 ({total_chunks}个分片) from {source_addr}...") self._reassembly_cache.clear() self._expected_chunks = total_chunks elif not self._reassembly_cache and self._expected_chunks == 0: # 如果不是第一个分片,但缓存是空的,说明错过了第一个分片,丢弃当前分片 - log(f"LoRa: 收到非首个分片 {current_chunk},但未检测到会话开始,已丢弃。") + log(f"LoRa: 收到非首个分片 {current_chunk} from {source_addr},但未检测到会话开始,已丢弃。") continue self._reassembly_cache[current_chunk] = chunk_data - log(f"LoRa: 收到分片 {current_chunk + 1}/{self._expected_chunks},已缓存 {len(self._reassembly_cache)} 个") + log(f"LoRa: 收到分片 {current_chunk + 1}/{self._expected_chunks} from {source_addr},已缓存 {len(self._reassembly_cache)} 个") if len(self._reassembly_cache) == self._expected_chunks: - log("LoRa: 所有分片已集齐,正在重组...") + log(f"LoRa: 所有分片已集齐 (from {source_addr}),正在重组...") full_payload = bytearray() for i in range(self._expected_chunks): if i not in self._reassembly_cache: log(f"LoRa: 重组失败!缺少分片 {i}。") self._reassembly_cache.clear() + self._expected_chunks = 0 return None full_payload.extend(self._reassembly_cache[i]) log(f"LoRa: 重组完成,总长度 {len(full_payload)}") self._reassembly_cache.clear() + self._expected_chunks = 0 return bytes(full_payload) + + # while 循环结束,意味着缓冲区被处理完毕但没有返回一个完整的包 + return None diff --git a/app/processor.py b/app/processor.py index 96f3dd1..9b16780 100644 --- a/app/processor.py +++ b/app/processor.py @@ -42,6 +42,7 @@ class Processor: try: instruction = client_pb.decode_instruction(packet_bytes) + log(f"解析指令成功: {instruction}") except Exception as e: log(f"错误:解码指令失败: {e}") return diff --git a/main.py b/main.py index 42c1805..47239c0 100644 --- a/main.py +++ b/main.py @@ -65,7 +65,6 @@ def loop(): 只负责监听LoRa,并将数据放入队列。 """ packet = lora_manager.receive_packet() - if packet: if task_queue.full(): log("警告:任务队列已满,新的LoRa数据包被丢弃!")