mirror of
https://github.com/goldenfishs/MRobot.git
synced 2026-03-31 21:07:14 +08:00
疯狂写bsp
This commit is contained in:
@@ -366,6 +366,14 @@ def get_available_gpio(project_path):
|
||||
return analyzing_ioc.get_enabled_gpio_from_ioc(ioc_path)
|
||||
return []
|
||||
|
||||
def get_available_pwm(project_path):
|
||||
"""获取可用的PWM通道"""
|
||||
ioc_files = [f for f in os.listdir(project_path) if f.endswith('.ioc')]
|
||||
if ioc_files:
|
||||
ioc_path = os.path.join(project_path, ioc_files[0])
|
||||
return analyzing_ioc.get_enabled_pwm_from_ioc(ioc_path)
|
||||
return []
|
||||
|
||||
# 具体外设类
|
||||
class bsp_i2c(BspPeripheralBase):
|
||||
def __init__(self, project_path):
|
||||
@@ -391,6 +399,70 @@ 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函数
|
||||
get_lines = []
|
||||
for idx, (name, instance) in enumerate(configs):
|
||||
if idx == 0:
|
||||
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};")
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
template_content, "AUTO GENERATED CAN_GET", "\n".join(get_lines)
|
||||
)
|
||||
|
||||
# Handle函数
|
||||
handle_lines = []
|
||||
for name, instance in configs:
|
||||
handle_lines.append(f" case {self.enum_prefix}_{name}:")
|
||||
handle_lines.append(f" return &h{instance.lower()};")
|
||||
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("")
|
||||
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
content, "AUTO GENERATED CAN_INIT", "\n".join(init_lines)
|
||||
)
|
||||
|
||||
output_path = os.path.join(self.project_path, f"User/bsp/{self.template_names['source']}")
|
||||
save_with_preserve(output_path, content)
|
||||
return True
|
||||
|
||||
class bsp_spi(BspPeripheralBase):
|
||||
def __init__(self, project_path):
|
||||
super().__init__(
|
||||
@@ -419,19 +491,30 @@ class bsp_gpio(QWidget):
|
||||
def __init__(self, project_path):
|
||||
super().__init__()
|
||||
self.project_path = project_path
|
||||
self.available_list = get_available_gpio(project_path)
|
||||
# 新增:加载描述
|
||||
self.available_list = self._get_all_gpio_list()
|
||||
# 加载描述
|
||||
describe_path = os.path.join(os.path.dirname(__file__), "../../assets/User_code/bsp/describe.csv")
|
||||
self.descriptions = load_descriptions(describe_path)
|
||||
self._init_ui()
|
||||
self._load_config()
|
||||
|
||||
def _get_all_gpio_list(self):
|
||||
"""获取所有GPIO配置"""
|
||||
ioc_files = [f for f in os.listdir(self.project_path) if f.endswith('.ioc')]
|
||||
if ioc_files:
|
||||
ioc_path = os.path.join(self.project_path, ioc_files[0])
|
||||
return analyzing_ioc.get_all_gpio_from_ioc(ioc_path)
|
||||
return []
|
||||
|
||||
def _init_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# 顶部布局
|
||||
top_layout = QHBoxLayout()
|
||||
top_layout.setAlignment(Qt.AlignVCenter)
|
||||
|
||||
self.generate_checkbox = CheckBox("生成 GPIO 代码")
|
||||
self.generate_checkbox.stateChanged.connect(self._on_generate_changed)
|
||||
top_layout.addWidget(self.generate_checkbox, alignment=Qt.AlignLeft)
|
||||
|
||||
top_layout.addStretch()
|
||||
@@ -449,77 +532,407 @@ class bsp_gpio(QWidget):
|
||||
desc_label = BodyLabel(f"功能说明:{desc}")
|
||||
desc_label.setWordWrap(True)
|
||||
layout.addWidget(desc_label)
|
||||
|
||||
# 内容区域
|
||||
self.content_widget = QWidget()
|
||||
content_layout = QVBoxLayout(self.content_widget)
|
||||
|
||||
if not self.available_list:
|
||||
layout.addWidget(BodyLabel("在 .ioc 文件中未找到可用的 GPIO"))
|
||||
content_layout.addWidget(BodyLabel("在 .ioc 文件中未找到可用的 GPIO"))
|
||||
else:
|
||||
# 创建表格
|
||||
self.table = TableWidget()
|
||||
self.table.setColumnCount(1)
|
||||
self.table.setRowCount(len(self.available_list))
|
||||
self.table.setHorizontalHeaderLabels(["Label"])
|
||||
self.table.setColumnCount(4)
|
||||
self.table.setHorizontalHeaderLabels(["IOC Label", "自定义名称", "类型", "包含"])
|
||||
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
for row, item in enumerate(self.available_list):
|
||||
|
||||
# 填充表格
|
||||
for row, gpio_info in enumerate(self.available_list):
|
||||
self.table.insertRow(row)
|
||||
|
||||
# IOC Label (只读)
|
||||
from PyQt5.QtWidgets import QTableWidgetItem
|
||||
self.table.setItem(row, 0, QTableWidgetItem(item['label']))
|
||||
self.table.setEditTriggers(TableWidget.NoEditTriggers)
|
||||
layout.addWidget(self.table)
|
||||
label_item = QTableWidgetItem(gpio_info['label'])
|
||||
label_item.setFlags(label_item.flags() & ~Qt.ItemIsEditable)
|
||||
self.table.setItem(row, 0, label_item)
|
||||
|
||||
# 自定义名称 (可编辑)
|
||||
name_edit = LineEdit()
|
||||
name_edit.setText(gpio_info['label']) # 默认使用IOC的label
|
||||
name_edit.setPlaceholderText("输入自定义名称")
|
||||
self.table.setCellWidget(row, 1, name_edit)
|
||||
|
||||
# 类型显示
|
||||
gpio_type = "EXTI" if gpio_info['has_exti'] else ("输出" if gpio_info['is_output'] else "输入")
|
||||
type_item = QTableWidgetItem(gpio_type)
|
||||
type_item.setFlags(type_item.flags() & ~Qt.ItemIsEditable)
|
||||
self.table.setItem(row, 2, type_item)
|
||||
|
||||
# 包含复选框
|
||||
include_checkbox = CheckBox("")
|
||||
include_checkbox.setChecked(True) # 默认选中
|
||||
self.table.setCellWidget(row, 3, include_checkbox)
|
||||
|
||||
content_layout.addWidget(self.table)
|
||||
|
||||
layout.addWidget(self.content_widget)
|
||||
self.content_widget.setEnabled(False)
|
||||
|
||||
def _on_generate_changed(self, state):
|
||||
self.content_widget.setEnabled(state == 2)
|
||||
|
||||
def is_need_generate(self):
|
||||
return self.generate_checkbox.isChecked() and bool(self.available_list)
|
||||
|
||||
def _collect_configs(self):
|
||||
"""收集用户配置"""
|
||||
configs = []
|
||||
for row in range(self.table.rowCount()):
|
||||
include_widget = self.table.cellWidget(row, 3)
|
||||
if include_widget and include_widget.isChecked():
|
||||
name_widget = self.table.cellWidget(row, 1)
|
||||
if name_widget:
|
||||
custom_name = name_widget.text().strip()
|
||||
if custom_name:
|
||||
gpio_info = self.available_list[row]
|
||||
configs.append({
|
||||
'custom_name': custom_name.upper(),
|
||||
'ioc_label': gpio_info['label'],
|
||||
'pin': gpio_info['pin'],
|
||||
'has_exti': gpio_info['has_exti']
|
||||
})
|
||||
return configs
|
||||
|
||||
def _generate_bsp_code_internal(self):
|
||||
if not self.is_need_generate():
|
||||
return False
|
||||
|
||||
configs = self._collect_configs()
|
||||
if not configs:
|
||||
return False
|
||||
|
||||
template_dir = CodeGenerator.get_template_dir()
|
||||
if not self._generate_header_file(template_dir):
|
||||
if not self._generate_header_file(configs, template_dir):
|
||||
return False
|
||||
if not self._generate_source_file(template_dir):
|
||||
if not self._generate_source_file(configs, template_dir):
|
||||
return False
|
||||
self._save_config()
|
||||
self._save_config(configs)
|
||||
return True
|
||||
|
||||
def _generate_header_file(self, template_dir):
|
||||
def _generate_header_file(self, configs, template_dir):
|
||||
template_path = os.path.join(template_dir, "gpio.h")
|
||||
template_content = CodeGenerator.load_template(template_path)
|
||||
if not template_content:
|
||||
return False
|
||||
|
||||
# 生成枚举
|
||||
enum_lines = []
|
||||
for config in configs:
|
||||
enum_lines.append(f" BSP_GPIO_{config['custom_name']},")
|
||||
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
template_content, "AUTO GENERATED BSP_GPIO_ENUM", "\n".join(enum_lines)
|
||||
)
|
||||
|
||||
output_path = os.path.join(self.project_path, "User/bsp/gpio.h")
|
||||
save_with_preserve(output_path, template_content) # 使用保留用户区域的写入
|
||||
save_with_preserve(output_path, content)
|
||||
return True
|
||||
|
||||
def _generate_source_file(self, template_dir):
|
||||
def _generate_source_file(self, configs, template_dir):
|
||||
template_path = os.path.join(template_dir, "gpio.c")
|
||||
template_content = CodeGenerator.load_template(template_path)
|
||||
if not template_content:
|
||||
return False
|
||||
|
||||
# 生成MAP数组
|
||||
map_lines = []
|
||||
for config in configs:
|
||||
ioc_label = config['ioc_label']
|
||||
map_lines.append(f" {{{ioc_label}_Pin, {ioc_label}_GPIO_Port}},")
|
||||
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
template_content, "AUTO GENERATED BSP_GPIO_MAP", "\n".join(map_lines)
|
||||
)
|
||||
|
||||
# 生成EXTI使能代码
|
||||
enable_lines = []
|
||||
disable_lines = []
|
||||
for item in self.available_list:
|
||||
label = item['label']
|
||||
enable_lines.append(f" case {label}_Pin:")
|
||||
enable_lines.append(f" HAL_NVIC_EnableIRQ({label}_EXTI_IRQn);")
|
||||
enable_lines.append(f" break;")
|
||||
disable_lines.append(f" case {label}_Pin:")
|
||||
disable_lines.append(f" HAL_NVIC_DisableIRQ({label}_EXTI_IRQn);")
|
||||
disable_lines.append(f" break;")
|
||||
for config in configs:
|
||||
if config['has_exti']:
|
||||
ioc_label = config['ioc_label']
|
||||
enable_lines.append(f" case {ioc_label}_Pin:")
|
||||
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" HAL_NVIC_DisableIRQ({ioc_label}_EXTI_IRQn);")
|
||||
disable_lines.append(f" break;")
|
||||
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
template_content, "AUTO GENERATED BSP_GPIO_ENABLE_IRQ", "\n".join(enable_lines)
|
||||
content, "AUTO GENERATED BSP_GPIO_ENABLE_IRQ", "\n".join(enable_lines)
|
||||
)
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
content, "AUTO GENERATED BSP_GPIO_DISABLE_IRQ", "\n".join(disable_lines)
|
||||
)
|
||||
|
||||
output_path = os.path.join(self.project_path, "User/bsp/gpio.c")
|
||||
save_with_preserve(output_path, content) # 使用保留用户区域的写入
|
||||
save_with_preserve(output_path, content)
|
||||
return True
|
||||
|
||||
def _save_config(self):
|
||||
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)
|
||||
config_data['gpio'] = {
|
||||
'enabled': True,
|
||||
'labels': [item['label'] for item in self.available_list]
|
||||
'configs': [
|
||||
{
|
||||
'custom_name': config['custom_name'],
|
||||
'ioc_label': config['ioc_label'],
|
||||
'pin': config['pin'],
|
||||
'has_exti': config['has_exti']
|
||||
} for config in configs
|
||||
]
|
||||
}
|
||||
CodeGenerator.save_config(config_data, config_path)
|
||||
|
||||
def _load_config(self):
|
||||
config_path = os.path.join(self.project_path, "User/bsp/bsp_config.yaml")
|
||||
config_data = CodeGenerator.load_config(config_path)
|
||||
conf = config_data.get('gpio', {})
|
||||
if conf.get('enabled', False):
|
||||
self.generate_checkbox.setChecked(True)
|
||||
saved_configs = conf.get('configs', [])
|
||||
# 恢复用户的自定义名称和选择状态
|
||||
for saved_config in saved_configs:
|
||||
for row in range(len(self.available_list)):
|
||||
if (self.available_list[row]['label'] == saved_config['ioc_label'] and
|
||||
hasattr(self, 'table')):
|
||||
name_widget = self.table.cellWidget(row, 1)
|
||||
if name_widget:
|
||||
name_widget.setText(saved_config['custom_name'])
|
||||
|
||||
class bsp_pwm(QWidget):
|
||||
def __init__(self, project_path):
|
||||
super().__init__()
|
||||
self.project_path = project_path
|
||||
self.available_list = self._get_pwm_channels()
|
||||
# 加载描述
|
||||
describe_path = os.path.join(os.path.dirname(__file__), "../../assets/User_code/bsp/describe.csv")
|
||||
self.descriptions = load_descriptions(describe_path)
|
||||
self._init_ui()
|
||||
self._load_config()
|
||||
|
||||
def _get_pwm_channels(self):
|
||||
"""获取所有PWM通道配置"""
|
||||
return get_available_pwm(self.project_path)
|
||||
|
||||
def _init_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# 顶部布局
|
||||
top_layout = QHBoxLayout()
|
||||
top_layout.setAlignment(Qt.AlignVCenter)
|
||||
|
||||
self.generate_checkbox = CheckBox("生成 PWM 代码")
|
||||
self.generate_checkbox.stateChanged.connect(self._on_generate_changed)
|
||||
top_layout.addWidget(self.generate_checkbox, alignment=Qt.AlignLeft)
|
||||
|
||||
top_layout.addStretch()
|
||||
|
||||
title = SubtitleLabel("PWM 配置 ")
|
||||
title.setAlignment(Qt.AlignHCenter)
|
||||
top_layout.addWidget(title, alignment=Qt.AlignHCenter)
|
||||
|
||||
top_layout.addStretch()
|
||||
|
||||
layout.addLayout(top_layout)
|
||||
|
||||
desc = self.descriptions.get("pwm", "")
|
||||
if desc:
|
||||
desc_label = BodyLabel(f"功能说明:{desc}")
|
||||
desc_label.setWordWrap(True)
|
||||
layout.addWidget(desc_label)
|
||||
|
||||
# 内容区域
|
||||
self.content_widget = QWidget()
|
||||
content_layout = QVBoxLayout(self.content_widget)
|
||||
|
||||
if not self.available_list:
|
||||
content_layout.addWidget(BodyLabel("在 .ioc 文件中未找到可用的 PWM 通道"))
|
||||
else:
|
||||
# 创建表格
|
||||
self.table = TableWidget()
|
||||
self.table.setColumnCount(4)
|
||||
self.table.setHorizontalHeaderLabels(["PWM通道", "自定义名称", "定时器信息", "选择"])
|
||||
|
||||
# 设置列宽度 - 手动调整各列的初始宽度
|
||||
header = self.table.horizontalHeader()
|
||||
header.setSectionResizeMode(0, QHeaderView.Interactive) # PWM通道列可调整
|
||||
header.setSectionResizeMode(1, QHeaderView.Stretch) # 自定义名称列拉伸
|
||||
header.setSectionResizeMode(2, QHeaderView.Interactive) # 定时器信息列可调整
|
||||
header.setSectionResizeMode(3, QHeaderView.Fixed) # 选择列固定宽度
|
||||
|
||||
# 设置初始列宽
|
||||
self.table.setColumnWidth(0, 150) # PWM通道列宽度
|
||||
self.table.setColumnWidth(2, 120) # 定时器信息列宽度
|
||||
self.table.setColumnWidth(3, 80) # 选择列宽度
|
||||
|
||||
# 填充表格
|
||||
for row, pwm_info in enumerate(self.available_list):
|
||||
self.table.insertRow(row)
|
||||
|
||||
# PWM通道信息 (只读) - 显示完整的通道信息
|
||||
from PyQt5.QtWidgets import QTableWidgetItem
|
||||
channel_display = f"{pwm_info['timer']} {pwm_info['channel'].replace('TIM_CHANNEL_', 'CH')}"
|
||||
channel_item = QTableWidgetItem(channel_display)
|
||||
channel_item.setFlags(channel_item.flags() & ~Qt.ItemIsEditable)
|
||||
self.table.setItem(row, 0, channel_item)
|
||||
|
||||
# 自定义名称 (可编辑)
|
||||
name_edit = LineEdit()
|
||||
name_edit.setText(pwm_info['label']) # 默认使用IOC的label
|
||||
name_edit.setPlaceholderText("输入自定义名称")
|
||||
self.table.setCellWidget(row, 1, name_edit)
|
||||
|
||||
# 定时器信息 - 显示引脚和信号
|
||||
timer_info = f"{pwm_info['pin']}"
|
||||
timer_item = QTableWidgetItem(timer_info)
|
||||
timer_item.setFlags(timer_item.flags() & ~Qt.ItemIsEditable)
|
||||
self.table.setItem(row, 2, timer_item)
|
||||
|
||||
# 选择复选框 - 放在中央
|
||||
checkbox_widget = QWidget()
|
||||
checkbox_layout = QHBoxLayout(checkbox_widget)
|
||||
checkbox_layout.setContentsMargins(0, 0, 0, 0)
|
||||
checkbox_layout.setAlignment(Qt.AlignCenter)
|
||||
|
||||
include_checkbox = CheckBox("")
|
||||
include_checkbox.setChecked(True) # 默认选中
|
||||
checkbox_layout.addWidget(include_checkbox)
|
||||
|
||||
self.table.setCellWidget(row, 3, checkbox_widget)
|
||||
|
||||
content_layout.addWidget(self.table)
|
||||
|
||||
layout.addWidget(self.content_widget)
|
||||
self.content_widget.setEnabled(False)
|
||||
|
||||
def _on_generate_changed(self, state):
|
||||
self.content_widget.setEnabled(state == 2)
|
||||
|
||||
def is_need_generate(self):
|
||||
return self.generate_checkbox.isChecked() and bool(self.available_list)
|
||||
|
||||
def _collect_configs(self):
|
||||
"""收集用户配置"""
|
||||
configs = []
|
||||
for row in range(self.table.rowCount()):
|
||||
checkbox_widget = self.table.cellWidget(row, 3)
|
||||
if checkbox_widget:
|
||||
# 获取复选框
|
||||
include_checkbox = checkbox_widget.findChild(CheckBox)
|
||||
if include_checkbox and include_checkbox.isChecked():
|
||||
name_widget = self.table.cellWidget(row, 1)
|
||||
if name_widget:
|
||||
custom_name = name_widget.text().strip()
|
||||
if custom_name:
|
||||
pwm_info = self.available_list[row]
|
||||
configs.append({
|
||||
'custom_name': custom_name.upper(),
|
||||
'timer': pwm_info['timer'],
|
||||
'channel': pwm_info['channel'],
|
||||
'label': pwm_info['label']
|
||||
})
|
||||
return configs
|
||||
|
||||
def _generate_bsp_code_internal(self):
|
||||
if not self.is_need_generate():
|
||||
return False
|
||||
|
||||
configs = self._collect_configs()
|
||||
if not configs:
|
||||
return False
|
||||
|
||||
template_dir = CodeGenerator.get_template_dir()
|
||||
if not self._generate_header_file(configs, template_dir):
|
||||
return False
|
||||
if not self._generate_source_file(configs, template_dir):
|
||||
return False
|
||||
self._save_config(configs)
|
||||
return True
|
||||
|
||||
def _generate_header_file(self, configs, template_dir):
|
||||
template_path = os.path.join(template_dir, "pwm.h")
|
||||
template_content = CodeGenerator.load_template(template_path)
|
||||
if not template_content:
|
||||
return False
|
||||
|
||||
# 生成枚举
|
||||
enum_lines = []
|
||||
for config in configs:
|
||||
enum_lines.append(f" BSP_PWM_{config['custom_name']},")
|
||||
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
template_content, "AUTO GENERATED BSP_PWM_ENUM", "\n".join(enum_lines)
|
||||
)
|
||||
|
||||
output_path = os.path.join(self.project_path, "User/bsp/pwm.h")
|
||||
save_with_preserve(output_path, content)
|
||||
return True
|
||||
|
||||
def _generate_source_file(self, configs, template_dir):
|
||||
template_path = os.path.join(template_dir, "pwm.c")
|
||||
template_content = CodeGenerator.load_template(template_path)
|
||||
if not template_content:
|
||||
return False
|
||||
|
||||
# 生成MAP数组
|
||||
map_lines = []
|
||||
for config in configs:
|
||||
timer = config['timer'].lower() # tim1 -> htim1
|
||||
channel = config['channel']
|
||||
map_lines.append(f" {{&h{timer}, {channel}}},")
|
||||
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
template_content, "AUTO GENERATED BSP_PWM_MAP", "\n".join(map_lines)
|
||||
)
|
||||
|
||||
output_path = os.path.join(self.project_path, "User/bsp/pwm.c")
|
||||
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)
|
||||
config_data['pwm'] = {
|
||||
'enabled': True,
|
||||
'configs': [
|
||||
{
|
||||
'custom_name': config['custom_name'],
|
||||
'timer': config['timer'],
|
||||
'channel': config['channel'],
|
||||
'label': config['label']
|
||||
} for config in configs
|
||||
]
|
||||
}
|
||||
CodeGenerator.save_config(config_data, config_path)
|
||||
|
||||
def _load_config(self):
|
||||
config_path = os.path.join(self.project_path, "User/bsp/bsp_config.yaml")
|
||||
config_data = CodeGenerator.load_config(config_path)
|
||||
conf = config_data.get('pwm', {})
|
||||
if conf.get('enabled', False):
|
||||
self.generate_checkbox.setChecked(True)
|
||||
saved_configs = conf.get('configs', [])
|
||||
# 恢复用户的自定义名称和选择状态
|
||||
for saved_config in saved_configs:
|
||||
for row in range(len(self.available_list)):
|
||||
if (self.available_list[row]['label'] == saved_config['label'] and
|
||||
hasattr(self, 'table')):
|
||||
name_widget = self.table.cellWidget(row, 1)
|
||||
if name_widget:
|
||||
name_widget.setText(saved_config['custom_name'])
|
||||
|
||||
# 更新get_bsp_page函数以包含PWM
|
||||
def get_bsp_page(peripheral_name, project_path):
|
||||
"""根据外设名返回对应的页面类,没有特殊类则返回默认BspSimplePeripheral"""
|
||||
name_lower = peripheral_name.lower()
|
||||
@@ -529,6 +942,7 @@ def get_bsp_page(peripheral_name, project_path):
|
||||
"spi": bsp_spi,
|
||||
"uart": bsp_uart,
|
||||
"gpio": bsp_gpio,
|
||||
"pwm": bsp_pwm, # 添加PWM
|
||||
# 以后可以继续添加特殊外设
|
||||
}
|
||||
if name_lower in special_classes:
|
||||
@@ -539,7 +953,8 @@ def get_bsp_page(peripheral_name, project_path):
|
||||
'source': f'{name_lower}.c'
|
||||
}
|
||||
return BspSimplePeripheral(project_path, peripheral_name, template_names)
|
||||
|
||||
|
||||
|
||||
class bsp(QWidget):
|
||||
def __init__(self, project_path):
|
||||
super().__init__()
|
||||
|
||||
Reference in New Issue
Block a user