Merge fdcan-feature into main

This commit is contained in:
2026-01-01 16:59:45 +08:00
26 changed files with 199 additions and 83 deletions

View File

@@ -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")

View File

@@ -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):

View File

@@ -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:

View File

@@ -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__))