can支持自定义id解析了

This commit is contained in:
2025-08-07 04:40:31 +08:00
parent 3e49722616
commit 3159d3ae1a
38 changed files with 558 additions and 350 deletions

Binary file not shown.

View File

@@ -155,30 +155,49 @@ class CodeGenerateInterface(QWidget):
def generate_code(self):
"""生成代码逻辑"""
# 收集所有已加载的页面对象
pages = []
for i in range(self.stack.count()):
widget = self.stack.widget(i)
pages.append(widget)
# 生成 BSP 代码
bsp_result = bsp.generate_bsp(self.project_path, pages)
# 生成 Component 代码
from app.code_page.component_interface import component
component_result = component.generate_component(self.project_path, pages)
# 合并结果信息
combined_result = f"BSP代码生成:\n{bsp_result}\n\nComponent代码生成:\n{component_result}"
# 用 InfoBar 在主界面弹出
InfoBar.success(
title="代码生成结果",
content=combined_result,
parent=self,
duration=5000 # 增加显示时间,因为内容更多
)
"""生成代码逻辑 - 修复导入问题"""
try:
# 收集所有已加载的页面对象
pages = []
for i in range(self.stack.count()):
widget = self.stack.widget(i)
pages.append(widget)
# 确保导入成功
from app.code_page.bsp_interface import bsp
from app.code_page.component_interface import component
# 生成 BSP 代码
bsp_result = bsp.generate_bsp(self.project_path, pages)
# 生成 Component 代码
component_result = component.generate_component(self.project_path, pages)
# 合并结果信息
combined_result = f"BSP代码生成:\n{bsp_result}\n\nComponent代码生成:\n{component_result}"
# 用 InfoBar 在主界面弹出
InfoBar.success(
title="代码生成结果",
content=combined_result,
parent=self,
duration=5000
)
except ImportError as e:
InfoBar.error(
title="导入错误",
content=f"模块导入失败: {str(e)}",
parent=self,
duration=3000
)
except Exception as e:
InfoBar.error(
title="生成失败",
content=f"代码生成过程中出现错误: {str(e)}",
parent=self,
duration=3000
)
def _get_freertos_status(self):
"""获取FreeRTOS状态"""
@@ -220,7 +239,6 @@ class CodeGenerateInterface(QWidget):
if widget:
self.stack.setCurrentWidget(widget)
# ...existing code...
def _get_or_create_page(self, class_name):
"""获取或创建页面"""
if class_name in self.page_cache:
@@ -235,12 +253,12 @@ class CodeGenerateInterface(QWidget):
if class_name.startswith('bsp_'):
# BSP页面
from app.code_page.bsp_interface import get_bsp_page
# 提取外设名,如 bsp_delay -> delay
periph_name = class_name[len('bsp_'):].replace("_", " ")
# 提取外设名,如 bsp_error_detect -> error_detect
periph_name = class_name[len('bsp_'):] # 移除 .replace("_", " ")
page = get_bsp_page(periph_name, self.project_path)
elif class_name.startswith('component_'):
from app.code_page.component_interface import get_component_page
comp_name = class_name[len('component_'):].replace("_", " ")
comp_name = class_name[len('component_'):] # 移除 .replace("_", " ")
page = get_component_page(comp_name, self.project_path, self.component_manager)
self.component_manager.register_component(page.component_name, page)
else:
@@ -253,5 +271,4 @@ class CodeGenerateInterface(QWidget):
except Exception as e:
print(f"创建页面 {class_name} 失败: {e}")
return None
# ...existing code...

Binary file not shown.

View File

@@ -399,20 +399,21 @@ class bsp_can(BspPeripheralBase):
get_available_can
)
def _generate_source_file(self, configs, template_dir):
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函数
# CAN_Get函数
get_lines = []
for idx, (name, instance) in enumerate(configs):
if idx == 0:
get_lines.append(f" if (hcan->Instance == {instance})")
get_lines.append(f" if (hcan->Instance == {instance})")
else:
get_lines.append(f" else if (hcan->Instance == {instance})")
get_lines.append(f" return {self.enum_prefix}_{name};")
get_lines.append(f" else if (hcan->Instance == {instance})")
get_lines.append(f" return {self.enum_prefix}_{name};")
content = CodeGenerator.replace_auto_generated(
template_content, "AUTO GENERATED CAN_GET", "\n".join(get_lines)
)
@@ -420,41 +421,106 @@ class bsp_can(BspPeripheralBase):
# Handle函数
handle_lines = []
for name, instance in configs:
num = ''.join(filter(str.isdigit, instance)) # 提取数字
handle_lines.append(f" case {self.enum_prefix}_{name}:")
handle_lines.append(f" return &h{instance.lower()};")
handle_lines.append(f" return &hcan{num};")
content = CodeGenerator.replace_auto_generated(
content, f"AUTO GENERATED {self.enum_prefix}_GET_HANDLE", "\n".join(handle_lines)
)
# 生成CAN初始化代码
init_lines = []
for idx, (name, instance) in enumerate(configs):
can_num = instance[-1] # CAN1 -> 1, CAN2 -> 2
init_lines.append(f" // 初始化 {instance}")
init_lines.append(f" CAN_FilterTypeDef can{can_num}_filter = {{0}};")
init_lines.append(f" can{can_num}_filter.FilterBank = {0 if can_num == '1' else 14};")
init_lines.append(f" can{can_num}_filter.FilterIdHigh = 0;")
init_lines.append(f" can{can_num}_filter.FilterIdLow = 0;")
init_lines.append(f" can{can_num}_filter.FilterMode = CAN_FILTERMODE_IDMASK;")
init_lines.append(f" can{can_num}_filter.FilterScale = CAN_FILTERSCALE_32BIT;")
init_lines.append(f" can{can_num}_filter.FilterMaskIdHigh = 0;")
init_lines.append(f" can{can_num}_filter.FilterMaskIdLow = 0;")
init_lines.append(f" can{can_num}_filter.FilterActivation = ENABLE;")
if can_num == '1':
init_lines.append(f" can{can_num}_filter.SlaveStartFilterBank = 14;")
init_lines.append(f" can{can_num}_filter.FilterFIFOAssignment = CAN_RX_FIFO0;")
else:
init_lines.append(f" can{can_num}_filter.FilterFIFOAssignment = CAN_RX_FIFO1;")
init_lines.append(f" HAL_CAN_ConfigFilter(BSP_CAN_GetHandle({self.enum_prefix}_{name}), &can{can_num}_filter);")
init_lines.append(f" HAL_CAN_Start(BSP_CAN_GetHandle({self.enum_prefix}_{name}));")
# 注册回调和激活中断
fifo = "FIFO0" if can_num == '1' else "FIFO1"
init_lines.append(f" HAL_CAN_ActivateNotification(BSP_CAN_GetHandle({self.enum_prefix}_{name}), CAN_IT_RX_{fifo}_MSG_PENDING);")
init_lines.append("")
# 先设置初始化标志
init_lines.append(" // 先设置初始化标志,以便后续回调注册能通过检查")
init_lines.append(" inited = true;")
init_lines.append("")
# 检查是否同时有CAN1和CAN2
has_can1 = any(instance == 'CAN1' for _, instance in configs)
has_can2 = any(instance == 'CAN2' for _, instance in configs)
if has_can1 and has_can2:
# 同时配置CAN1和CAN2的情况 - 统一使用FIFO0
init_lines.extend([
" // 初始化 CAN1 - 使用 FIFO0",
" CAN_FilterTypeDef can1_filter = {0};",
" can1_filter.FilterBank = 0;",
" can1_filter.FilterIdHigh = 0;",
" can1_filter.FilterIdLow = 0;",
" can1_filter.FilterMode = CAN_FILTERMODE_IDMASK;",
" can1_filter.FilterScale = CAN_FILTERSCALE_32BIT;",
" can1_filter.FilterMaskIdHigh = 0;",
" can1_filter.FilterMaskIdLow = 0;",
" can1_filter.FilterActivation = ENABLE;",
" can1_filter.SlaveStartFilterBank = 14; // 重要:设置从过滤器起始组",
" can1_filter.FilterFIFOAssignment = CAN_RX_FIFO0;",
" HAL_CAN_ConfigFilter(&hcan1, &can1_filter);",
" HAL_CAN_Start(&hcan1);",
" HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);",
"",
" // 初始化 CAN2 - 使用 FIFO0注意通过 CAN1 配置 CAN2 的过滤器)",
" CAN_FilterTypeDef can2_filter = {0};",
" can2_filter.FilterBank = 14; // CAN2 使用过滤器组 14",
" can2_filter.FilterIdHigh = 0;",
" can2_filter.FilterIdLow = 0;",
" can2_filter.FilterMode = CAN_FILTERMODE_IDMASK;",
" can2_filter.FilterScale = CAN_FILTERSCALE_32BIT;",
" can2_filter.FilterMaskIdHigh = 0;",
" can2_filter.FilterMaskIdLow = 0;",
" can2_filter.FilterActivation = ENABLE;",
" can2_filter.FilterFIFOAssignment = CAN_RX_FIFO0; // 改为 FIFO0",
" HAL_CAN_ConfigFilter(&hcan1, &can2_filter); // 通过 CAN1 配置",
" HAL_CAN_Start(&hcan2);",
" HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING); // 激活 FIFO0 中断",
"",
" // 注册回调函数",
f" BSP_CAN_RegisterCallback({self.enum_prefix}_CAN1, HAL_CAN_RX_FIFO0_MSG_PENDING_CB, BSP_CAN_RxFifoCallback);",
f" BSP_CAN_RegisterCallback({self.enum_prefix}_CAN2, HAL_CAN_RX_FIFO0_MSG_PENDING_CB, BSP_CAN_RxFifoCallback);",
])
else:
# 只有单个CAN的情况
for idx, (name, instance) in enumerate(configs):
can_num = instance[-1] # CAN1 -> 1, CAN2 -> 2
init_lines.append(f" // 初始化 {instance}")
init_lines.append(f" CAN_FilterTypeDef can{can_num}_filter = {{0}};")
if instance == 'CAN1':
init_lines.extend([
f" can{can_num}_filter.FilterBank = 0;",
f" can{can_num}_filter.SlaveStartFilterBank = 14;",
f" can{can_num}_filter.FilterFIFOAssignment = CAN_RX_FIFO0;",
])
else: # CAN2
init_lines.extend([
f" can{can_num}_filter.FilterBank = 14;",
f" can{can_num}_filter.FilterFIFOAssignment = CAN_RX_FIFO0;",
])
init_lines.extend([
f" can{can_num}_filter.FilterIdHigh = 0;",
f" can{can_num}_filter.FilterIdLow = 0;",
f" can{can_num}_filter.FilterMode = CAN_FILTERMODE_IDMASK;",
f" can{can_num}_filter.FilterScale = CAN_FILTERSCALE_32BIT;",
f" can{can_num}_filter.FilterMaskIdHigh = 0;",
f" can{can_num}_filter.FilterMaskIdLow = 0;",
f" can{can_num}_filter.FilterActivation = ENABLE;",
])
if instance == 'CAN2':
init_lines.append(f" HAL_CAN_ConfigFilter(&hcan1, &can{can_num}_filter); // 通过 CAN1 配置")
else:
init_lines.append(f" HAL_CAN_ConfigFilter(&hcan{can_num}, &can{can_num}_filter);")
init_lines.extend([
f" HAL_CAN_Start(&hcan{can_num});",
f" HAL_CAN_ActivateNotification(&hcan{can_num}, CAN_IT_RX_FIFO0_MSG_PENDING);",
"",
f" // 注册回调函数",
f" BSP_CAN_RegisterCallback({self.enum_prefix}_{name}, HAL_CAN_RX_FIFO0_MSG_PENDING_CB, BSP_CAN_RxFifoCallback);",
""
])
content = CodeGenerator.replace_auto_generated(
content, "AUTO GENERATED CAN_INIT", "\n".join(init_lines)
)
@@ -463,6 +529,8 @@ class bsp_can(BspPeripheralBase):
save_with_preserve(output_path, content)
return True
class bsp_spi(BspPeripheralBase):
def __init__(self, project_path):
super().__init__(
@@ -654,16 +722,17 @@ class bsp_gpio(QWidget):
template_content, "AUTO GENERATED BSP_GPIO_MAP", "\n".join(map_lines)
)
# 生成EXTI使能代码
# 生成EXTI使能代码 - 使用用户自定义的BSP枚举名称
enable_lines = []
disable_lines = []
for config in configs:
if config['has_exti']:
ioc_label = config['ioc_label']
enable_lines.append(f" case {ioc_label}_Pin:")
custom_name = config['custom_name']
enable_lines.append(f" case BSP_GPIO_{custom_name}:")
enable_lines.append(f" HAL_NVIC_EnableIRQ({ioc_label}_EXTI_IRQn);")
enable_lines.append(f" break;")
disable_lines.append(f" case {ioc_label}_Pin:")
disable_lines.append(f" case BSP_GPIO_{custom_name}:")
disable_lines.append(f" HAL_NVIC_DisableIRQ({ioc_label}_EXTI_IRQn);")
disable_lines.append(f" break;")
@@ -678,6 +747,8 @@ class bsp_gpio(QWidget):
save_with_preserve(output_path, content)
return True
def _save_config(self, configs):
config_path = os.path.join(self.project_path, "User/bsp/bsp_config.yaml")
config_data = CodeGenerator.load_config(config_path)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -2,7 +2,8 @@ import os
import yaml
import shutil
from typing import Dict, List, Tuple
import sys
import os
class CodeGenerator:
"""通用代码生成器"""
@@ -61,15 +62,20 @@ class CodeGenerator:
@staticmethod
def get_template_dir():
"""获取模板文件目录"""
# 从当前文件向上找到 MRobot 目录,然后定位到模板目录
current_dir = os.path.dirname(os.path.abspath(__file__))
# 向上找到 MRobot 根目录
while os.path.basename(current_dir) != 'MRobot' and current_dir != '/':
current_dir = os.path.dirname(current_dir)
if os.path.basename(current_dir) == 'MRobot':
return os.path.join(current_dir, "assets/User_code/bsp")
"""获取模板目录路径,兼容打包环境"""
if getattr(sys, 'frozen', False):
# 打包后的环境
base_path = sys._MEIPASS
template_dir = os.path.join(base_path, "assets", "User_code", "bsp")
else:
# 如果找不到,使用相对路径作为备选
return os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "assets/User_code/bsp")
# 开发环境
current_dir = os.path.dirname(os.path.abspath(__file__))
while os.path.basename(current_dir) != 'MRobot' and current_dir != '/':
current_dir = os.path.dirname(current_dir)
template_dir = os.path.join(current_dir, "assets", "User_code", "bsp")
print(f"模板目录路径: {template_dir}")
if not os.path.exists(template_dir):
print(f"警告:模板目录不存在: {template_dir}")
return template_dir