first commit

This commit is contained in:
2026-06-16 15:40:19 +08:00
commit 8ba6324244
97 changed files with 6216 additions and 0 deletions

23
midware/core/__init__.py Normal file
View 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"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

View File

View 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__} 自动断开连接")

View File

View File

View File

View 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},无法调整优先级")

View File

View 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

View 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("所有队列处理完成,线程已停止")
'''

View 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设2000UART设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) # 默认优先级51最高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("所有队列处理完成,线程已停止")
'''