first commit
This commit is contained in:
23
midware/core/__init__.py
Normal file
23
midware/core/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# midware/core/__init__.py
|
||||
"""
|
||||
核心业务层:总线-UDP解耦、总线驱动、数据处理
|
||||
"""
|
||||
# from .bus_udp_decoupler import (
|
||||
# start_all_threads,
|
||||
# stop_all_threads,
|
||||
# protocol_dispatch_queue,
|
||||
# bus_queues,
|
||||
# udp_send_queue
|
||||
# )
|
||||
|
||||
from .bus_udp_decoupler import (
|
||||
start_all_threads,
|
||||
stop_all_threads,
|
||||
bus_recv_queues,
|
||||
bus_send_queues,
|
||||
udp_send_queue,
|
||||
udp_recv_dispatch_queue
|
||||
)
|
||||
# 暴露版本/作者等元信息(可选)
|
||||
__version__ = "1.0.0"
|
||||
__author__ = "xxx"
|
||||
BIN
midware/core/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
midware/core/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
midware/core/__pycache__/bus_udp_decoupler.cpython-311.pyc
Normal file
BIN
midware/core/__pycache__/bus_udp_decoupler.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
midware/core/__pycache__/data_forward.cpython-311.pyc
Normal file
BIN
midware/core/__pycache__/data_forward.cpython-311.pyc
Normal file
Binary file not shown.
BIN
midware/core/__pycache__/error_check.cpython-311.pyc
Normal file
BIN
midware/core/__pycache__/error_check.cpython-311.pyc
Normal file
Binary file not shown.
0
midware/core/bus_drivers/1553b_driver.py
Normal file
0
midware/core/bus_drivers/1553b_driver.py
Normal file
0
midware/core/bus_drivers/__init__.py
Normal file
0
midware/core/bus_drivers/__init__.py
Normal file
0
midware/core/bus_drivers/ad_driver.py
Normal file
0
midware/core/bus_drivers/ad_driver.py
Normal file
78
midware/core/bus_drivers/base_driver.py
Normal file
78
midware/core/bus_drivers/base_driver.py
Normal file
@@ -0,0 +1,78 @@
|
||||
# midware/drivers/base_driver.py
|
||||
|
||||
"""
|
||||
Tan mingyan
|
||||
2026/3/9
|
||||
驱动基类(base_driver.py)—— 定义标准接口(核心)
|
||||
所有总线驱动继承该基类,保证接口统一,解耦 bus_udp_decoupler.py 与具体驱动实现:
|
||||
"""
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional, Dict, Any
|
||||
from loguru import logger
|
||||
|
||||
class BaseBusDriver(ABC):
|
||||
"""
|
||||
总线驱动基类:定义所有总线必须实现的标准接口
|
||||
遵循「开闭原则」:新增总线只需继承该类实现接口,无需修改现有代码
|
||||
"""
|
||||
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
||||
"""
|
||||
初始化驱动
|
||||
:param config: 驱动配置(如波特率、端口、IP等)
|
||||
"""
|
||||
self.config = config or {}
|
||||
self.is_connected = False # 驱动连接状态
|
||||
self._init_config() # 初始化配置
|
||||
|
||||
def _init_config(self):
|
||||
"""初始化默认配置(子类可重写)"""
|
||||
logger.info(f"初始化 {self.__class__.__name__} 默认配置")
|
||||
|
||||
@abstractmethod
|
||||
def connect(self) -> bool:
|
||||
"""
|
||||
连接总线(如打开串口、建立CAN通道、连接1553B板卡)
|
||||
:return: 连接成功返回True,失败返回False
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def disconnect(self) -> bool:
|
||||
"""
|
||||
断开总线连接
|
||||
:return: 断开成功返回True,失败返回False
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def send(self, data: bytes, **kwargs) -> bool:
|
||||
"""
|
||||
发送数据到总线
|
||||
:param data: 待发送的原始字节数据
|
||||
:param kwargs: 扩展参数(如优先级、地址、帧ID等)
|
||||
:return: 发送成功返回True,失败返回False
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def recv(self, timeout: float = 0.1, **kwargs) -> Optional[bytes]:
|
||||
"""
|
||||
从总线接收数据
|
||||
:param timeout: 接收超时时间(秒)
|
||||
:param kwargs: 扩展参数(如过滤条件、地址等)
|
||||
:return: 接收到的字节数据,超时/失败返回None
|
||||
"""
|
||||
pass
|
||||
|
||||
def check_status(self) -> bool:
|
||||
"""
|
||||
检查驱动状态(默认实现,子类可重写)
|
||||
:return: 驱动正常返回True,异常返回False
|
||||
"""
|
||||
return self.is_connected
|
||||
|
||||
def __del__(self):
|
||||
"""析构函数:自动断开连接"""
|
||||
if self.is_connected:
|
||||
self.disconnect()
|
||||
logger.info(f"{self.__class__.__name__} 自动断开连接")
|
||||
0
midware/core/bus_drivers/can_driver.py
Normal file
0
midware/core/bus_drivers/can_driver.py
Normal file
0
midware/core/bus_drivers/oc_driver.py
Normal file
0
midware/core/bus_drivers/oc_driver.py
Normal file
0
midware/core/bus_drivers/uart_driver.py
Normal file
0
midware/core/bus_drivers/uart_driver.py
Normal file
637
midware/core/bus_udp_decoupler.py
Normal file
637
midware/core/bus_udp_decoupler.py
Normal file
@@ -0,0 +1,637 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Tan Mintgyan
|
||||
2026/3/9
|
||||
总线-UDP双向通信解耦模块(新增带协议优先级:1553B>CAN>UART>AD>OC>网络)
|
||||
"""
|
||||
import threading
|
||||
import queue
|
||||
import time
|
||||
from loguru import logger
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
from midware.config.base_config import DEVICE_CONFIG_DICT
|
||||
from midware.drivers import create_bus_driver
|
||||
import midware.config.base_config as base_config
|
||||
|
||||
from ..drivers.renode_agent import renode
|
||||
|
||||
|
||||
# ========== 1. 核心:定义协议优先级映射(数值越小优先级越高) ==========
|
||||
PROTOCOL_PRIORITY = {
|
||||
"1553B": 1, # 最高优先级
|
||||
"CAN": 2,
|
||||
"UART": 3,
|
||||
"AD": 4,
|
||||
"OC": 5,
|
||||
"网络": 6 # 最低优先级
|
||||
}
|
||||
MAX_QUEUE_SIZE = 1000 # 队列最大长度(可按协议单独调整)
|
||||
|
||||
# ========== 2. 收发队列分离(发送队列统一用PriorityQueue) ==========
|
||||
# 总线接收队列(总线→中间件:上行数据,无需优先级)
|
||||
bus_recv_queues = {
|
||||
"1553B": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"CAN": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"UART": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"AD": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"OC": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"网络": queue.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
}
|
||||
|
||||
# 总线发送队列(中间件→总线:下行数据,带优先级)
|
||||
# 统一使用PriorityQueue,按PROTOCOL_PRIORITY的数值排序
|
||||
bus_send_queues = {
|
||||
"1553B": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE),
|
||||
"CAN": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE),
|
||||
"UART": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE),
|
||||
"AD": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE),
|
||||
"OC": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE),
|
||||
"网络": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE)
|
||||
}
|
||||
|
||||
# UDP发送队列(中间件→UDP:上行数据)
|
||||
udp_send_queue = queue.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
# UDP接收分发队列(UDP→中间件:下行数据)
|
||||
udp_recv_dispatch_queue = queue.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
|
||||
# ========== 3. UDP接收线程:自动映射协议优先级 ==========
|
||||
def udp_recv_thread(udp_server):
|
||||
"""UDP接收线程:接收下行指令,自动分配优先级后放入总线发送队列"""
|
||||
logger.info("UDP接收线程(下行指令)启动")
|
||||
|
||||
##测试用
|
||||
try:
|
||||
logger.debug("测试队列入队")
|
||||
print("测试队列入队")
|
||||
protocol= 'AD'
|
||||
dev_name = 'adc1',#2026/4/9
|
||||
#dev_name = '正电压采集热敏量采集',
|
||||
raw_data = b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'#56*2=112字节
|
||||
priority = 3
|
||||
bus_send_queues[protocol].put_nowait((
|
||||
priority, # 按数值从小到大优先
|
||||
{
|
||||
"dev_name": dev_name,
|
||||
"raw_data": raw_data,
|
||||
"protocol": protocol,
|
||||
"priority": priority,
|
||||
"recv_time": time.time() # 记录接收时间
|
||||
}
|
||||
))
|
||||
logger.debug(
|
||||
f"下行指令入队|{protocol}(优先级{priority})|{dev_name}|"
|
||||
f"队列长度:{bus_send_queues[protocol].qsize()}"
|
||||
)
|
||||
except queue.Full:
|
||||
logger.warning(
|
||||
f"{protocol}(优先级{priority})发送队列已满,丢弃 {dev_name} 下行指令"
|
||||
)
|
||||
|
||||
while True:
|
||||
try:
|
||||
recv_data = udp_server.recv_multi_udp_hex()
|
||||
if recv_data:
|
||||
for data in recv_data:
|
||||
protocol = data.get("protocol", "").strip().upper()
|
||||
dev_name = data.get("dev_name", "")
|
||||
raw_data = data.get("raw_data", b"")
|
||||
recv_time = time.time()
|
||||
# 核心:自动获取协议优先级(未知协议设为最低优先级7)
|
||||
priority = PROTOCOL_PRIORITY.get(protocol, 7)
|
||||
|
||||
if protocol not in bus_send_queues:
|
||||
logger.warning(f"未知协议 {protocol},丢弃下行指令:{dev_name}(优先级:{priority})")
|
||||
continue
|
||||
|
||||
# 放入总线发送队列(PriorityQueue格式:(优先级数值, 数据))
|
||||
try:
|
||||
bus_send_queues[protocol].put_nowait((
|
||||
priority, # 按数值从小到大优先
|
||||
#recv_time,#新增,用来打破优先级相同的平局
|
||||
{
|
||||
"dev_name": dev_name,
|
||||
"raw_data": raw_data,
|
||||
"protocol": protocol,
|
||||
"priority": priority,
|
||||
"recv_time": recv_time # 记录接收时间
|
||||
}
|
||||
))
|
||||
logger.debug(
|
||||
f"下行指令入队|{protocol}(优先级{priority})|{dev_name}|"
|
||||
f"队列长度:{bus_send_queues[protocol].qsize()}"
|
||||
)
|
||||
except queue.Full:
|
||||
logger.warning(
|
||||
f"{protocol}(优先级{priority})发送队列已满,丢弃 {dev_name} 下行指令"
|
||||
)
|
||||
time.sleep(1e-6)
|
||||
except Exception as e:
|
||||
logger.error(f"UDP接收线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
# ========== 4. 总线发送线程:按优先级消费数据 ==========
|
||||
'''
|
||||
def bus_send_thread(protocol: str, bus_driver: Optional[Any] = None):#2026/3/9停用
|
||||
"""总线发送线程:优先消费高优先级数据(数值越小越先处理)"""
|
||||
logger.info(f"{protocol} 总线发送线程启动(优先级:{PROTOCOL_PRIORITY.get(protocol, 7)})")
|
||||
while True:
|
||||
try:
|
||||
# PriorityQueue自动按优先级取值(数值小的先出)
|
||||
priority, send_data = bus_send_queues[protocol].get(timeout=1)
|
||||
dev_name = send_data["dev_name"]
|
||||
raw_data = send_data["raw_data"]
|
||||
recv_time = send_data["recv_time"]
|
||||
|
||||
# 超时检查(可选:超过5秒未发送则丢弃)
|
||||
if time.time() - recv_time > 5:
|
||||
logger.warning(
|
||||
f"{protocol}(优先级{priority})|{dev_name} 指令超时(5秒),丢弃"
|
||||
)
|
||||
bus_send_queues[protocol].task_done()
|
||||
continue
|
||||
|
||||
# 核心:总线发送逻辑(替换为真实驱动调用)
|
||||
logger.info(
|
||||
f"总线发送|{protocol}(优先级{priority})|{dev_name}|"
|
||||
f"数据:{raw_data.hex()}|队列剩余:{bus_send_queues[protocol].qsize()}"
|
||||
)
|
||||
# if bus_driver:
|
||||
# bus_driver.send(raw_data) # 调用总线驱动发送
|
||||
|
||||
# 标记任务完成
|
||||
bus_send_queues[protocol].task_done()
|
||||
except queue.Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 发送线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
'''
|
||||
|
||||
# ========== 修正:总线发送线程(参数改为接收驱动配置) ==========
|
||||
def bus_send_thread(protocol: str, bus_driver_config: Optional[Dict[str, Any]] = None):
|
||||
"""
|
||||
总线发送线程:通过统一驱动接口发送数据
|
||||
:param protocol: 协议名称
|
||||
:param bus_driver_config: 驱动配置字典
|
||||
"""
|
||||
logger.info(f"{protocol} 总线发送线程启动(优先级:{PROTOCOL_PRIORITY.get(protocol, 7)})")
|
||||
|
||||
# 创建驱动实例
|
||||
try:
|
||||
driver = create_bus_driver(protocol, config=bus_driver_config)
|
||||
# 连接总线
|
||||
if not driver.connect():
|
||||
logger.error(f"{protocol} 驱动连接失败,线程退出")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 驱动创建失败:{str(e)},线程退出")
|
||||
return
|
||||
|
||||
while True:
|
||||
try:
|
||||
priority, send_data = bus_send_queues[protocol].get(timeout=1)
|
||||
dev_name = send_data["dev_name"]
|
||||
raw_data = send_data["raw_data"]
|
||||
recv_time = send_data["recv_time"]
|
||||
|
||||
'''# 超时检查
|
||||
if time.time() - recv_time > 5:
|
||||
logger.warning(f"{protocol}(优先级{priority})|{dev_name} 指令超时,丢弃")
|
||||
bus_send_queues[protocol].task_done()
|
||||
continue
|
||||
'''
|
||||
# 调用驱动发送(统一接口)
|
||||
send_success = driver.send(
|
||||
data=raw_data,
|
||||
priority=priority, # 传递优先级参数
|
||||
dev_name=dev_name # 传递设备名
|
||||
)
|
||||
|
||||
if send_success:
|
||||
logger.info(
|
||||
f"{protocol}(优先级{priority})|{dev_name} 发送成功|"
|
||||
f"数据:{raw_data.hex()}|队列剩余:{bus_send_queues[protocol].qsize()}"
|
||||
)
|
||||
else:
|
||||
logger.error(f"{protocol}(优先级{priority})|{dev_name} 发送失败")
|
||||
|
||||
bus_send_queues[protocol].task_done()
|
||||
except queue.Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 发送线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
# 线程退出时断开驱动(析构函数也会自动处理)
|
||||
driver.disconnect()
|
||||
|
||||
# ========== 修正:start_all_threads 函数(适配 bus_driver_configs 参数) ==========
|
||||
def start_all_threads(udp_server, bus_driver_configs: Optional[Dict[str, Any]] = None):
|
||||
"""
|
||||
启动所有线程
|
||||
:param udp_server: UDP服务实例
|
||||
:param bus_driver_configs: 驱动配置字典,格式:{"1553B": {...}, "CAN": {...}, ...}
|
||||
"""
|
||||
threads = []
|
||||
bus_driver_configs = bus_driver_configs or {} # 无配置时设为空字典
|
||||
|
||||
# 按优先级从高到低排序协议
|
||||
sorted_protos = sorted(PROTOCOL_PRIORITY.keys(), key=lambda x: PROTOCOL_PRIORITY[x])
|
||||
|
||||
# 1. UDP接收线程
|
||||
udp_recv_t = threading.Thread(target=udp_recv_thread, args=(udp_server,), daemon=True)
|
||||
threads.append(udp_recv_t)
|
||||
|
||||
# 2. 总线发送线程(按优先级排序启动,传递对应驱动配置)
|
||||
for protocol in sorted_protos:
|
||||
# 获取当前协议的驱动配置
|
||||
driver_config = bus_driver_configs.get(protocol, {})
|
||||
send_t = threading.Thread(
|
||||
target=bus_send_thread,
|
||||
args=(protocol, driver_config), # 传递协议名+驱动配置
|
||||
daemon=True
|
||||
)
|
||||
threads.append(send_t)
|
||||
'''
|
||||
# 3. 总线接收线程(按优先级排序启动,传递对应驱动配置)
|
||||
for protocol in sorted_protos:
|
||||
driver_config = bus_driver_configs.get(protocol, {})
|
||||
recv_t = threading.Thread(
|
||||
target=bus_recv_thread,
|
||||
args=(protocol, driver_config), # 传递协议名+驱动配置
|
||||
daemon=True
|
||||
)
|
||||
threads.append(recv_t)
|
||||
'''
|
||||
|
||||
# 4. 总线接收分发线程
|
||||
recv_dispatch_t = threading.Thread(target=bus_recv_dispatch_thread, daemon=True)
|
||||
threads.append(recv_dispatch_t)
|
||||
|
||||
# 5. UDP发送线程
|
||||
udp_send_t = threading.Thread(target=udp_send_thread, args=(udp_server,), daemon=True)
|
||||
threads.append(udp_send_t)
|
||||
|
||||
#6. 总线轮询线程
|
||||
for protocol in sorted_protos:
|
||||
driver_config = bus_driver_configs.get(protocol, {})
|
||||
daq_t = threading.Thread(
|
||||
target=bus_daq_thread,
|
||||
args=(protocol, driver_config), # 传递协议名+驱动配置
|
||||
daemon=True
|
||||
)
|
||||
threads.append(daq_t)
|
||||
|
||||
# 启动所有线程
|
||||
for t in threads:
|
||||
t.start()
|
||||
logger.info(f"线程 {t.name} 启动成功")
|
||||
return threads
|
||||
|
||||
# ========== 其他函数(stop_all_threads、udp_recv_thread等)保持不变 ==========
|
||||
|
||||
|
||||
# ========== 5. 总线接收线程(无优先级,保持原有逻辑) ==========
|
||||
# ========== 修正:总线接收线程(参数改为接收驱动配置) ==========
|
||||
def bus_recv_thread(protocol: str, bus_driver_config: Optional[Dict[str, Any]] = None):
|
||||
"""总线接收线程:通过统一驱动接口接收数据"""
|
||||
logger.info(f"{protocol} 总线接收线程启动")
|
||||
|
||||
# 创建驱动实例
|
||||
try:
|
||||
driver = create_bus_driver(protocol, config=bus_driver_config)
|
||||
if not driver.connect():
|
||||
logger.error(f"{protocol} 驱动连接失败,线程退出")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 驱动创建失败:{str(e)},线程退出")
|
||||
return
|
||||
|
||||
time.sleep(0.001)#5->0.5
|
||||
while True:
|
||||
try:
|
||||
'''
|
||||
##循环发送读取请求
|
||||
# if(protocol=="UART"):
|
||||
# sysbus_cmd = f'uart24 GetTXFIFODataString'
|
||||
# print(sysbus_cmd)
|
||||
# response = renode.send_sync(sysbus_cmd)#2026/4/10
|
||||
time.sleep(0.001)
|
||||
|
||||
##循环发送读取请求
|
||||
if(protocol == "UART"):#发现protocol == "CAN"时候循环更快
|
||||
sysbus_cmd = f'uart0 GetTXFIFODataString'#uart 0
|
||||
logger.info(f'uart0轮询请求:{sysbus_cmd}')#print(sysbus_cmd)
|
||||
response = renode.send_sync(sysbus_cmd,timeout_ms=10)#2026/4/10
|
||||
time.sleep(0.001)
|
||||
|
||||
if(protocol == "CAN"):
|
||||
sysbus_cmd = f'can_a GetTxBufferDataString'#CAN_A
|
||||
#sysbus_cmd = f'uart0 GetTXFIFODataString'#uart 0
|
||||
logger.info(f'can_a轮询请求:{sysbus_cmd}')#print(sysbus_cmd)
|
||||
response = renode.send_sync(sysbus_cmd,timeout_ms=10)#2026/4/10
|
||||
time.sleep(0.25)
|
||||
'''
|
||||
# 调用驱动接收(统一接口)
|
||||
# raw_data = driver.recv(timeout=0.001) # 短超时,非阻塞
|
||||
## 以下代码没有作用,因为recv接口没有实现
|
||||
'''
|
||||
if raw_data and len(raw_data) > 0:
|
||||
dev_name = f"{protocol}_DEV"
|
||||
try:
|
||||
bus_recv_queues[protocol].put_nowait({
|
||||
"dev_name": dev_name,
|
||||
"raw_data": raw_data,
|
||||
"protocol": protocol,
|
||||
"recv_time": time.time()
|
||||
})
|
||||
logger.debug(f"{protocol} 接收:{dev_name} 上行数据,队列长度:{bus_recv_queues[protocol].qsize()}")
|
||||
except queue.Full:
|
||||
logger.warning(f"{protocol} 接收队列已满,丢弃上行数据")
|
||||
time.sleep(1e-6)
|
||||
'''
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 接收线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
driver.disconnect()
|
||||
'''
|
||||
def bus_recv_thread(protocol: str, bus_driver: Optional[Any] = None):#2026/3/9 停用
|
||||
"""总线接收线程:接收上行数据,放入接收队列"""
|
||||
logger.info(f"{protocol} 总线接收线程启动")
|
||||
while True:
|
||||
try:
|
||||
# 模拟总线接收(替换为真实驱动的recv接口)
|
||||
# raw_data = bus_driver.recv()
|
||||
raw_data = b"" # 占位
|
||||
|
||||
if raw_data:
|
||||
dev_name = f"{protocol}_DEV"
|
||||
try:
|
||||
bus_recv_queues[protocol].put_nowait({
|
||||
"dev_name": dev_name,
|
||||
"raw_data": raw_data,
|
||||
"protocol": protocol,
|
||||
"recv_time": time.time()
|
||||
})
|
||||
logger.debug(
|
||||
f"总线接收|{protocol}|{dev_name}|"
|
||||
f"队列长度:{bus_recv_queues[protocol].qsize()}"
|
||||
)
|
||||
except queue.Full:
|
||||
logger.warning(f"{protocol} 接收队列已满,丢弃上行数据")
|
||||
time.sleep(1e-6)
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 接收线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
'''
|
||||
|
||||
# ========== 5.5 总线轮询线程(无优先级,保持原有逻辑) ==========
|
||||
def bus_daq_thread(protocol: str, bus_driver_config: Optional[Dict[str, Any]] = None):
|
||||
"""总线接收线程:通过统一驱动接口接收数据"""
|
||||
logger.info(f"{protocol} 总线接收线程启动")
|
||||
|
||||
# 创建驱动实例
|
||||
try:
|
||||
driver = create_bus_driver(protocol, config=bus_driver_config)
|
||||
if not driver.connect():
|
||||
logger.error(f"{protocol} 驱动连接失败,线程退出")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 驱动创建失败:{str(e)},线程退出")
|
||||
return
|
||||
|
||||
time.sleep(0.001)#5->0.5
|
||||
while True:
|
||||
try:
|
||||
##循环发送读取请求
|
||||
# if(protocol=="UART"):
|
||||
# sysbus_cmd = f'uart24 GetTXFIFODataString'
|
||||
# print(sysbus_cmd)
|
||||
# response = renode.send_sync(sysbus_cmd)#2026/4/10
|
||||
time.sleep(0.001)
|
||||
|
||||
##循环发送读取请求
|
||||
if(protocol == "CAN"):#发现protocol == "CAN"时候循环更快
|
||||
sysbus_cmd = f'uart0 GetTXFIFODataString'#uart 0
|
||||
logger.info(f'uart0轮询请求:{sysbus_cmd}')#print(sysbus_cmd)
|
||||
response = renode.send_sync(sysbus_cmd,timeout_ms=5)#2026/4/10
|
||||
# response = renode.enqueue_cmd(sysbus_cmd)#2026/4/10
|
||||
time.sleep(0.001)
|
||||
|
||||
sysbus_cmd = f'uart18 GetTXFIFODataString'#uart 0
|
||||
logger.info(f'uart18 轮询请求:{sysbus_cmd}')#print(sysbus_cmd)
|
||||
response = renode.send_sync(sysbus_cmd,timeout_ms=5)#2026/4/10
|
||||
# response = renode.enqueue_cmd(sysbus_cmd)#2026/4/10
|
||||
time.sleep(0.001)
|
||||
|
||||
|
||||
if(protocol == "CAN"):
|
||||
sysbus_cmd = f'can_a GetTxBufferDataString'#CAN_A
|
||||
#sysbus_cmd = f'uart0 GetTXFIFODataString'#uart 0
|
||||
logger.info(f'can_a轮询请求:{sysbus_cmd}')#print(sysbus_cmd)
|
||||
|
||||
response = renode.send_sync(sysbus_cmd,timeout_ms=5)#2026/4/10
|
||||
#response = renode.enqueue_cmd(sysbus_cmd)#2026/4/10
|
||||
time.sleep(0.25)
|
||||
|
||||
# 调用驱动接收(统一接口)
|
||||
raw_data = driver.recv(timeout=0.001) # 短超时,非阻塞
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 接收线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
driver.disconnect()
|
||||
|
||||
import time
|
||||
'''
|
||||
# ========== 5.5 总线轮询线程(无优先级,保持原有逻辑) ==========
|
||||
def bus_daq_thread(protocol: str, bus_driver_config: Optional[Dict[str, Any]] = None):
|
||||
logger.info(f"{protocol}总线轮询线程启动")
|
||||
# 创建驱动实例
|
||||
try:
|
||||
driver = create_bus_driver(protocol, config=bus_driver_config)
|
||||
if not driver.connect():
|
||||
logger.error(f"{protocol} 驱动连接失败,线程退出")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 驱动创建失败:{str(e)},线程退出")
|
||||
return
|
||||
time.sleep(5)
|
||||
# ==================原来的while循环删除==============#
|
||||
poll_period = 0.25
|
||||
next_run_time = time.perf_counter()
|
||||
while True:
|
||||
try:
|
||||
if protocol == "UART":
|
||||
sysbus_cmd = f'uart0 GetTXFIFODataString'#uart 0
|
||||
logger.info(f'uart0轮询请求:{sysbus_cmd}')#print(sysbus_cmd)
|
||||
response = renode.send_sync(sysbus_cmd,timeout_ms=1)#2026/4/10
|
||||
elif protocol =="CAN":
|
||||
sysbus_cmd = f'can_a GetTxBufferDataString'#CAN_A
|
||||
logger.info(f'can_a轮询请求:{sysbus_cmd}')#print(sysbus_cmd)
|
||||
response = renode.send_sync(sysbus_cmd,timeout_ms=1)#2026/4/10
|
||||
next_run_time = poll_period + next_run_time
|
||||
sleep_time = next_run_time- time.perf_counter()
|
||||
if sleep_time >0:
|
||||
time.sleep(sleep_time)
|
||||
#如果小于0,代表超时,
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 接收线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.01)
|
||||
'''
|
||||
|
||||
|
||||
|
||||
# ========== 6. 总线接收分发线程(无优先级,保持原有逻辑) ==========
|
||||
def bus_recv_dispatch_thread():
|
||||
"""汇总总线接收数据,转发到UDP发送队列"""
|
||||
logger.info("总线接收分发线程启动")
|
||||
while True:
|
||||
try:
|
||||
for protocol, q in bus_recv_queues.items():
|
||||
try:
|
||||
recv_data = q.get_nowait()
|
||||
try:
|
||||
udp_send_queue.put_nowait(recv_data)
|
||||
logger.debug(
|
||||
f"上行数据转发到udp_send_queue|{protocol}|{recv_data['dev_name']}|{recv_data['raw_data'].hex()}"
|
||||
f"UDP队列长度:{udp_send_queue.qsize()}"
|
||||
)
|
||||
except queue.Full:
|
||||
logger.warning(f"UDP发送队列已满,丢弃 {protocol} 上行数据")
|
||||
q.task_done()
|
||||
except queue.Empty:
|
||||
continue
|
||||
time.sleep(1e-6)
|
||||
except Exception as e:
|
||||
logger.error(f"总线接收分发线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
'''
|
||||
# ========== 7. UDP发送线程(无优先级,保持原有逻辑) ==========
|
||||
def udp_send_thread(udp_server): #2026/4/15停用,因为本函数智能输出一个UDP端口
|
||||
"""UDP发送线程:发送上行数据到故障注入平台"""
|
||||
logger.info("UDP发送线程(上行数据)启动")
|
||||
while True:
|
||||
try:
|
||||
send_data = udp_send_queue.get(timeout=1)
|
||||
dev_name = send_data["dev_name"]
|
||||
raw_data = send_data["raw_data"]
|
||||
|
||||
udp_server.send_to_fault(raw_data, dev_name)
|
||||
logger.debug(
|
||||
f"UDP发送|{dev_name}|数据:{raw_data.hex()}|"
|
||||
f"队列剩余:{udp_send_queue.qsize()}"
|
||||
)
|
||||
udp_send_queue.task_done()
|
||||
except queue.Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"UDP发送线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
'''
|
||||
# ========== 7. UDP发送线程(已修改:按设备send_port动态发送) ==========2026/4/15
|
||||
def udp_send_thread(udp_server):
|
||||
"""UDP发送线程:按设备配置的send_port发送到故障注入平台"""
|
||||
logger.info("UDP发送线程(上行数据)启动")
|
||||
|
||||
while True:
|
||||
try:
|
||||
send_data = udp_send_queue.get(timeout=1)
|
||||
dev_name = send_data["dev_name"]
|
||||
raw_data = send_data["raw_data"]
|
||||
protocol = send_data["protocol"]
|
||||
|
||||
# ======================
|
||||
# 🔥 关键:从设备配置获取远端端口 send_port
|
||||
# ======================
|
||||
send_port = 9999 # 默认端口
|
||||
if dev_name in base_config.DEVICE_CONFIG_DICT: ##引用全局变量时候有问题,这里需要修改
|
||||
dev_cfg = base_config.DEVICE_CONFIG_DICT[dev_name]
|
||||
send_port = dev_cfg.get("remote_port", 9999) # 读取CSV里的 remote_port
|
||||
|
||||
# ======================
|
||||
# 🔥 发送到指定远端端口(修改这里)
|
||||
# ======================
|
||||
udp_server.send_to_fault(raw_data, dev_name, send_port)
|
||||
|
||||
logger.info(
|
||||
f"通过UDP向动力学或前端发送|{dev_name}|port:{send_port}|数据:{raw_data.hex()}" #防止刷屏,先注释
|
||||
)
|
||||
udp_send_queue.task_done()
|
||||
|
||||
except queue.Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"UDP发送线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
'''
|
||||
# ========== 8. 线程管理(启动/停止) ==========
|
||||
def start_all_threads(udp_server, bus_drivers: Dict[str, Any] = None):#2026/3/9停用
|
||||
"""启动所有线程(按优先级顺序启动,非必须,仅为日志清晰)"""
|
||||
threads = []
|
||||
bus_drivers = bus_drivers or {}
|
||||
|
||||
# 按优先级从高到低启动总线发送线程(日志更清晰)
|
||||
sorted_protos = sorted(PROTOCOL_PRIORITY.keys(), key=lambda x: PROTOCOL_PRIORITY[x])
|
||||
|
||||
# 1. UDP接收线程
|
||||
udp_recv_t = threading.Thread(target=udp_recv_thread, args=(udp_server,), daemon=True)
|
||||
threads.append(udp_recv_t)
|
||||
|
||||
# 2. 总线发送线程(按优先级排序启动)
|
||||
for protocol in sorted_protos:
|
||||
driver = bus_drivers.get(protocol)
|
||||
send_t = threading.Thread(target=bus_send_thread, args=(protocol, driver), daemon=True)
|
||||
threads.append(send_t)
|
||||
|
||||
# 3. 总线接收线程(按优先级排序启动)
|
||||
for protocol in sorted_protos:
|
||||
driver = bus_drivers.get(protocol)
|
||||
recv_t = threading.Thread(target=bus_recv_thread, args=(protocol, driver), daemon=True)
|
||||
threads.append(recv_t)
|
||||
|
||||
# 4. 总线接收分发线程
|
||||
recv_dispatch_t = threading.Thread(target=bus_recv_dispatch_thread, daemon=True)
|
||||
threads.append(recv_dispatch_t)
|
||||
|
||||
# 5. UDP发送线程
|
||||
udp_send_t = threading.Thread(target=udp_send_thread, args=(udp_server,), daemon=True)
|
||||
threads.append(udp_send_t)
|
||||
|
||||
# 启动所有线程
|
||||
for t in threads:
|
||||
t.start()
|
||||
logger.info(f"线程 {t.name} 启动成功")
|
||||
return threads
|
||||
'''
|
||||
def stop_all_threads():
|
||||
"""优雅停止所有线程"""
|
||||
logger.info("开始停止所有线程,等待队列处理完成...")
|
||||
# 等待发送队列(按优先级从高到低)
|
||||
sorted_protos = sorted(PROTOCOL_PRIORITY.keys(), key=lambda x: PROTOCOL_PRIORITY[x])
|
||||
for protocol in sorted_protos:
|
||||
bus_send_queues[protocol].join()
|
||||
# 等待接收队列
|
||||
for protocol in sorted_protos:
|
||||
bus_recv_queues[protocol].join()
|
||||
# 等待UDP发送队列
|
||||
udp_send_queue.join()
|
||||
logger.info("所有队列处理完成,线程已停止")
|
||||
|
||||
# ========== 扩展函数:动态调整优先级(可选) ==========
|
||||
def update_protocol_priority(protocol: str, new_priority: int):
|
||||
"""
|
||||
动态调整协议优先级(运行时生效)
|
||||
:param protocol: 协议名称(如"1553B")
|
||||
:param new_priority: 新优先级数值(越小越高)
|
||||
"""
|
||||
if protocol in PROTOCOL_PRIORITY:
|
||||
old_priority = PROTOCOL_PRIORITY[protocol]
|
||||
PROTOCOL_PRIORITY[protocol] = new_priority
|
||||
logger.info(f"协议 {protocol} 优先级调整:{old_priority} → {new_priority}")
|
||||
else:
|
||||
logger.warning(f"未知协议 {protocol},无法调整优先级")
|
||||
0
midware/core/data_forward.py
Normal file
0
midware/core/data_forward.py
Normal file
97
midware/core/error_check.py
Normal file
97
midware/core/error_check.py
Normal file
@@ -0,0 +1,97 @@
|
||||
import crcmod
|
||||
from loguru import logger
|
||||
import os
|
||||
|
||||
#初始化校验和算法,适配不同总线协议(通用 CRC16 为主,兼容自定义校验)
|
||||
#预定义各总线校验算法,可根据需求扩展
|
||||
#CRC16_UART = crcmod.predefined.Crc('crc16_modbus')
|
||||
CRC16_UART = crcmod.predefined.Crc('crc16')
|
||||
#CRC16_CAN = crcmod.predefined.Crc('crc16/ccitt')
|
||||
CRC16_CAN = crcmod.predefined.Crc('crc16')
|
||||
#CRC16_1553B = crcmod.predefined.Crc('crc16_x25')
|
||||
CRC16_1553B = crcmod.predefined.Crc('crc16')
|
||||
|
||||
|
||||
#确保日志目录存在
|
||||
if not os.path.exists("logs"):os.makedirs("logs")
|
||||
def _calculate_checksum (data: bytes, protocol: str) -> bytes:
|
||||
"""私有方法:根据协议类型计算校验和
|
||||
:param data: 原始二进制数据
|
||||
:param protocol: 总线协议(UART/CAN/1553B/AD/OC)
|
||||
:return: 校验和字节流(2 字节,大端)
|
||||
"""
|
||||
if not isinstance (data, bytes) or len (data) == 0:
|
||||
return b'\x00\x00'
|
||||
crc = None
|
||||
if protocol == "UART":
|
||||
crc = CRC16_UART
|
||||
elif protocol == "CAN":
|
||||
crc = CRC16_CAN
|
||||
elif protocol == "1553B":
|
||||
crc = CRC16_1553B
|
||||
elif protocol in ["AD", "OC"]:
|
||||
#AD/OC 采用简单累加和校验(低字节),适配星务平台常用规则
|
||||
sum_val = sum(byte for byte in data) & 0xFF
|
||||
return bytes([sum_val])
|
||||
else:
|
||||
#未知协议默认使用 CRC16_MODBUS
|
||||
crc = CRC16_UART
|
||||
#重置 CRC 计算器并计算
|
||||
#crc.reset()
|
||||
crc.update(data)
|
||||
|
||||
#返回 2 字节大端校验和
|
||||
return crc.crcValue.to_bytes(2, byteorder='big')
|
||||
|
||||
def check_checksum (data: bytes, protocol: str, device_name: str) -> bool:
|
||||
"""核心校验和检测逻辑:分离数据与校验位,对比计算值与传入值规则:数据末尾携带校验位,不同协议校验位长度不同(UART/CAN/1553B 为 2 字节,AD/OC 为 1 字节)
|
||||
:param data: 包含校验位的原始二进制数据
|
||||
:param protocol: 总线协议(UART/CAN/1553B/AD/OC)
|
||||
:param device_name: 外设名称(用于日志定位)
|
||||
:return: 校验通过返回 True,失败返回 False 并记录错误日志
|
||||
"""
|
||||
#基础参数校验
|
||||
if not isinstance (data, bytes) or len (data) == 0:
|
||||
logger.error (f"【{device_name}-{protocol}】校验和检测失败:输入数据为空或非二进制格式")
|
||||
return False
|
||||
if protocol not in ["UART", "CAN", "1553B", "AD", "OC"]:
|
||||
logger.error (f"【{device_name}-{protocol}】校验和检测失败:不支持的协议类型")
|
||||
return False
|
||||
#定义各协议校验位长度
|
||||
checksum_len = 2 if protocol in ["UART", "CAN", "1553B"] else 1
|
||||
#数据长度需大于校验位长度,否则无效
|
||||
if len (data) <= checksum_len:
|
||||
logger.error (f"【{device_name}-{protocol}】校验和检测失败:数据长度 {len (data)} 字节,小于校验位长度 {checksum_len} 字节")
|
||||
return False
|
||||
#分离原始数据和携带的校验位
|
||||
raw_data = data[:-checksum_len]
|
||||
received_checksum = data[-checksum_len:]
|
||||
#计算原始数据的校验和
|
||||
calculated_checksum = _calculate_checksum(raw_data, protocol)
|
||||
#对比校验和
|
||||
if received_checksum == calculated_checksum:
|
||||
logger.debug (f"【{device_name}-{protocol}】校验和检测通过:接收校验位 {received_checksum.hex ()},计算校验位 {calculated_checksum.hex ()}")
|
||||
return True
|
||||
else:
|
||||
#校验失败,记录详细错误日志(含设备、协议、数据、校验位对比)
|
||||
error_msg = (f"【{device_name}-{protocol}】校验和检测失败 |"f"原始数据长度:{len (raw_data)} 字节 |"f"接收校验位:{received_checksum.hex ()} |"f"计算校验位:{calculated_checksum.hex ()} |"f"原始数据(前 16 字节):{raw_data [:16].hex () if len (raw_data)>=16 else raw_data.hex ()}")
|
||||
logger.error (error_msg)
|
||||
return False
|
||||
|
||||
def verify_frame_integrity (data: bytes, protocol: str, device_name: str) -> bool:
|
||||
"""扩展方法:帧完整性检测(可选),结合校验和 + 协议帧长度规则用于 CAN(单帧≤11 字节)、1553B 等有帧长限制的协议
|
||||
:param data: 包含校验位的原始二进制数据
|
||||
:return: 完整性通过返回 True,否则 False"""
|
||||
#先执行校验和检测
|
||||
if not check_checksum(data, protocol, device_name):
|
||||
return False
|
||||
#各协议帧长度规则校验
|
||||
frame_rules = {"CAN": lambda d: len (d) - 2 <= 11, # CAN 单帧≤11 字节(扣除 2 字节校验位)"1553B": lambda d: len (d) % 2 == 0, # 1553B 数据为 2 字节整数倍(军用总线规范)"UART": lambda d: True, # UART 不定长,无帧长限制"AD": lambda d: True, # AD 无帧长限制"OC": lambda d: True # OC 无帧长限制
|
||||
}
|
||||
if protocol in frame_rules:
|
||||
if not frame_rulesprotocol:
|
||||
error_msg = f"【{device_name}-{protocol}】帧完整性检测失败:数据长度不符合协议规范,数据总长度 {len (data)} 字节"
|
||||
logger.error (error_msg)
|
||||
return False
|
||||
logger.debug (f"【{device_name}-{protocol}】帧完整性检测通过")
|
||||
return True
|
||||
Binary file not shown.
203
midware/core/history/bus_udp_decoupler_20260306.py
Normal file
203
midware/core/history/bus_udp_decoupler_20260306.py
Normal file
@@ -0,0 +1,203 @@
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Tan Mingyan 2026/3/6
|
||||
|
||||
四、关键设计亮点(解耦 + 队列的核心价值)
|
||||
彻底解耦:
|
||||
UDP 收发 ≠ 总线处理:UDP 线程只做「数据搬运」,总线线程只做「业务处理」,修改总线逻辑无需改动 UDP 代码;
|
||||
异常隔离:某一线程(如 CAN 处理)崩溃,不影响 UDP 收发和其他总线线程运行。
|
||||
队列缓冲区的核心作用:
|
||||
削峰填谷:UDP 突发大量数据时,队列暂存,总线线程按能力消费,避免数据丢失;
|
||||
异步通信:线程间通过队列通信,无直接调用,消除阻塞依赖;
|
||||
可监控:通过 qsize() 监控队列长度,及时发现「生产 > 消费」的瓶颈(如队列持续满则需优化总线处理速度)。
|
||||
工业级容错:
|
||||
队列满时丢弃数据 + 告警,避免内存溢出;
|
||||
线程异常时休眠重试,避免 CPU 100%;
|
||||
守护线程(daemon=True):主线程退出时自动终止子线程,避免僵尸线程;
|
||||
优雅退出:join() 等待队列处理完成,避免强制退出导致数据丢失。
|
||||
五、扩展建议(根据业务需求调整)
|
||||
队列持久化:若需断电不丢数据,可将队列数据写入本地文件 / Redis;
|
||||
优先级队列:对关键设备(如 1553B)使用 queue.PriorityQueue,优先处理高优先级数据;
|
||||
流量控制:监控队列长度,超过阈值时暂停 UDP 接收(或降低接收频率);
|
||||
线程池优化:若总线协议过多,改用 concurrent.futures.ThreadPoolExecutor 管理线程,避免线程数量过多。
|
||||
"""
|
||||
"""
|
||||
总线-UDP解耦核心模块:队列+多线程
|
||||
"""
|
||||
import threading
|
||||
import queue
|
||||
import time
|
||||
from loguru import logger
|
||||
from typing import Dict, Any, List
|
||||
|
||||
# ========== 1. 全局队列定义(按协议分类) ==========
|
||||
# 队列最大长度:避免内存溢出,根据业务调整(如1000)
|
||||
MAX_QUEUE_SIZE = 1000
|
||||
|
||||
# 协议分发队列(UDP接收→协议分流)
|
||||
protocol_dispatch_queue = queue.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
|
||||
# 各总线处理队列
|
||||
bus_queues = {
|
||||
"UART": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"CAN": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"1553B": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"AD": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"OC": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"网络": queue.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
}
|
||||
|
||||
# UDP发送队列(总线回传→UDP发送)
|
||||
udp_send_queue = queue.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
|
||||
# ========== 2. UDP接收线程(仅负责收数据,不处理) ==========
|
||||
def udp_receive_thread(udp_server):
|
||||
"""UDP接收线程:独立运行,仅收数据放入分发队列"""
|
||||
logger.info("UDP接收线程启动")
|
||||
while True:
|
||||
try:
|
||||
recv_data = udp_server.recv_multi_udp_hex()
|
||||
if recv_data:
|
||||
for data in recv_data:
|
||||
# 非阻塞放入队列,避免线程阻塞
|
||||
try:
|
||||
protocol_dispatch_queue.put_nowait(data)
|
||||
logger.debug(f"UDP接收:{data['dev_name']} 数据放入分发队列,队列当前长度:{protocol_dispatch_queue.qsize()}")
|
||||
except queue.Full:
|
||||
logger.warning(f"协议分发队列已满,丢弃 {data['dev_name']} 数据")
|
||||
time.sleep(1e-6)
|
||||
except Exception as e:
|
||||
logger.error(f"UDP接收线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1) # 异常时休眠,避免CPU飙高
|
||||
|
||||
# ========== 3. 协议分发线程(仅负责分流,不处理业务) ==========
|
||||
def protocol_dispatch_thread():
|
||||
"""协议分发线程:从分发队列取数据,按protocol分流到对应总线队列"""
|
||||
logger.info("协议分发线程启动")
|
||||
while True:
|
||||
try:
|
||||
# 阻塞取数据(队列为空时等待,无CPU消耗)
|
||||
data = protocol_dispatch_queue.get(timeout=1)
|
||||
protocol = data.get("protocol", "").strip().upper()
|
||||
|
||||
# 分流到对应总线队列
|
||||
if protocol in bus_queues:
|
||||
try:
|
||||
bus_queues[protocol].put_nowait(data)
|
||||
logger.debug(f"分发:{data['dev_name']} 数据到 {protocol} 队列,队列长度:{bus_queues[protocol].qsize()}")
|
||||
except queue.Full:
|
||||
logger.warning(f"{protocol} 队列已满,丢弃 {data['dev_name']} 数据")
|
||||
else:
|
||||
logger.warning(f"未知协议 {protocol},丢弃 {data['dev_name']} 数据")
|
||||
|
||||
# 标记任务完成(队列join时需要)
|
||||
protocol_dispatch_queue.task_done()
|
||||
except queue.Empty:
|
||||
continue # 队列为空,继续循环
|
||||
except Exception as e:
|
||||
logger.error(f"协议分发线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
# ========== 4. 总线处理线程(以UART为例,其他协议同理) ==========
|
||||
def bus_process_thread(protocol: str, udp_server):
|
||||
"""通用总线处理线程:从对应队列取数据,处理后放入UDP发送队列"""
|
||||
logger.info(f"{protocol} 总线处理线程启动")
|
||||
while True:
|
||||
try:
|
||||
# 阻塞取数据
|
||||
data = bus_queues[protocol].get(timeout=1)
|
||||
dev_name = data["dev_name"]
|
||||
raw_data = data["raw_data"]
|
||||
|
||||
# ========== 核心:总线业务处理(解耦后仅在此处修改) ==========
|
||||
logger.info(f"{protocol} 处理:{dev_name} 原始数据:{raw_data.hex()}")
|
||||
# 1. 总线数据解析(如UART波特率解析、CAN帧解析等)
|
||||
processed_data = raw_data # 示例:实际需替换为业务逻辑
|
||||
# 2. 总线数据发送(如写入UART串口、发送CAN帧等)
|
||||
# bus_driver.send(protocol, processed_data) # 总线驱动调用
|
||||
|
||||
# ========== 处理完成后,回传数据到UDP发送队列 ==========
|
||||
try:
|
||||
udp_send_queue.put_nowait({
|
||||
"dev_name": dev_name,
|
||||
"data": processed_data,
|
||||
"protocol": protocol
|
||||
})
|
||||
logger.debug(f"{protocol} 处理完成,{dev_name} 回传数据放入UDP发送队列")
|
||||
except queue.Full:
|
||||
logger.warning(f"UDP发送队列已满,丢弃 {dev_name} 回传数据")
|
||||
|
||||
# 标记任务完成
|
||||
bus_queues[protocol].task_done()
|
||||
except queue.Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 总线线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
# ========== 5. UDP发送线程(仅负责发数据,不处理) ==========
|
||||
def udp_send_thread(udp_server):
|
||||
"""UDP发送线程:从发送队列取数据,发送到故障注入平台"""
|
||||
logger.info("UDP发送线程启动")
|
||||
while True:
|
||||
try:
|
||||
# 阻塞取数据
|
||||
send_data = udp_send_queue.get(timeout=1)
|
||||
dev_name = send_data["dev_name"]
|
||||
data = send_data["data"]
|
||||
|
||||
# 调用UDP服务发送
|
||||
udp_server.send_to_fault(data, dev_name)
|
||||
logger.debug(f"UDP发送:{dev_name} 数据到故障注入平台,队列剩余:{udp_send_queue.qsize()}")
|
||||
|
||||
# 标记任务完成
|
||||
udp_send_queue.task_done()
|
||||
except queue.Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"UDP发送线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
# ========== 6. 线程启动/停止管理(集成到main.py) ==========
|
||||
'''
|
||||
def start_all_threads(udp_server):
|
||||
"""启动所有解耦线程"""
|
||||
threads = []
|
||||
|
||||
# 1. UDP接收线程
|
||||
udp_recv_t = threading.Thread(target=udp_receive_thread, args=(udp_server,), daemon=True)
|
||||
threads.append(udp_recv_t)
|
||||
|
||||
# 2. 协议分发线程
|
||||
dispatch_t = threading.Thread(target=protocol_dispatch_thread, daemon=True)
|
||||
threads.append(dispatch_t)
|
||||
|
||||
# 3. 各总线处理线程
|
||||
for protocol in bus_queues.keys():
|
||||
bus_t = threading.Thread(target=bus_process_thread, args=(protocol, udp_server), daemon=True)
|
||||
threads.append(bus_t)
|
||||
|
||||
# 4. UDP发送线程
|
||||
udp_send_t = threading.Thread(target=udp_send_thread, args=(udp_server,), daemon=True)
|
||||
threads.append(udp_send_t)
|
||||
|
||||
# 启动所有线程
|
||||
for t in threads:
|
||||
t.start()
|
||||
logger.info(f"线程 {t.name} 启动成功")
|
||||
|
||||
return threads
|
||||
|
||||
def stop_all_threads():
|
||||
"""优雅停止所有线程(等待队列处理完成)"""
|
||||
logger.info("开始停止所有线程,等待队列处理完成...")
|
||||
|
||||
# 等待队列所有任务完成
|
||||
protocol_dispatch_queue.join()
|
||||
for q in bus_queues.values():
|
||||
q.join()
|
||||
udp_send_queue.join()
|
||||
|
||||
logger.info("所有队列处理完成,线程已停止")
|
||||
'''
|
||||
234
midware/core/history/bus_udp_decoupler_20260307.py
Normal file
234
midware/core/history/bus_udp_decoupler_20260307.py
Normal file
@@ -0,0 +1,234 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Tan Mingyan 2026/3/7
|
||||
"""
|
||||
"""
|
||||
总线-UDP双向通信解耦模块(加入收发缓冲区分离)
|
||||
"""
|
||||
import threading
|
||||
import queue
|
||||
import time
|
||||
from loguru import logger
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
# ========== 1. 收发队列分离:为每个协议定义独立的收/发队列 ==========
|
||||
MAX_QUEUE_SIZE = 1000 # 可按协议单独调整(如1553B设2000,UART设500)
|
||||
|
||||
# 总线接收队列(总线→中间件:上行数据)
|
||||
bus_recv_queues = {
|
||||
"UART": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"CAN": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"1553B": queue.Queue(maxsize=2000), # 1553B数据量大,单独调整
|
||||
"AD": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"OC": queue.Queue(maxsize=MAX_QUEUE_SIZE),
|
||||
"网络": queue.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
}
|
||||
|
||||
# 总线发送队列(中间件→总线:下行数据)
|
||||
bus_send_queues = {
|
||||
"UART": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE), # 发送队列支持优先级
|
||||
"CAN": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE),
|
||||
"1553B": queue.PriorityQueue(maxsize=2000),
|
||||
"AD": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE),
|
||||
"OC": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE),
|
||||
"网络": queue.PriorityQueue(maxsize=MAX_QUEUE_SIZE)
|
||||
}
|
||||
|
||||
# UDP发送队列(中间件→UDP:上行数据,总线接收后转发)
|
||||
udp_send_queue = queue.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
# UDP接收队列(UDP→中间件:下行数据,转发到总线发送队列)
|
||||
udp_recv_dispatch_queue = queue.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
|
||||
# ========== 2. UDP接收线程:仅处理下行指令(转发到总线发送队列) ==========
|
||||
def udp_recv_thread(udp_server):
|
||||
"""UDP接收线程:接收故障注入平台的下行指令,分发到总线发送队列"""
|
||||
logger.info("UDP接收线程(下行指令)启动")
|
||||
while True:
|
||||
try:
|
||||
recv_data = udp_server.recv_multi_udp_hex()
|
||||
if recv_data:
|
||||
for data in recv_data:
|
||||
protocol = data.get("protocol", "").strip().upper()
|
||||
dev_name = data.get("dev_name", "")
|
||||
raw_data = data.get("raw_data", b"")
|
||||
priority = data.get("priority", 5) # 默认优先级5(1最高,10最低)
|
||||
|
||||
if protocol not in bus_send_queues:
|
||||
logger.warning(f"未知协议 {protocol},丢弃下行指令:{dev_name}")
|
||||
continue
|
||||
|
||||
# 放入总线发送队列(带优先级)
|
||||
try:
|
||||
# PriorityQueue格式:(优先级, 数据)
|
||||
bus_send_queues[protocol].put_nowait((priority, {
|
||||
"dev_name": dev_name,
|
||||
"raw_data": raw_data,
|
||||
"protocol": protocol
|
||||
}))
|
||||
logger.debug(f"下行指令:{dev_name} ({protocol}) 放入发送队列,优先级:{priority}")
|
||||
except queue.Full:
|
||||
logger.warning(f"{protocol} 发送队列已满,丢弃 {dev_name} 下行指令")
|
||||
time.sleep(1e-6)
|
||||
except Exception as e:
|
||||
logger.error(f"UDP接收线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
# ========== 3. 总线发送线程:处理下行指令(中间件→总线) ==========
|
||||
def bus_send_thread(protocol: str, bus_driver: Optional[Any] = None):
|
||||
"""总线发送线程:从发送队列取下行指令,发送到总线"""
|
||||
logger.info(f"{protocol} 总线发送线程启动")
|
||||
while True:
|
||||
try:
|
||||
# PriorityQueue阻塞取数据(优先级高的先取)
|
||||
priority, send_data = bus_send_queues[protocol].get(timeout=1)
|
||||
dev_name = send_data["dev_name"]
|
||||
raw_data = send_data["raw_data"]
|
||||
|
||||
# 总线发送逻辑(适配双向通信:调用总线驱动发送指令)
|
||||
logger.info(f"{protocol} 发送:{dev_name} | 优先级:{priority} | 数据:{raw_data.hex()}")
|
||||
# 实际业务:调用总线驱动发送(如CAN发送帧、UART写串口)
|
||||
# if bus_driver:
|
||||
# bus_driver.send(raw_data)
|
||||
|
||||
# 标记任务完成
|
||||
bus_send_queues[protocol].task_done()
|
||||
|
||||
# 在bus_send_thread中添加超时检查
|
||||
if time.time() - send_data.get("send_time", 0) > 5: # 5秒超时
|
||||
logger.error(f"{protocol} 发送超时:{dev_name}")
|
||||
bus_send_queues[protocol].task_done()
|
||||
continue
|
||||
except queue.Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 发送线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
# ========== 4. 总线接收线程:处理上行数据(总线→中间件) ==========
|
||||
def bus_recv_thread(protocol: str, bus_driver: Optional[Any] = None):
|
||||
"""总线接收线程:从总线接收上行数据,放入接收队列"""
|
||||
logger.info(f"{protocol} 总线接收线程启动")
|
||||
while True:
|
||||
try:
|
||||
# 模拟总线接收(实际需替换为总线驱动的接收接口)
|
||||
# raw_data = bus_driver.recv() # 从总线读取上行数据
|
||||
# 此处为示例,实际需对接真实总线驱动
|
||||
raw_data = b"" # 占位:替换为总线接收逻辑
|
||||
|
||||
if raw_data:
|
||||
dev_name = f"{protocol}_DEV" # 实际从总线数据解析设备名
|
||||
# 放入总线接收队列
|
||||
try:
|
||||
bus_recv_queues[protocol].put_nowait({
|
||||
"dev_name": dev_name,
|
||||
"raw_data": raw_data,
|
||||
"protocol": protocol,
|
||||
"recv_time": time.time() # 记录接收时间,便于时序分析
|
||||
})
|
||||
logger.debug(f"{protocol} 接收:{dev_name} 上行数据,队列长度:{bus_recv_queues[protocol].qsize()}")
|
||||
except queue.Full:
|
||||
logger.warning(f"{protocol} 接收队列已满,丢弃上行数据")
|
||||
time.sleep(1e-6) # 匹配总线接收速率
|
||||
except Exception as e:
|
||||
logger.error(f"{protocol} 接收线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
# ========== 5. 总线接收分发线程:汇总上行数据→UDP发送 ==========
|
||||
def bus_recv_dispatch_thread():
|
||||
"""总线接收分发线程:汇总各协议接收队列数据,转发到UDP发送队列"""
|
||||
logger.info("总线接收分发线程启动")
|
||||
while True:
|
||||
try:
|
||||
# 遍历所有总线接收队列,非阻塞取数据(避免单队列阻塞)
|
||||
for protocol, q in bus_recv_queues.items():
|
||||
try:
|
||||
recv_data = q.get_nowait()
|
||||
# 转发到UDP发送队列(发送到故障注入平台)
|
||||
try:
|
||||
udp_send_queue.put_nowait(recv_data)
|
||||
logger.debug(f"{protocol} 上行数据:{recv_data['dev_name']} 转发到UDP发送队列")
|
||||
except queue.Full:
|
||||
logger.warning(f"UDP发送队列已满,丢弃 {protocol} 上行数据")
|
||||
q.task_done()
|
||||
except queue.Empty:
|
||||
continue
|
||||
time.sleep(1e-6)
|
||||
except Exception as e:
|
||||
logger.error(f"总线接收分发线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
# ========== 6. UDP发送线程:处理上行数据(中间件→UDP) ==========
|
||||
def udp_send_thread(udp_server):
|
||||
"""UDP发送线程:从UDP发送队列取上行数据,发送到故障注入平台"""
|
||||
logger.info("UDP发送线程(上行数据)启动")
|
||||
while True:
|
||||
try:
|
||||
send_data = udp_send_queue.get(timeout=1)
|
||||
dev_name = send_data["dev_name"]
|
||||
raw_data = send_data["raw_data"]
|
||||
|
||||
# 调用UDP服务发送到故障注入平台
|
||||
udp_server.send_to_fault(raw_data, dev_name)
|
||||
logger.debug(f"UDP发送:{dev_name} 上行数据,队列剩余:{udp_send_queue.qsize()}")
|
||||
udp_send_queue.task_done()
|
||||
except queue.Empty:
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"UDP发送线程异常:{str(e)}", exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
'''
|
||||
# ========== 7. 线程管理:启动/停止所有收发线程 ==========
|
||||
def start_all_threads(udp_server, bus_drivers: Dict[str, Any] = None):
|
||||
"""
|
||||
启动所有双向通信线程
|
||||
:param udp_server: UDP服务实例
|
||||
:param bus_drivers: 总线驱动字典,格式:{"UART": uart_driver, "CAN": can_driver, ...}
|
||||
"""
|
||||
threads = []
|
||||
bus_drivers = bus_drivers or {} # 无驱动时传空字典
|
||||
|
||||
# 1. UDP接收线程(下行指令)
|
||||
udp_recv_t = threading.Thread(target=udp_recv_thread, args=(udp_server,), daemon=True)
|
||||
threads.append(udp_recv_t)
|
||||
|
||||
# 2. 总线发送线程(每个协议一个)
|
||||
for protocol in bus_send_queues.keys():
|
||||
driver = bus_drivers.get(protocol)
|
||||
send_t = threading.Thread(target=bus_send_thread, args=(protocol, driver), daemon=True)
|
||||
threads.append(send_t)
|
||||
|
||||
# 3. 总线接收线程(每个协议一个)
|
||||
for protocol in bus_recv_queues.keys():
|
||||
driver = bus_drivers.get(protocol)
|
||||
recv_t = threading.Thread(target=bus_recv_thread, args=(protocol, driver), daemon=True)
|
||||
threads.append(recv_t)
|
||||
|
||||
# 4. 总线接收分发线程
|
||||
recv_dispatch_t = threading.Thread(target=bus_recv_dispatch_thread, daemon=True)
|
||||
threads.append(recv_dispatch_t)
|
||||
|
||||
# 5. UDP发送线程(上行数据)
|
||||
udp_send_t = threading.Thread(target=udp_send_thread, args=(udp_server,), daemon=True)
|
||||
threads.append(udp_send_t)
|
||||
|
||||
# 启动所有线程
|
||||
for t in threads:
|
||||
t.start()
|
||||
logger.info(f"线程 {t.name} 启动成功")
|
||||
return threads
|
||||
|
||||
def stop_all_threads():
|
||||
"""优雅停止所有线程,等待队列处理完成"""
|
||||
logger.info("开始停止所有线程,等待队列处理完成...")
|
||||
# 等待发送队列处理完成
|
||||
for q in bus_send_queues.values():
|
||||
q.join()
|
||||
# 等待接收队列处理完成
|
||||
for q in bus_recv_queues.values():
|
||||
q.join()
|
||||
# 等待UDP发送队列处理完成
|
||||
udp_send_queue.join()
|
||||
logger.info("所有队列处理完成,线程已停止")
|
||||
|
||||
'''
|
||||
Reference in New Issue
Block a user