import os from loguru import logger import threading from midware.config.excel_config import load_csv_config ''' 3. 基础配置模块(midware/config/base_config.py) 定义全局配置常量,初始化外设、UDP、总线基础参数,预留配置动态加载接口: ''' # 基础配置 - UDP(故障注入软件交互) UDP_CONFIG = { "LOCAL_IP": "10.20.48.138", # 本地UDP地址,用于回环测试,自测时候是"127.0.0.1",科学所是"192.168.0.150"","10.20.48.138" "LOCAL_PORT": 8888, # 本地UDP端口 "FAULT_INJECT_IP": "10.20.48.129",# 故障注入软件IP,用于回环测试,自测时候是"127.0.0.1",科学所是"192.168.0.130"","10.20.48.129" "FAULT_INJECT_PORT": 18889, # 故障注入软件端口 "BUFFER_SIZE": 4096 # UDP缓冲区大小 } # 基础配置 - 外设总线(支持UART/CAN/1553B/AD/OC) BUS_CONFIG = { "SUPPORT_BUS": ["UART", "CAN", "1553B", "AD", "OC"], "MAX_DEVICE_NUM": 10, # 最大支持10个单机 "WRITE_BYTE_UART": 2, # UART每次写入2字节 "WRITE_BYTE_CAN": 2, # CAN每次写入2字节 "READ_BYTE_CAN": 1, # CAN每次读取1字节 "WRITE_BYTE_1553B": 2, # 1553B每次写入2字节 "WRITE_BYTE_AD": 2, # AD每次写入2字节 "READ_BYTE_OC": 1 # OC每次读取1字节 } # 基础配置 - UART芯片寄存器(初始写死,后续由chip_config.ini加载) UART_CHIP_CONFIG = { "TBR": 0x00, # 发送FIFO "FIFO_STATUS": 0x04, # FIFO状态寄存器 "FRAME_COUNT": 0x08, # 帧计数 "FIFO_REMAIN": 0x0C, # FIFO剩余字节数 "CLOCK_CONFIG": 0x10, # 时钟配置 "SCRAMBLE": 0x14, # 加解扰使能 "RESET": 0x7C # 复位 } # 全局外设配置字典,存储已启用的外设信息 # ==================== 全局配置(唯一数据源,仅在此文件定义)==================== # 初始化为空字典,由init_base_config()初始化 DEVICE_CONFIG_DICT = {} #{1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 8: {}, 9: {}, 10: {}} # 配置读写锁(保证多线程安全,防止读写冲突) CONFIG_LOCK = threading.RLock() # ==================== 日志初始化(工程全局)==================== def init_logger(): os.makedirs("logs", exist_ok=True) # 运行日志+错误日志分离 logger.add("logs/run_{time:YYYYMMDDHHmmss}.log", level="INFO", format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}") logger.add("logs/error_{time:YYYYMMDDHHmmss}.log", level="ERROR", format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {file}:{line} | {message}") # 工程启动时自动初始化日志 init_logger() ''' # 加载xlsx文件 def init_base_config(): """初始化基础配置,加载默认外设配置""" try: # 加载默认Excel配置(后续实现) from midware.config.excel_config import load_excel_config default_excel = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "config_files/device_config.xlsx") if os.path.exists(default_excel): DEVICE_CONFIG_DICT = load_excel_config(default_excel) logger.info(f"加载默认Excel配置,共{len(DEVICE_CONFIG_DICT)}个外设") else: logger.warning(f"默认配置文件不存在:{default_excel},使用空配置") logger.info("基础配置初始化完成") except Exception as e: logger.error(f"基础配置初始化失败:{str(e)}", exc_info=True) raise e ''' ''' # midware/config/base_config.py 中init_base_config函数 def init_base_config(): """初始化基础配置,加载默认外设配置""" global DEVICE_CONFIG_DICT try: # 替换为CSV加载方法 #from midware.config.excel_config import load_csv_config default_csv = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "config_files/device_config.csv") if os.path.exists(default_csv): #global DEVICE_CONFIG_DICT DEVICE_CONFIG_DICT = load_csv_config(default_csv) logger.info(f"加载默认CSV配置,共{len(DEVICE_CONFIG_DICT)}个外设") else: logger.warning(f"默认配置文件不存在:{default_csv},使用空配置") DEVICE_CONFIG_DICT = {} logger.info("基础配置初始化完成") except Exception as e: logger.error(f"基础配置初始化失败:{str(e)}", exc_info=True) DEVICE_CONFIG_DICT = {} #raise e #注释掉这行,避免程序崩溃 def update_device_config(new_config: dict): """ 对外提供配置更新方法(如UI勾选外设、导入新配置时调用) :param new_config: 新的外设配置字典,格式与DEVICE_CONFIG_DICT一致 """ global DEVICE_CONFIG_DICT if isinstance(new_config, dict): DEVICE_CONFIG_DICT = new_config logger.info(f"外设配置已更新,当前共{len(DEVICE_CONFIG_DICT)}个外设") # 配置更新后,自动触发UDP套接字重新加载(关键:保证UDP端口与配置同步) from midware.network.udp_handler import udp_server udp_server.reload_sockets() else: logger.error("配置更新失败:新配置非字典类型") # 工程启动时自动初始化日志 #init_logger() ''' # ==================== 配置核心方法(对外暴露,唯一入口)==================== def init_base_config(csv_path: str = None): """ 初始化外设配置:工程启动时**唯一调用**,加载CSV配置到DEVICE_CONFIG_DICT :param csv_path: 配置文件路径,默认取工程根目录config_files/device_config.csv """ global DEVICE_CONFIG_DICT # 声明修改全局变量 if csv_path is None: # 自动拼接工程根目录的配置文件路径 csv_path = os.path.join( os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "config_files/device_config.csv" ) # 加锁保证初始化原子性,防止多线程同时修改 with CONFIG_LOCK: try: if os.path.exists(csv_path): # 加载CSV配置并覆盖全局变量 DEVICE_CONFIG_DICT = load_csv_config(csv_path) logger.info(f"配置初始化成功|加载{len(DEVICE_CONFIG_DICT)}个外设|配置文件:{csv_path}") else: DEVICE_CONFIG_DICT = {} logger.error(f"配置初始化失败|配置文件不存在:{csv_path}") except Exception as e: DEVICE_CONFIG_DICT = {} logger.error(f"配置初始化异常|{str(e)}", exc_info=True) return DEVICE_CONFIG_DICT def update_device_config(new_config: dict): """ 唯一配置更新入口:修改配置后自动同步UDP端口 【关键】延迟导入udp_server,避免模块顶层循环导入 """ global DEVICE_CONFIG_DICT with CONFIG_LOCK: if not isinstance(new_config, dict): logger.error("配置更新失败|新配置非字典类型") return False # 覆盖全局配置 DEVICE_CONFIG_DICT = new_config.copy() # 深拷贝,防止外部修改源字典 logger.info(f"配置更新成功|当前外设数量:{len(DEVICE_CONFIG_DICT)}") # 延迟导入:仅在函数内导入,避免模块加载时循环依赖 try: from midware.network.udp_handler import udp_server udp_server.reload_sockets(new_config) # 传参同步配置,不依赖全局引用 except ImportError as e: logger.warning(f"UDP配置同步失败|未找到UDP模块:{str(e)}") return True def get_device_config(): """ 全局配置**只读接口**:所有其他模块必须通过此方法获取配置 返回副本,防止外部修改原全局变量导致数据混乱 """ with CONFIG_LOCK: return DEVICE_CONFIG_DICT.copy() # 返回深拷贝,彻底隔离原变量 def get_udp_config(): """UDP基础配置只读接口""" return UDP_CONFIG.copy()