diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e5eccc8..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "files.associations": { - "user_math.h": "c", - "bsp.h": "c", - "stdint.h": "c", - "array": "c", - "string": "c", - "string_view": "c", - "vector": "c", - "can.h": "c", - "device.h": "c", - "gpio.h": "c", - "uart.h": "c", - "motor_rm.h": "c", - "mm.h": "c", - "capacity.h": "c", - "error_detect.h": "c", - "bmi088.h": "c", - "time.h": "c", - "motor.h": "c" - } -} \ No newline at end of file diff --git a/MRobot.iss b/MRobot.iss index 8268548..70482d5 100644 --- a/MRobot.iss +++ b/MRobot.iss @@ -11,8 +11,6 @@ OutputBaseFilename=MRobotInstaller Source: "dist\MRobot\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs ; 复制 assets 资源文件到安装目录(支持后续更新) Source: "assets\logo\*"; DestDir: "{app}\assets\logo"; Flags: ignoreversion recursesubdirs -Source: "assets\User_code\*"; DestDir: "{app}\assets\User_code"; Flags: ignoreversion recursesubdirs -Source: "assets\mech_lib\*"; DestDir: "{app}\assets\mech_lib"; Flags: ignoreversion recursesubdirs [Icons] Name: "{group}\MRobot"; Filename: "{app}\MRobot.exe"; IconFilename: "{app}\assets\logo\M.ico" diff --git a/README.md b/README.md index cad5bcb..9d2722c 100644 --- a/README.md +++ b/README.md @@ -86,5 +86,5 @@ 使用以下命令构建可执行文件: ```bash -pyinstaller MRobot.py --onefile --windowed --add-data "assets;assets" --add-data "app;app" --add-data "app/tools;app/tools" +pyinstaller MRobot.py --onefile --windowed --add-data "assets/logo;assets/logo" --add-data "app;app" --add-data "app/tools;app/tools" ``` \ No newline at end of file diff --git a/app/__pycache__/about_interface.cpython-39.pyc b/app/__pycache__/about_interface.cpython-39.pyc index 12e5049..2791c9f 100644 Binary files a/app/__pycache__/about_interface.cpython-39.pyc and b/app/__pycache__/about_interface.cpython-39.pyc differ diff --git a/app/__pycache__/batch_export_dialog.cpython-39.pyc b/app/__pycache__/batch_export_dialog.cpython-39.pyc index 04dfbb6..8eb294b 100644 Binary files a/app/__pycache__/batch_export_dialog.cpython-39.pyc and b/app/__pycache__/batch_export_dialog.cpython-39.pyc differ diff --git a/app/__pycache__/category_management_dialog.cpython-39.pyc b/app/__pycache__/category_management_dialog.cpython-39.pyc index 7dc1aba..662d16e 100644 Binary files a/app/__pycache__/category_management_dialog.cpython-39.pyc and b/app/__pycache__/category_management_dialog.cpython-39.pyc differ diff --git a/app/__pycache__/code_configuration_interface.cpython-39.pyc b/app/__pycache__/code_configuration_interface.cpython-39.pyc index 88528d7..bfc26be 100644 Binary files a/app/__pycache__/code_configuration_interface.cpython-39.pyc and b/app/__pycache__/code_configuration_interface.cpython-39.pyc differ diff --git a/app/__pycache__/data_interface.cpython-39.pyc b/app/__pycache__/data_interface.cpython-39.pyc index 3ee06cd..5b32c94 100644 Binary files a/app/__pycache__/data_interface.cpython-39.pyc and b/app/__pycache__/data_interface.cpython-39.pyc differ diff --git a/app/__pycache__/finance_interface.cpython-39.pyc b/app/__pycache__/finance_interface.cpython-39.pyc index aba10e8..967722b 100644 Binary files a/app/__pycache__/finance_interface.cpython-39.pyc and b/app/__pycache__/finance_interface.cpython-39.pyc differ diff --git a/app/__pycache__/function_fit_interface.cpython-39.pyc b/app/__pycache__/function_fit_interface.cpython-39.pyc index 827a109..66edcfa 100644 Binary files a/app/__pycache__/function_fit_interface.cpython-39.pyc and b/app/__pycache__/function_fit_interface.cpython-39.pyc differ diff --git a/app/__pycache__/home_interface.cpython-39.pyc b/app/__pycache__/home_interface.cpython-39.pyc index 5c30dbd..c6ce228 100644 Binary files a/app/__pycache__/home_interface.cpython-39.pyc and b/app/__pycache__/home_interface.cpython-39.pyc differ diff --git a/app/__pycache__/main_window.cpython-39.pyc b/app/__pycache__/main_window.cpython-39.pyc index 386b8f7..a8602e4 100644 Binary files a/app/__pycache__/main_window.cpython-39.pyc and b/app/__pycache__/main_window.cpython-39.pyc differ diff --git a/app/__pycache__/mini_tool_interface.cpython-39.pyc b/app/__pycache__/mini_tool_interface.cpython-39.pyc index 624bef0..a8c9259 100644 Binary files a/app/__pycache__/mini_tool_interface.cpython-39.pyc and b/app/__pycache__/mini_tool_interface.cpython-39.pyc differ diff --git a/app/code_page/__pycache__/bsp_interface.cpython-39.pyc b/app/code_page/__pycache__/bsp_interface.cpython-39.pyc index cb8cc0e..b64011f 100644 Binary files a/app/code_page/__pycache__/bsp_interface.cpython-39.pyc and b/app/code_page/__pycache__/bsp_interface.cpython-39.pyc differ diff --git a/app/code_page/bsp_interface.py b/app/code_page/bsp_interface.py index d48513c..5ba4617 100644 --- a/app/code_page/bsp_interface.py +++ b/app/code_page/bsp_interface.py @@ -803,6 +803,92 @@ class bsp_spi(BspPeripheralBase): ) +class bsp_fdcan(BspPeripheralBase): + def __init__(self, project_path): + super().__init__( + project_path, + "FDCAN", + {'header': 'fdcan.h', 'source': 'fdcan.c'}, + "BSP_FDCAN", + "hfdcan", + "fdcan", + get_available_fdcan + ) + + def _generate_header_file(self, configs, template_dir): + """生成FDCAN头文件,包含动态宏定义""" + template_path = os.path.join(template_dir, self.template_names['header']) + template_content = CodeGenerator.load_template(template_path) + if not template_content: + return False + + # 生成枚举 + enum_lines = [f" {self.enum_prefix}_{name}," for name, _ in configs] + content = CodeGenerator.replace_auto_generated( + template_content, f"AUTO GENERATED {self.enum_prefix}_NAME", "\n".join(enum_lines) + ) + + # 生成FDCAN实例使能宏定义 + macro_lines = [] + for name, instance in configs: + fdcan_num = ''.join(filter(str.isdigit, instance)) # 提取数字,如FDCAN1 -> 1 + macro_lines.append(f"#define {instance}_EN") + + # 替换宏定义区域 + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FDCAN_EN", "\n".join(macro_lines) + ) + + # 生成FIFO配置宏定义 + fifo_lines = [] + fdcan_count = len(configs) + for idx, (name, instance) in enumerate(configs): + fdcan_num = ''.join(filter(str.isdigit, instance)) + # FDCAN1使用FIFO0,其他使用FIFO1 + if instance == 'FDCAN1': + fifo_lines.append(f"#define {instance}_RX_FIFO 0") + else: + fifo_lines.append(f"#define {instance}_RX_FIFO 1") + + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FDCAN_RX_FIFO", "\n".join(fifo_lines) + ) + + output_path = os.path.join(self.project_path, f"User/bsp/{self.template_names['header']}") + CodeGenerator.save_with_preserve(output_path, content) + return True + + def _generate_source_file(self, configs, template_dir): + """生成FDCAN源文件""" + template_path = os.path.join(template_dir, self.template_names['source']) + template_content = CodeGenerator.load_template(template_path) + if not template_content: + return False + + # Get函数 + get_lines = [] + for idx, (name, instance) in enumerate(configs): + get_lines.append(f" case {idx}: return {self.enum_prefix}_{name};") + content = CodeGenerator.replace_auto_generated( + template_content, "AUTO GENERATED FDCAN_GET", "\n".join(get_lines) + ) + + # Handle函数 + handle_lines = [] + for name, instance in configs: + fdcan_num = ''.join(filter(str.isdigit, instance)) + handle_lines.append(f"#ifdef {instance}_EN") + handle_lines.append(f" case {self.enum_prefix}_{name}: return &{self.handle_prefix}{fdcan_num};") + handle_lines.append(f"#endif") + content = CodeGenerator.replace_auto_generated( + content, f"AUTO GENERATED {self.enum_prefix}_GET_HANDLE", "\n".join(handle_lines) + ) + + output_path = os.path.join(self.project_path, f"User/bsp/{self.template_names['source']}") + CodeGenerator.save_with_preserve(output_path, content) + return True + + def patch_uart_interrupts(project_path, uart_instances): """自动修改 stm32f4xx_it.c,插入 UART BSP 相关代码""" it_path = os.path.join(project_path, "Core/Src/stm32f4xx_it.c") diff --git a/app/home_interface.py b/app/home_interface.py index 4ba30be..678e166 100644 --- a/app/home_interface.py +++ b/app/home_interface.py @@ -5,10 +5,20 @@ import sys import os def resource_path(relative_path): - """获取资源文件的绝对路径,兼容打包和开发环境""" - if hasattr(sys, '_MEIPASS'): - # PyInstaller 打包后的临时目录 - return os.path.join(sys._MEIPASS, relative_path) + """获取资源文件的绝对路径,兼容打包和开发环境 + 对于 logo 文件,使用打包的临时目录(只有 logo 被打包) + 对于其他资源,使用可执行文件所在目录 + """ + if getattr(sys, 'frozen', False): + # 打包环境 + if 'logo' in relative_path: + # logo 文件使用打包的临时目录 + if hasattr(sys, '_MEIPASS'): + return os.path.join(sys._MEIPASS, relative_path) + # 其他资源使用可执行文件所在目录 + exe_dir = os.path.dirname(sys.executable) + return os.path.join(exe_dir, relative_path) + # 开发环境 return os.path.join(os.path.abspath("."), relative_path) class HomeInterface(QWidget): diff --git a/app/tools/__pycache__/analyzing_ioc.cpython-39.pyc b/app/tools/__pycache__/analyzing_ioc.cpython-39.pyc index a219040..00dd03d 100644 Binary files a/app/tools/__pycache__/analyzing_ioc.cpython-39.pyc and b/app/tools/__pycache__/analyzing_ioc.cpython-39.pyc differ diff --git a/app/tools/__pycache__/code_generator.cpython-39.pyc b/app/tools/__pycache__/code_generator.cpython-39.pyc index 80e4181..fcc5e55 100644 Binary files a/app/tools/__pycache__/code_generator.cpython-39.pyc and b/app/tools/__pycache__/code_generator.cpython-39.pyc differ diff --git a/app/tools/__pycache__/update_code.cpython-39.pyc b/app/tools/__pycache__/update_code.cpython-39.pyc index f7baf68..63ba87c 100644 Binary files a/app/tools/__pycache__/update_code.cpython-39.pyc and b/app/tools/__pycache__/update_code.cpython-39.pyc differ diff --git a/app/tools/analyzing_ioc.py b/app/tools/analyzing_ioc.py index 51a70c6..542cbb4 100644 --- a/app/tools/analyzing_ioc.py +++ b/app/tools/analyzing_ioc.py @@ -71,7 +71,7 @@ class analyzing_ioc: @staticmethod def get_enabled_can_from_ioc(ioc_path): """ - 获取已启用的CAN列表 + 获取已启用的CAN列表(不包括FDCAN) 返回格式: ['CAN1', 'CAN2'] 等 """ enabled_can = [] @@ -84,6 +84,7 @@ class analyzing_ioc: key, value = line.split('=', 1) key = key.strip() value = value.strip() + # 只匹配CAN,不包括FDCAN if key.startswith('Mcu.IP') and value.startswith('CAN') and not value.startswith('FDCAN'): can_name = value.split('.')[0] if '.' in value else value if can_name not in enabled_can: diff --git a/app/tools/code_generator.py b/app/tools/code_generator.py index 654ccbd..676c581 100644 --- a/app/tools/code_generator.py +++ b/app/tools/code_generator.py @@ -97,44 +97,19 @@ class CodeGenerator: assets_dir = "" if getattr(sys, 'frozen', False): - # 打包后的环境 - print("检测到打包环境") - - # 优先使用可执行文件所在目录(支持更新后的文件) + # 打包后的环境 - 始终使用可执行文件所在目录 + # 这样可以使用安装目录下的文件,而不是打包进去的文件 exe_dir = os.path.dirname(sys.executable) - exe_assets = os.path.join(exe_dir, "assets") + assets_dir = os.path.join(exe_dir, "assets") + print(f"打包环境:使用可执行文件目录: {assets_dir}") - # 如果exe目录下不存在assets,但_MEIPASS中有,则首次复制过去 - if not os.path.exists(exe_assets) and hasattr(sys, '_MEIPASS'): - base_path = getattr(sys, '_MEIPASS') - meipass_assets = os.path.join(base_path, "assets") - if os.path.exists(meipass_assets): - try: - import shutil - print(f"首次运行:从 {meipass_assets} 复制到 {exe_assets}") - shutil.copytree(meipass_assets, exe_assets) - print("初始资源复制成功") - except Exception as e: - print(f"复制初始资源失败: {e}") - - # 优先使用exe目录下的assets(这样可以读取更新后的文件) - if os.path.exists(exe_assets): - assets_dir = exe_assets - print(f"使用可执行文件目录: {assets_dir}") - # 后备方案:使用PyInstaller的临时解包目录 - elif hasattr(sys, '_MEIPASS'): - base_path = getattr(sys, '_MEIPASS') - assets_dir = os.path.join(base_path, "assets") - print(f"后备:使用PyInstaller临时目录: {assets_dir}") - # 最后尝试工作目录 - else: - cwd_assets = os.path.join(os.getcwd(), "assets") - if os.path.exists(cwd_assets): - assets_dir = cwd_assets - print(f"从工作目录找到assets: {assets_dir}") - else: - assets_dir = exe_assets # 即使不存在也使用exe目录,后续会创建 - print(f"使用默认路径(将创建): {assets_dir}") + # 如果assets目录不存在,创建它 + if not os.path.exists(assets_dir): + try: + os.makedirs(assets_dir, exist_ok=True) + print(f"创建assets目录: {assets_dir}") + except Exception as e: + print(f"创建assets目录失败: {e}") else: # 开发环境 current_dir = os.path.dirname(os.path.abspath(__file__)) diff --git a/assets/Finance_Data/accounts/7751771f-1363-4606-b292-2db511004bae/metadata.json b/assets/Finance_Data/accounts/7751771f-1363-4606-b292-2db511004bae/metadata.json new file mode 100644 index 0000000..0b87776 --- /dev/null +++ b/assets/Finance_Data/accounts/7751771f-1363-4606-b292-2db511004bae/metadata.json @@ -0,0 +1,8 @@ +{ + "id": "7751771f-1363-4606-b292-2db511004bae", + "name": "admin", + "description": "默认管理账户", + "categories": [], + "created_at": "2025-12-29T20:48:32.536465", + "updated_at": "2025-12-29T20:48:32.536472" +} \ No newline at end of file diff --git a/assets/User_code/.DS_Store b/assets/User_code/.DS_Store index e391af5..0f8f41b 100644 Binary files a/assets/User_code/.DS_Store and b/assets/User_code/.DS_Store differ diff --git a/assets/User_code/bsp/describe.csv b/assets/User_code/bsp/describe.csv index 5206a52..2788635 100644 --- a/assets/User_code/bsp/describe.csv +++ b/assets/User_code/bsp/describe.csv @@ -1,5 +1,6 @@ uart,请开启uart的dma和中断 can,请开启can中断,使用函数前请确保can已经初始化。一定要开启can发送中断!!! +fdcan,请开启fdcan中断,支持经典CAN和FDCAN模式。会自动根据IOC配置生成对应的宏定义。 gpio,会自动读取cubemx中配置为gpio的引脚,并自动区分输入输出和中断。 spi,请开启spi的dma和中断 i2c,要求开始spi中断 diff --git a/assets/User_code/bsp/fdcan.c b/assets/User_code/bsp/fdcan.c index 3ddb26d..6c6221f 100644 --- a/assets/User_code/bsp/fdcan.c +++ b/assets/User_code/bsp/fdcan.c @@ -90,7 +90,9 @@ static bool BSP_FDCAN_TxQueueIsEmpty(BSP_FDCAN_t fdcan); /* Private functions -------------------------------------------------------- */ static BSP_FDCAN_t FDCAN_Get(FDCAN_HandleTypeDef *hfdcan) { if (hfdcan == NULL) return BSP_FDCAN_ERR; -/* AUTO GENERATED FDCAN_GET */ + if (hfdcan->Instance == FDCAN1) return BSP_FDCAN_1; + else if (hfdcan->Instance == FDCAN2) return BSP_FDCAN_2; + else if (hfdcan->Instance == FDCAN3) return BSP_FDCAN_3; else return BSP_FDCAN_ERR; } @@ -326,11 +328,10 @@ int8_t BSP_FDCAN_Init(void) { queue_mutex = osMutexNew(NULL); if (queue_mutex == NULL) return BSP_ERR; - /* 配置并启动 FDCAN 实例,绑定中断/回调 */ -/* AUTO GENERATED FDCAN_INIT */ - inited = true; + /* 配置并启动 FDCAN 实例,绑定中断/回调 */ + //========== 过滤器配置说明:========================== // 过滤器编号:相对于每个(相当于经典can过滤器的bank) // sFilterConfig.FilterIndex = 0 to 127(标准ID) or 0 to 63(扩展ID); @@ -370,11 +371,48 @@ int8_t BSP_FDCAN_Init(void) { // IsCalibrationMsg = 0 or 1; // fdcan_filter_table.h //================================================================================= - /* 配置并启动 FDCAN 实例,绑定中断/回调 */ -/* AUTO GENERATED FDCAN_INIT */ - - inited = true; - + /* 依据上述说明,配置过滤器并启动FDCAN */ + FDCAN_FilterTypeDef sFilterConfig; + +#ifdef FDCAN1_EN + #define hfdcan hfdcan1 + #define FDCANX_RX_FIFO FDCAN1_RX_FIFO + FDCAN1_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER) + #undef hfdcan + #undef FDCANX_RX_FIFO + HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN1_GLOBAL_FILTER); + HAL_FDCAN_ActivateNotification(&hfdcan1, FDCANx_NOTIFY_FLAGS(FDCAN1_RX_FIFO), 0); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_1, FDCANX_MSG_PENDING_CB(FDCAN1_RX_FIFO), BSP_FDCAN_RxFifo0Callback); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_1, HAL_FDCAN_TX_EVENT_FIFO_CB, BSP_FDCAN_TxCompleteCallback); + HAL_FDCAN_Start(&hfdcan1); +#endif + +#ifdef FDCAN2_EN + #define hfdcan hfdcan2 + #define FDCANX_RX_FIFO FDCAN2_RX_FIFO + FDCAN2_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER) + #undef hfdcan + #undef FDCANX_RX_FIFO + HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN2_GLOBAL_FILTER); + HAL_FDCAN_ActivateNotification(&hfdcan2, FDCANx_NOTIFY_FLAGS(FDCAN2_RX_FIFO), 0); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_2, FDCANX_MSG_PENDING_CB(FDCAN2_RX_FIFO), BSP_FDCAN_RxFifo1Callback); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_2, HAL_FDCAN_TX_EVENT_FIFO_CB, BSP_FDCAN_TxCompleteCallback); + HAL_FDCAN_Start(&hfdcan2); +#endif + +#ifdef FDCAN3_EN + #define hfdcan hfdcan3 + #define FDCANX_RX_FIFO FDCAN3_RX_FIFO + FDCAN3_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER) + #undef hfdcan + #undef FDCANX_RX_FIFO + HAL_FDCAN_ConfigGlobalFilter(&hfdcan3, FDCAN3_GLOBAL_FILTER); + HAL_FDCAN_ActivateNotification(&hfdcan3, FDCANx_NOTIFY_FLAGS(FDCAN3_RX_FIFO), 0); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_3, FDCANX_MSG_PENDING_CB(FDCAN3_RX_FIFO), BSP_FDCAN_RxFifo1Callback); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_3, HAL_FDCAN_TX_EVENT_FIFO_CB, BSP_FDCAN_TxCompleteCallback); + HAL_FDCAN_Start(&hfdcan3); +#endif + #undef FDCAN_FILTER_TO_RXFIFO_ENUM_INNER #undef FDCAN_FILTER_TO_RXFIFO_ENUM #undef FDCAN_CONFIG_FILTER @@ -388,13 +426,15 @@ int8_t BSP_FDCAN_Init(void) { } FDCAN_HandleTypeDef *BSP_FDCAN_GetHandle(BSP_FDCAN_t fdcan) { - if (fdcan >= BSP_FDCAN_NUM) return NULL; - - switch (fdcan) { -/* AUTO GENERATED BSP_FDCAN_GET_HANDLE */ - default: - return NULL; - } + if (fdcan >= BSP_FDCAN_NUM) return NULL; + switch (fdcan) { + /* AUTO GENERATED BSP_FDCAN_GET_HANDLE BEGIN */ + case BSP_FDCAN_1: return &hfdcan1; + case BSP_FDCAN_2: return &hfdcan2; + case BSP_FDCAN_3: return &hfdcan3; + /* AUTO GENERATED BSP_FDCAN_GET_HANDLE END */ + default: return NULL; + } } int8_t BSP_FDCAN_RegisterCallback(BSP_FDCAN_t fdcan, BSP_FDCAN_Callback_t type, void (*callback)(void)) { diff --git a/assets/User_code/bsp/fdcan.h b/assets/User_code/bsp/fdcan.h index 3a53319..99ecd80 100644 --- a/assets/User_code/bsp/fdcan.h +++ b/assets/User_code/bsp/fdcan.h @@ -22,13 +22,32 @@ extern "C" { #define BSP_FDCAN_TIMEOUT_FOREVER osWaitForever #define BSP_FDCAN_TX_QUEUE_SIZE 32 /* Exported macro ----------------------------------------------------------- */ -/* AUTO GENERATED FDCAN_ENABLE */ +//FDCANX实例使能 +/* AUTO GENERATED FDCAN_EN BEGIN */ +#define FDCAN1_EN +#define FDCAN2_EN +#define FDCAN3_EN +/* AUTO GENERATED FDCAN_EN END */ +// FDCANX接收FIFO选择(0=FIFO0, 1=FIFO1) +/* AUTO GENERATED FDCAN_RX_FIFO BEGIN */ +#ifdef FDCAN1_EN + #define FDCAN1_RX_FIFO 0 +#endif +#ifdef FDCAN2_EN + #define FDCAN2_RX_FIFO 1 +#endif +#ifdef FDCAN3_EN + #define FDCAN3_RX_FIFO 1 +#endif +/* AUTO GENERATED FDCAN_RX_FIFO END */ /* Exported types ----------------------------------------------------------- */ typedef enum { + /* AUTO GENERATED BSP_FDCAN_NAME BEGIN */ BSP_FDCAN_1, BSP_FDCAN_2, BSP_FDCAN_3, + /* AUTO GENERATED BSP_FDCAN_NAME END */ BSP_FDCAN_NUM, BSP_FDCAN_ERR, } BSP_FDCAN_t;