mirror of
https://github.com/goldenfishs/MRobot.git
synced 2025-09-14 12:54:33 +08:00
bsp写的差不多了
This commit is contained in:
parent
af7529b529
commit
bebfbd716c
@ -1,6 +1,12 @@
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QSizePolicy, QTreeWidget, QTreeWidgetItem, QStackedWidget
|
||||
from PyQt5.QtCore import Qt
|
||||
from qfluentwidgets import TitleLabel, BodyLabel
|
||||
from qfluentwidgets import TitleLabel, BodyLabel, PushButton
|
||||
from app.tools.analyzing_ioc import analyzing_ioc
|
||||
from app.code_page.bsp_interface import bsp
|
||||
|
||||
import os
|
||||
import csv
|
||||
import importlib
|
||||
|
||||
class CodeGenerateInterface(QWidget):
|
||||
def __init__(self, project_path, parent=None):
|
||||
@ -8,14 +14,137 @@ class CodeGenerateInterface(QWidget):
|
||||
self.setObjectName("CodeGenerateInterface")
|
||||
self.project_path = project_path
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setAlignment(Qt.AlignTop)
|
||||
layout.setContentsMargins(10, 10, 10, 10)
|
||||
self._init_ui()
|
||||
|
||||
title = TitleLabel("代码生成页面")
|
||||
title.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(title)
|
||||
def _init_ui(self):
|
||||
"""初始化界面布局"""
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setAlignment(Qt.AlignTop)
|
||||
main_layout.setContentsMargins(10, 10, 10, 10)
|
||||
|
||||
desc = BodyLabel(f"当前工程路径: {self.project_path}")
|
||||
desc.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(desc)
|
||||
top_layout = self._create_top_layout()
|
||||
main_layout.addLayout(top_layout)
|
||||
|
||||
# 下方主区域,左右分栏
|
||||
content_layout = QHBoxLayout()
|
||||
content_layout.setContentsMargins(0, 10, 0, 0)
|
||||
main_layout.addLayout(content_layout)
|
||||
|
||||
# 左侧树形列表
|
||||
self.tree = QTreeWidget()
|
||||
self.tree.setHeaderHidden(True)
|
||||
self.tree.setMaximumWidth(250)
|
||||
content_layout.addWidget(self.tree)
|
||||
|
||||
# 右侧内容区
|
||||
self.stack = QStackedWidget()
|
||||
content_layout.addWidget(self.stack)
|
||||
|
||||
self._load_csv_and_build_tree()
|
||||
self.tree.itemClicked.connect(self.on_tree_item_clicked)
|
||||
|
||||
def _create_top_layout(self):
|
||||
"""创建顶部横向布局"""
|
||||
top_layout = QHBoxLayout()
|
||||
top_layout.setAlignment(Qt.AlignTop)
|
||||
|
||||
# 项目名称标签
|
||||
project_name = os.path.basename(self.project_path)
|
||||
name_label = BodyLabel(f"项目名称: {project_name}")
|
||||
name_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
||||
top_layout.addWidget(name_label)
|
||||
|
||||
# FreeRTOS状态标签
|
||||
freertos_label = BodyLabel(f"FreeRTOS: {self._get_freertos_status()}")
|
||||
freertos_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
||||
top_layout.addWidget(freertos_label)
|
||||
|
||||
# 生成代码按钮
|
||||
generate_btn = PushButton("Generate Code")
|
||||
generate_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
||||
generate_btn.clicked.connect(self.generate_code)
|
||||
top_layout.addWidget(generate_btn, alignment=Qt.AlignRight)
|
||||
|
||||
return top_layout
|
||||
|
||||
def generate_code(self):
|
||||
"""生成代码逻辑"""
|
||||
# 收集所有已加载的页面对象
|
||||
pages = []
|
||||
for i in range(self.stack.count()):
|
||||
widget = self.stack.widget(i)
|
||||
pages.append(widget)
|
||||
bsp.generate_bsp(self.project_path, pages)
|
||||
# component.generate_component(self.project_path)
|
||||
# device.generate_device(self.project_path)
|
||||
|
||||
|
||||
def _get_freertos_status(self):
|
||||
"""获取FreeRTOS状态"""
|
||||
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 "开启" if analyzing_ioc.is_freertos_enabled_from_ioc(ioc_path) else "未开启"
|
||||
return "未找到.ioc文件"
|
||||
|
||||
def _load_csv_and_build_tree(self):
|
||||
# 获取脚本目录
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
csv_path = os.path.join(script_dir, "../assets/User_code/config.csv")
|
||||
csv_path = os.path.abspath(csv_path)
|
||||
print(f"加载CSV路径: {csv_path}")
|
||||
if not os.path.exists(csv_path):
|
||||
print(f"配置文件未找到: {csv_path}")
|
||||
return
|
||||
self.tree.clear()
|
||||
with open(csv_path, newline='', encoding='utf-8') as f:
|
||||
reader = csv.reader(f)
|
||||
for row in reader:
|
||||
row = [cell.strip() for cell in row if cell.strip()]
|
||||
if not row:
|
||||
continue
|
||||
main_title = row[0]
|
||||
main_item = QTreeWidgetItem([main_title])
|
||||
for sub in row[1:]:
|
||||
sub_item = QTreeWidgetItem([sub])
|
||||
main_item.addChild(sub_item)
|
||||
self.tree.addTopLevelItem(main_item)
|
||||
self.tree.repaint()
|
||||
|
||||
def on_tree_item_clicked(self, item, column):
|
||||
if item.parent():
|
||||
main_title = item.parent().text(0)
|
||||
sub_title = item.text(0)
|
||||
class_name = f"{main_title}_{sub_title}".replace("-", "_")
|
||||
widget = self._get_or_create_page(class_name)
|
||||
if widget:
|
||||
self.stack.setCurrentWidget(widget)
|
||||
|
||||
def _get_or_create_page(self, class_name):
|
||||
for i in range(self.stack.count()):
|
||||
w = self.stack.widget(i)
|
||||
if w.objectName() == class_name:
|
||||
return w
|
||||
try:
|
||||
module_name = f"app.code_page.{class_name.split('_')[0]}_interface"
|
||||
module = importlib.import_module(module_name)
|
||||
cls = getattr(module, class_name)
|
||||
widget = cls(self.project_path)
|
||||
widget.setObjectName(class_name)
|
||||
self.stack.addWidget(widget)
|
||||
print(f"加载页面类: {class_name} 来自模块: {module_name}")
|
||||
return widget
|
||||
except Exception as e:
|
||||
# 自动识别通用外设页面
|
||||
from app.code_page.bsp_interface import BspSimplePeripheral
|
||||
peripheral_name = class_name.split('_')[1] if '_' in class_name else class_name
|
||||
# 模板文件名自动推断
|
||||
template_names = {
|
||||
'header': f"{peripheral_name.lower()}.h",
|
||||
'source': f"{peripheral_name.lower()}.c"
|
||||
}
|
||||
widget = BspSimplePeripheral(self.project_path, peripheral_name, template_names)
|
||||
widget.setObjectName(class_name)
|
||||
self.stack.addWidget(widget)
|
||||
print(f"自动加载通用外设页面: {class_name}")
|
||||
return widget
|
453
app/code_page/bsp_interface.py
Normal file
453
app/code_page/bsp_interface.py
Normal file
@ -0,0 +1,453 @@
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLineEdit, QCheckBox, QComboBox, QTableWidget, QHeaderView, QMessageBox
|
||||
from qfluentwidgets import TitleLabel, BodyLabel, PushButton
|
||||
from app.tools.analyzing_ioc import analyzing_ioc
|
||||
from app.tools.code_generator import CodeGenerator
|
||||
import os
|
||||
import csv
|
||||
|
||||
class BspSimplePeripheral(QWidget):
|
||||
def __init__(self, project_path, peripheral_name, template_names):
|
||||
super().__init__()
|
||||
self.project_path = project_path
|
||||
self.peripheral_name = peripheral_name
|
||||
self.template_names = template_names
|
||||
# 加载描述
|
||||
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 _init_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(TitleLabel(f"{self.peripheral_name} 配置"))
|
||||
desc = self.descriptions.get(self.peripheral_name.lower(), "")
|
||||
if desc:
|
||||
layout.addWidget(BodyLabel(f"功能说明:{desc}"))
|
||||
self.generate_checkbox = QCheckBox(f"启用 {self.peripheral_name}")
|
||||
layout.addWidget(self.generate_checkbox)
|
||||
|
||||
def is_need_generate(self):
|
||||
return self.generate_checkbox.isChecked()
|
||||
|
||||
def _generate_bsp_code_internal(self):
|
||||
if not self.is_need_generate():
|
||||
return False
|
||||
template_dir = CodeGenerator.get_template_dir()
|
||||
# 直接拷贝模板,无需特殊处理
|
||||
for key, filename in self.template_names.items():
|
||||
template_path = os.path.join(template_dir, filename)
|
||||
template_content = CodeGenerator.load_template(template_path)
|
||||
if not template_content:
|
||||
return False
|
||||
output_path = os.path.join(self.project_path, f"User/bsp/{filename}")
|
||||
if not CodeGenerator.save_file(template_content, output_path):
|
||||
return False
|
||||
self._save_config()
|
||||
return True
|
||||
|
||||
def _save_config(self):
|
||||
config_path = os.path.join(self.project_path, "User/bsp/bsp_config.yaml")
|
||||
config_data = CodeGenerator.load_config(config_path)
|
||||
config_data[self.peripheral_name.lower()] = {'enabled': True}
|
||||
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(self.peripheral_name.lower(), {})
|
||||
if conf.get('enabled', False):
|
||||
self.generate_checkbox.setChecked(True)
|
||||
|
||||
|
||||
class BspPeripheralBase(QWidget):
|
||||
def __init__(self, project_path, peripheral_name, template_names, enum_prefix, handle_prefix, yaml_key, get_available_func):
|
||||
super().__init__()
|
||||
self.project_path = project_path
|
||||
self.peripheral_name = peripheral_name
|
||||
self.template_names = template_names
|
||||
self.enum_prefix = enum_prefix
|
||||
self.handle_prefix = handle_prefix
|
||||
self.yaml_key = yaml_key
|
||||
self.get_available_func = get_available_func
|
||||
self.available_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 _init_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(TitleLabel(f"{self.peripheral_name} 配置"))
|
||||
desc = self.descriptions.get(self.peripheral_name.lower(), "")
|
||||
if desc:
|
||||
layout.addWidget(BodyLabel(f"功能说明:{desc}"))
|
||||
self.generate_checkbox = QCheckBox(f"生成 {self.peripheral_name} 代码")
|
||||
self.generate_checkbox = QCheckBox(f"生成 {self.peripheral_name} 代码")
|
||||
self.generate_checkbox.stateChanged.connect(self._on_generate_changed)
|
||||
layout.addWidget(self.generate_checkbox)
|
||||
self.content_widget = QWidget()
|
||||
content_layout = QVBoxLayout(self.content_widget)
|
||||
self._get_available_list()
|
||||
if not self.available_list:
|
||||
content_layout.addWidget(BodyLabel(f"在 .ioc 文件中未找到已启用的 {self.peripheral_name}"))
|
||||
else:
|
||||
content_layout.addWidget(BodyLabel(f"可用的 {self.peripheral_name}: {', '.join(self.available_list)}"))
|
||||
self.table = QTableWidget(0, 3)
|
||||
self.table.setHorizontalHeaderLabels(["设备名称", f"{self.peripheral_name}选择", "操作"])
|
||||
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
content_layout.addWidget(self.table)
|
||||
add_btn = PushButton(f"添加 {self.peripheral_name} 设备")
|
||||
add_btn.clicked.connect(self._add_device)
|
||||
content_layout.addWidget(add_btn)
|
||||
layout.addWidget(self.content_widget)
|
||||
self.content_widget.setEnabled(False)
|
||||
|
||||
def _get_available_list(self):
|
||||
self.available_list = self.get_available_func(self.project_path)
|
||||
|
||||
def _on_generate_changed(self, state):
|
||||
self.content_widget.setEnabled(state == 2)
|
||||
|
||||
def _add_device(self):
|
||||
row = self.table.rowCount()
|
||||
self.table.insertRow(row)
|
||||
name_edit = QLineEdit()
|
||||
name_edit.setPlaceholderText(f"输入设备名称")
|
||||
self.table.setCellWidget(row, 0, name_edit)
|
||||
combo = QComboBox()
|
||||
combo.addItems(self.available_list)
|
||||
self.table.setCellWidget(row, 1, combo)
|
||||
del_btn = PushButton("删除")
|
||||
del_btn.clicked.connect(lambda: self._delete_device(row))
|
||||
self.table.setCellWidget(row, 2, del_btn)
|
||||
|
||||
def _delete_device(self, row):
|
||||
self.table.removeRow(row)
|
||||
|
||||
def _collect_configs(self):
|
||||
configs = []
|
||||
for row in range(self.table.rowCount()):
|
||||
name_widget = self.table.cellWidget(row, 0)
|
||||
sel_widget = self.table.cellWidget(row, 1)
|
||||
if name_widget and sel_widget:
|
||||
name = name_widget.text().strip()
|
||||
sel = sel_widget.currentText()
|
||||
if name and sel:
|
||||
configs.append((name.upper(), sel))
|
||||
return configs
|
||||
|
||||
def is_need_generate(self):
|
||||
return self.generate_checkbox.isChecked() and bool(self._collect_configs())
|
||||
|
||||
def generate_bsp_code(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)
|
||||
QMessageBox.information(self, "成功", f"{self.peripheral_name} 代码生成成功!")
|
||||
return True
|
||||
|
||||
def _generate_header_file(self, configs, template_dir):
|
||||
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)
|
||||
)
|
||||
output_path = os.path.join(self.project_path, f"User/bsp/{self.template_names['header']}")
|
||||
return CodeGenerator.save_file(content, output_path)
|
||||
|
||||
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 ({self.handle_prefix}->Instance == {instance})")
|
||||
else:
|
||||
get_lines.append(f" else if ({self.handle_prefix}->Instance == {instance})")
|
||||
get_lines.append(f" return {self.enum_prefix}_{name};")
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
template_content, f"AUTO GENERATED {self.enum_prefix.split('_')[1]}_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)
|
||||
)
|
||||
output_path = os.path.join(self.project_path, f"User/bsp/{self.template_names['source']}")
|
||||
return CodeGenerator.save_file(content, output_path)
|
||||
|
||||
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[self.yaml_key] = {
|
||||
'enabled': True,
|
||||
'devices': [{'name': name, 'instance': instance} for name, instance 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(self.yaml_key, {})
|
||||
if conf.get('enabled', False):
|
||||
self.generate_checkbox.setChecked(True)
|
||||
devices = conf.get('devices', [])
|
||||
for device in devices:
|
||||
if self.available_list:
|
||||
self._add_device()
|
||||
row = self.table.rowCount() - 1
|
||||
name_widget = self.table.cellWidget(row, 0)
|
||||
sel_widget = self.table.cellWidget(row, 1)
|
||||
if name_widget:
|
||||
name_widget.setText(device.get('name', ''))
|
||||
if sel_widget:
|
||||
instance = device.get('instance', '')
|
||||
if instance in self.available_list:
|
||||
sel_widget.setCurrentText(instance)
|
||||
|
||||
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 load_descriptions(csv_path):
|
||||
descriptions = {}
|
||||
if os.path.exists(csv_path):
|
||||
with open(csv_path, encoding='utf-8') as f:
|
||||
reader = csv.reader(f)
|
||||
for row in reader:
|
||||
if len(row) >= 2:
|
||||
key, desc = row[0].strip(), row[1].strip()
|
||||
descriptions[key.lower()] = desc
|
||||
return descriptions
|
||||
|
||||
# 各外设的可用列表获取函数
|
||||
def get_available_i2c(project_path):
|
||||
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_i2c_from_ioc(ioc_path)
|
||||
return []
|
||||
|
||||
def get_available_can(project_path):
|
||||
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_can_from_ioc(ioc_path)
|
||||
return []
|
||||
|
||||
def get_available_spi(project_path):
|
||||
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_spi_from_ioc(ioc_path)
|
||||
return []
|
||||
|
||||
def get_available_uart(project_path):
|
||||
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_uart_from_ioc(ioc_path)
|
||||
return []
|
||||
|
||||
def get_available_gpio(project_path):
|
||||
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_gpio_from_ioc(ioc_path)
|
||||
return []
|
||||
|
||||
# 具体外设类
|
||||
class bsp_i2c(BspPeripheralBase):
|
||||
def __init__(self, project_path):
|
||||
super().__init__(
|
||||
project_path,
|
||||
"I2C",
|
||||
{'header': 'i2c.h', 'source': 'i2c.c'},
|
||||
"BSP_I2C",
|
||||
"hi2c",
|
||||
"i2c",
|
||||
get_available_i2c
|
||||
)
|
||||
|
||||
class bsp_can(BspPeripheralBase):
|
||||
def __init__(self, project_path):
|
||||
super().__init__(
|
||||
project_path,
|
||||
"CAN",
|
||||
{'header': 'can.h', 'source': 'can.c'},
|
||||
"BSP_CAN",
|
||||
"hcan",
|
||||
"can",
|
||||
get_available_can
|
||||
)
|
||||
|
||||
class bsp_spi(BspPeripheralBase):
|
||||
def __init__(self, project_path):
|
||||
super().__init__(
|
||||
project_path,
|
||||
"SPI",
|
||||
{'header': 'spi.h', 'source': 'spi.c'},
|
||||
"BSP_SPI",
|
||||
"hspi",
|
||||
"spi",
|
||||
get_available_spi
|
||||
)
|
||||
|
||||
class bsp_uart(BspPeripheralBase):
|
||||
def __init__(self, project_path):
|
||||
super().__init__(
|
||||
project_path,
|
||||
"UART",
|
||||
{'header': 'uart.h', 'source': 'uart.c'},
|
||||
"BSP_UART",
|
||||
"huart",
|
||||
"uart",
|
||||
get_available_uart
|
||||
)
|
||||
|
||||
class bsp_gpio(QWidget):
|
||||
def __init__(self, project_path):
|
||||
super().__init__()
|
||||
self.project_path = project_path
|
||||
self.available_list = get_available_gpio(project_path)
|
||||
# 新增:加载描述
|
||||
describe_path = os.path.join(os.path.dirname(__file__), "../../assets/User_code/bsp/describe.csv")
|
||||
self.descriptions = load_descriptions(describe_path)
|
||||
self._init_ui()
|
||||
|
||||
def _init_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(TitleLabel("GPIO 配置"))
|
||||
# 新增:显示描述
|
||||
desc = self.descriptions.get("gpio", "")
|
||||
if desc:
|
||||
layout.addWidget(BodyLabel(f"功能说明:{desc}"))
|
||||
self.generate_checkbox = QCheckBox("生成 GPIO 代码")
|
||||
layout.addWidget(self.generate_checkbox)
|
||||
if not self.available_list:
|
||||
layout.addWidget(BodyLabel("在 .ioc 文件中未找到可用的 GPIO"))
|
||||
else:
|
||||
self.table = QTableWidget(len(self.available_list), 1)
|
||||
self.table.setHorizontalHeaderLabels(["Label"])
|
||||
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
for row, item in enumerate(self.available_list):
|
||||
from PyQt5.QtWidgets import QTableWidgetItem
|
||||
self.table.setItem(row, 0, QTableWidgetItem(item['label']))
|
||||
self.table.setEditTriggers(QTableWidget.NoEditTriggers)
|
||||
layout.addWidget(self.table)
|
||||
|
||||
def is_need_generate(self):
|
||||
return self.generate_checkbox.isChecked() and bool(self.available_list)
|
||||
|
||||
def _generate_bsp_code_internal(self):
|
||||
if not self.is_need_generate():
|
||||
return False
|
||||
template_dir = CodeGenerator.get_template_dir()
|
||||
if not self._generate_header_file(template_dir):
|
||||
return False
|
||||
if not self._generate_source_file(template_dir):
|
||||
return False
|
||||
self._save_config()
|
||||
return True
|
||||
|
||||
def _generate_header_file(self, template_dir):
|
||||
template_path = os.path.join(template_dir, "gpio.h")
|
||||
template_content = CodeGenerator.load_template(template_path)
|
||||
if not template_content:
|
||||
return False
|
||||
# 如有需要可在此处插入自动生成内容
|
||||
output_path = os.path.join(self.project_path, "User/bsp/gpio.h")
|
||||
return CodeGenerator.save_file(template_content, output_path)
|
||||
|
||||
def _generate_source_file(self, template_dir):
|
||||
template_path = os.path.join(template_dir, "gpio.c")
|
||||
template_content = CodeGenerator.load_template(template_path)
|
||||
if not template_content:
|
||||
return False
|
||||
# 生成 IRQ 使能/禁用代码
|
||||
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;")
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
template_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")
|
||||
return CodeGenerator.save_file(content, output_path)
|
||||
|
||||
def _save_config(self):
|
||||
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]
|
||||
}
|
||||
CodeGenerator.save_config(config_data, config_path)
|
||||
|
||||
|
||||
class bsp(QWidget):
|
||||
def __init__(self, project_path):
|
||||
super().__init__()
|
||||
self.project_path = project_path
|
||||
|
||||
@staticmethod
|
||||
def generate_bsp(project_path, pages):
|
||||
total = 0
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
fail_list = []
|
||||
for page in pages:
|
||||
name = page.objectName() if hasattr(page, "objectName") else str(page)
|
||||
if hasattr(page, "is_need_generate") and page.is_need_generate():
|
||||
total += 1
|
||||
try:
|
||||
result = page._generate_bsp_code_internal()
|
||||
if result:
|
||||
success_count += 1
|
||||
else:
|
||||
fail_count += 1
|
||||
fail_list.append(name)
|
||||
except Exception as e:
|
||||
fail_count += 1
|
||||
fail_list.append(f"{name} (异常: {e})")
|
||||
msg = f"总共尝试生成 {total} 项,成功 {success_count} 项,失败 {fail_count} 项。"
|
||||
if fail_list:
|
||||
msg += "\n失败项:\n" + "\n".join(fail_list)
|
||||
QMessageBox.information(None, "代码生成结果", msg)
|
0
app/code_page/device_interface.py
Normal file
0
app/code_page/device_interface.py
Normal file
0
app/code_page/module_interface.py
Normal file
0
app/code_page/module_interface.py
Normal file
@ -1,7 +1,146 @@
|
||||
|
||||
|
||||
class analyzing_ioc:
|
||||
def __init__(self, ioc_data): # 初始化方法,接收IOC数据
|
||||
self.ioc_data = ioc_data # 存储IOC数据
|
||||
@staticmethod
|
||||
def is_freertos_enabled_from_ioc(ioc_path):
|
||||
"""
|
||||
检查指定 .ioc 文件是否开启了 FreeRTOS
|
||||
"""
|
||||
config = {}
|
||||
with open(ioc_path, encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
config[key.strip()] = value.strip()
|
||||
ip_keys = [k for k in config if k.startswith('Mcu.IP')]
|
||||
for k in ip_keys:
|
||||
if config[k] == 'FREERTOS':
|
||||
return True
|
||||
for k in config:
|
||||
if k.startswith('FREERTOS.'):
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def get_enabled_i2c_from_ioc(ioc_path):
|
||||
"""
|
||||
从.ioc文件中获取已启用的I2C列表
|
||||
返回格式: ['I2C1', 'I2C3'] 等
|
||||
"""
|
||||
enabled_i2c = []
|
||||
with open(ioc_path, encoding='utf-8', errors='ignore') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
# 检查是否启用了I2C
|
||||
if key.startswith('Mcu.IP') and value.startswith('I2C'):
|
||||
# 提取I2C编号,如I2C1, I2C2等
|
||||
i2c_name = value.split('.')[0] if '.' in value else value
|
||||
if i2c_name not in enabled_i2c:
|
||||
enabled_i2c.append(i2c_name)
|
||||
return sorted(enabled_i2c)
|
||||
|
||||
@staticmethod
|
||||
def get_enabled_spi_from_ioc(ioc_path):
|
||||
"""
|
||||
获取已启用的SPI列表
|
||||
返回格式: ['SPI1', 'SPI2'] 等
|
||||
"""
|
||||
enabled_spi = []
|
||||
with open(ioc_path, encoding='utf-8', errors='ignore') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
if key.startswith('Mcu.IP') and value.startswith('SPI'):
|
||||
spi_name = value.split('.')[0] if '.' in value else value
|
||||
if spi_name not in enabled_spi:
|
||||
enabled_spi.append(spi_name)
|
||||
return sorted(enabled_spi)
|
||||
|
||||
@staticmethod
|
||||
def get_enabled_can_from_ioc(ioc_path):
|
||||
"""
|
||||
获取已启用的CAN列表
|
||||
返回格式: ['CAN1', 'CAN2'] 等
|
||||
"""
|
||||
enabled_can = []
|
||||
with open(ioc_path, encoding='utf-8', errors='ignore') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
if key.startswith('Mcu.IP') and value.startswith('CAN'):
|
||||
can_name = value.split('.')[0] if '.' in value else value
|
||||
if can_name not in enabled_can:
|
||||
enabled_can.append(can_name)
|
||||
return sorted(enabled_can)
|
||||
|
||||
@staticmethod
|
||||
def get_enabled_uart_from_ioc(ioc_path):
|
||||
"""
|
||||
获取已启用的UART/USART列表
|
||||
返回格式: ['USART1', 'USART2', 'UART4'] 等
|
||||
"""
|
||||
enabled_uart = []
|
||||
with open(ioc_path, encoding='utf-8', errors='ignore') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
# 检查是否启用了UART或USART
|
||||
if key.startswith('Mcu.IP') and (value.startswith('USART') or value.startswith('UART')):
|
||||
uart_name = value.split('.')[0] if '.' in value else value
|
||||
if uart_name not in enabled_uart:
|
||||
enabled_uart.append(uart_name)
|
||||
return sorted(enabled_uart)
|
||||
|
||||
@staticmethod
|
||||
def get_enabled_gpio_from_ioc(ioc_path):
|
||||
"""
|
||||
获取所有带 EXTI 且有 Label 的 GPIO,返回 [{'pin': 'PC4', 'label': 'ACCL_INT'}, ...]
|
||||
"""
|
||||
gpio_list = []
|
||||
gpio_params = {}
|
||||
with open(ioc_path, encoding='utf-8', errors='ignore') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
if '.GPIOParameters' in key:
|
||||
gpio_params[key.split('.')[0]] = value
|
||||
elif '.GPIO_Label' in key:
|
||||
pin = key.split('.')[0]
|
||||
gpio_params[f"{pin}_label"] = value
|
||||
elif '.GPIO_ModeDefaultEXTI' in key:
|
||||
pin = key.split('.')[0]
|
||||
gpio_params[f"{pin}_exti"] = value
|
||||
for pin in gpio_params:
|
||||
if not pin.endswith('_label') and not pin.endswith('_exti'):
|
||||
label = gpio_params.get(f"{pin}_label", None)
|
||||
exti = gpio_params.get(f"{pin}_exti", None)
|
||||
if label and exti:
|
||||
gpio_list.append({'pin': pin, 'label': label})
|
||||
return gpio_list
|
75
app/tools/code_generator.py
Normal file
75
app/tools/code_generator.py
Normal file
@ -0,0 +1,75 @@
|
||||
import os
|
||||
import yaml
|
||||
import shutil
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
class CodeGenerator:
|
||||
"""通用代码生成器"""
|
||||
|
||||
@staticmethod
|
||||
def load_template(template_path: str) -> str:
|
||||
"""加载代码模板"""
|
||||
try:
|
||||
with open(template_path, 'r', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
except Exception as e:
|
||||
print(f"加载模板失败: {template_path}, 错误: {e}")
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def replace_auto_generated(content: str, marker: str, replacement: str) -> str:
|
||||
"""替换自动生成的代码标记"""
|
||||
marker_line = f"/* {marker} */"
|
||||
if marker_line in content:
|
||||
return content.replace(marker_line, replacement)
|
||||
return content
|
||||
|
||||
@staticmethod
|
||||
def save_file(content: str, file_path: str) -> bool:
|
||||
"""保存文件"""
|
||||
try:
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"保存文件失败: {file_path}, 错误: {e}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def load_config(config_path: str) -> Dict:
|
||||
"""加载配置文件"""
|
||||
if os.path.exists(config_path):
|
||||
try:
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
return yaml.safe_load(f) or {}
|
||||
except Exception as e:
|
||||
print(f"加载配置失败: {config_path}, 错误: {e}")
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def save_config(config: Dict, config_path: str) -> bool:
|
||||
"""保存配置文件"""
|
||||
try:
|
||||
os.makedirs(os.path.dirname(config_path), exist_ok=True)
|
||||
with open(config_path, 'w', encoding='utf-8') as f:
|
||||
yaml.safe_dump(config, f, allow_unicode=True, default_flow_style=False)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"保存配置失败: {config_path}, 错误: {e}")
|
||||
return False
|
||||
|
||||
@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")
|
||||
else:
|
||||
# 如果找不到,使用相对路径作为备选
|
||||
return os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "assets/User_code/bsp")
|
BIN
assets/User_code/.DS_Store
vendored
BIN
assets/User_code/.DS_Store
vendored
Binary file not shown.
@ -1,32 +0,0 @@
|
||||
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include <gpio.h>
|
||||
#include "bsp/bsp.h"
|
||||
#include "bsp/buzzer_gpio.h"
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
#define BSP_BUZZER_GPIO GPIOA
|
||||
#define BSP_BUZZER_PIN GPIO_PIN_1
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
/* Private function --------------------------------------------------------- */
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
int8_t BSP_Buzzer_Set(BSP_Buzzer_Status_t s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case BSP_BUZZER_ON:
|
||||
HAL_GPIO_WritePin(BSP_BUZZER_GPIO, BSP_BUZZER_PIN, GPIO_PIN_SET); // 打开蜂鸣器
|
||||
break;
|
||||
case BSP_BUZZER_OFF:
|
||||
HAL_GPIO_WritePin(BSP_BUZZER_GPIO, BSP_BUZZER_PIN, GPIO_PIN_RESET); // 关闭蜂鸣器
|
||||
break;
|
||||
case BSP_BUZZER_TAGGLE:
|
||||
HAL_GPIO_TogglePin(BSP_BUZZER_GPIO, BSP_BUZZER_PIN); // 切换蜂鸣器状态
|
||||
break;
|
||||
default:
|
||||
return BSP_ERR;
|
||||
}
|
||||
return BSP_OK;
|
||||
}
|
@ -9,10 +9,7 @@ static void (*CAN_Callback[BSP_CAN_NUM][BSP_CAN_CB_NUM])(void);
|
||||
|
||||
/* Private function -------------------------------------------------------- */
|
||||
static BSP_CAN_t CAN_Get(CAN_HandleTypeDef *hcan) {
|
||||
if (hcan->Instance == CAN2)
|
||||
return BSP_CAN_2;
|
||||
else if (hcan->Instance == CAN1)
|
||||
return BSP_CAN_1;
|
||||
/* AUTO GENERATED CAN_GET */
|
||||
else
|
||||
return BSP_CAN_ERR;
|
||||
}
|
||||
@ -124,10 +121,7 @@ void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) {
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
CAN_HandleTypeDef *BSP_CAN_GetHandle(BSP_CAN_t can) {
|
||||
switch (can) {
|
||||
case BSP_CAN_2:
|
||||
return &hcan2;
|
||||
case BSP_CAN_1:
|
||||
return &hcan1;
|
||||
/* AUTO GENERATED BSP_CAN_GET_HANDLE */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ extern "C" {
|
||||
/* Exported macro ----------------------------------------------------------- */
|
||||
/* Exported types ----------------------------------------------------------- */
|
||||
typedef enum {
|
||||
BSP_CAN_1,
|
||||
BSP_CAN_2,
|
||||
/* AUTO GENERATED BSP_CAN_NAME */
|
||||
BSP_CAN_NUM,
|
||||
BSP_CAN_ERR,
|
||||
} BSP_CAN_t;
|
||||
|
@ -1,118 +1,34 @@
|
||||
#include "bsp_delay.h"
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "bsp/delay.h"
|
||||
|
||||
#include "cmsis_os.h"
|
||||
#include "main.h"
|
||||
#include <cmsis_os2.h>
|
||||
#include <main.h>
|
||||
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
static uint8_t fac_us = 0;
|
||||
static uint32_t fac_ms = 0;
|
||||
/* Private function -------------------------------------------------------- */
|
||||
static void delay_ticks(uint32_t ticks)
|
||||
{
|
||||
uint32_t told = SysTick->VAL;
|
||||
uint32_t tnow = 0;
|
||||
uint32_t tcnt = 0;
|
||||
uint32_t reload = SysTick->LOAD;
|
||||
while (1)
|
||||
{
|
||||
tnow = SysTick->VAL;
|
||||
if (tnow != told)
|
||||
{
|
||||
if (tnow < told)
|
||||
{
|
||||
tcnt += told - tnow;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcnt += reload - tnow + told;
|
||||
}
|
||||
told = tnow;
|
||||
if (tcnt >= ticks)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
int8_t BSP_Delay(uint32_t ms) {
|
||||
uint32_t tick_period = 1000u / osKernelGetTickFreq();
|
||||
uint32_t ticks = ms / tick_period;
|
||||
|
||||
/**
|
||||
* @brief 毫秒延时函数
|
||||
* @param ms
|
||||
* @return
|
||||
*/
|
||||
int8_t BSP_Delay(uint32_t ms)
|
||||
{
|
||||
uint32_t tick_period = 1000u / osKernelGetTickFreq();
|
||||
uint32_t ticks = ms / tick_period;
|
||||
|
||||
switch (osKernelGetState())
|
||||
{
|
||||
switch (osKernelGetState()) {
|
||||
case osKernelError:
|
||||
case osKernelReserved:
|
||||
case osKernelLocked:
|
||||
case osKernelSuspended:
|
||||
return BSP_ERR;
|
||||
return BSP_ERR;
|
||||
|
||||
case osKernelRunning:
|
||||
osDelay(ticks ? ticks : 1);
|
||||
break;
|
||||
osDelay(ticks ? ticks : 1);
|
||||
break;
|
||||
|
||||
case osKernelInactive:
|
||||
case osKernelReady:
|
||||
HAL_Delay(ms);
|
||||
break;
|
||||
}
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 延时初始化
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
int8_t BSP_Delay_Init(void)
|
||||
{
|
||||
if (SystemCoreClock == 0)
|
||||
{
|
||||
return BSP_ERR;
|
||||
}
|
||||
fac_us = SystemCoreClock / 1000000;
|
||||
fac_ms = SystemCoreClock / 1000;
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 微秒延时,注意:此函数会阻塞当前线程,直到延时结束,并且会被中断打断
|
||||
* @param us
|
||||
* @return
|
||||
*/
|
||||
int8_t BSP_Delay_us(uint32_t us)
|
||||
{
|
||||
if (fac_us == 0)
|
||||
{
|
||||
return BSP_ERR;
|
||||
}
|
||||
uint32_t ticks = us * fac_us;
|
||||
delay_ticks(ticks);
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 毫秒延时,注意:此函数会阻塞当前线程,直到延时结束,并且会被中断打断
|
||||
* @param ms
|
||||
* @return
|
||||
*/
|
||||
int8_t BSP_Delay_ms(uint32_t ms)
|
||||
{
|
||||
if (fac_ms == 0)
|
||||
{
|
||||
return BSP_ERR;
|
||||
}
|
||||
uint32_t ticks = ms * fac_ms;
|
||||
delay_ticks(ticks);
|
||||
return BSP_OK;
|
||||
HAL_Delay(ms);
|
||||
break;
|
||||
}
|
||||
return BSP_OK;
|
||||
}
|
||||
|
@ -1,34 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "bsp\delay.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
#include <main.h>
|
||||
#include "bsp/bsp.h"
|
||||
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
/* Private function -------------------------------------------------------- */
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
int8_t BSP_Delay(uint32_t ms) {
|
||||
uint32_t tick_period = 1000u / osKernelGetTickFreq();
|
||||
uint32_t ticks = ms / tick_period;
|
||||
/* Exported constants ------------------------------------------------------- */
|
||||
/* Exported macro ----------------------------------------------------------- */
|
||||
/* Exported types ----------------------------------------------------------- */
|
||||
/* Exported functions prototypes -------------------------------------------- */
|
||||
int8_t BSP_Delay(uint32_t ms);
|
||||
|
||||
switch (osKernelGetState()) {
|
||||
case osKernelError:
|
||||
case osKernelReserved:
|
||||
case osKernelLocked:
|
||||
case osKernelSuspended:
|
||||
return BSP_ERR;
|
||||
|
||||
case osKernelRunning:
|
||||
osDelay(ticks ? ticks : 1);
|
||||
break;
|
||||
|
||||
case osKernelInactive:
|
||||
case osKernelReady:
|
||||
HAL_Delay(ms);
|
||||
break;
|
||||
}
|
||||
return BSP_OK;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,2 +0,0 @@
|
||||
i2c,I2C
|
||||
uart,USART,UART
|
|
@ -1,3 +1,5 @@
|
||||
uart,要求开启dma和中断
|
||||
can,要求开启can的中断
|
||||
delay,暂时只有delay_ms函数
|
||||
gpio,要求设置label开启中断
|
||||
spi,要求开启spi中断
|
||||
i2c,要求开始spi中断
|
|
53
assets/User_code/bsp/gpio.c
Normal file
53
assets/User_code/bsp/gpio.c
Normal file
@ -0,0 +1,53 @@
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "bsp/gpio.h"
|
||||
|
||||
#include <gpio.h>
|
||||
#include <main.h>
|
||||
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
static void (*GPIO_Callback[16])(void);
|
||||
|
||||
/* Private function -------------------------------------------------------- */
|
||||
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
if (GPIO_Pin & (1 << i)) {
|
||||
if (GPIO_Callback[i]) {
|
||||
GPIO_Callback[i]();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
int8_t BSP_GPIO_RegisterCallback(uint16_t pin, void (*callback)(void)) {
|
||||
if (callback == NULL) return BSP_ERR_NULL;
|
||||
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
if (pin & (1 << i)) {
|
||||
GPIO_Callback[i] = callback;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
int8_t BSP_GPIO_EnableIRQ(uint16_t pin) {
|
||||
switch (pin) {
|
||||
/* AUTO GENERATED BSP_GPIO_ENABLE_IRQ */
|
||||
default:
|
||||
return BSP_ERR;
|
||||
}
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
int8_t BSP_GPIO_DisableIRQ(uint16_t pin) {
|
||||
switch (pin) {
|
||||
/* AUTO GENERATED BSP_GPIO_DISABLE_IRQ */
|
||||
default:
|
||||
return BSP_ERR;
|
||||
}
|
||||
return BSP_OK;
|
||||
}
|
@ -12,25 +12,11 @@ extern "C" {
|
||||
/* Exported constants ------------------------------------------------------- */
|
||||
/* Exported macro ----------------------------------------------------------- */
|
||||
/* Exported types ----------------------------------------------------------- */
|
||||
|
||||
/* GPIO设备枚举,与设备对应 */
|
||||
typedef enum {
|
||||
BSP_GPIO_USER_KEY,
|
||||
/* BSP_GPIO_XXX, */
|
||||
BSP_GPIO_NUM,
|
||||
BSP_GPIO_ERR,
|
||||
} BSP_GPIO_t;
|
||||
|
||||
/* GPIO支持的中断回调函数类型 */
|
||||
typedef enum {
|
||||
BSP_GPIO_EXTI_CB,
|
||||
BSP_GPIO_CB_NUM,
|
||||
} BSP_GPIO_Callback_t;
|
||||
|
||||
/* Exported functions prototypes -------------------------------------------- */
|
||||
int8_t BSP_GPIO_RegisterCallback(BSP_GPIO_t gpio, BSP_GPIO_Callback_t type, void (*callback)(void));
|
||||
int8_t BSP_GPIO_EnableIRQ(BSP_GPIO_t gpio);
|
||||
int8_t BSP_GPIO_DisableIRQ(BSP_GPIO_t gpio);
|
||||
int8_t BSP_GPIO_RegisterCallback(uint16_t pin, void (*callback)(void));
|
||||
|
||||
int8_t BSP_GPIO_EnableIRQ(uint16_t pin);
|
||||
int8_t BSP_GPIO_DisableIRQ(uint16_t pin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "bsp\gpio.h"
|
||||
|
||||
#include <gpio.h>
|
||||
#include <main.h>
|
||||
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
static void (*GPIO_Callback[BSP_GPIO_NUM][BSP_GPIO_CB_NUM])(void);
|
||||
|
||||
/* Private function -------------------------------------------------------- */
|
||||
static BSP_GPIO_t GPIO_Get(uint16_t pin) {
|
||||
switch (pin) {
|
||||
case USER_KEY_Pin:
|
||||
return BSP_GPIO_USER_KEY;
|
||||
/* case XXX_Pin:
|
||||
return BSP_GPIO_XXX; */
|
||||
default:
|
||||
return BSP_GPIO_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
|
||||
BSP_GPIO_t gpio = GPIO_Get(GPIO_Pin);
|
||||
if (gpio != BSP_GPIO_ERR) {
|
||||
if (GPIO_Callback[gpio][BSP_GPIO_EXTI_CB]) {
|
||||
GPIO_Callback[gpio][BSP_GPIO_EXTI_CB]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
int8_t BSP_GPIO_RegisterCallback(BSP_GPIO_t gpio, BSP_GPIO_Callback_t type, void (*callback)(void)) {
|
||||
if (callback == NULL || gpio >= BSP_GPIO_NUM || type >= BSP_GPIO_CB_NUM) return BSP_ERR_NULL;
|
||||
|
||||
GPIO_Callback[gpio][type] = callback;
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
int8_t BSP_GPIO_EnableIRQ(BSP_GPIO_t gpio) {
|
||||
switch (gpio) {
|
||||
case BSP_GPIO_USER_KEY:
|
||||
HAL_NVIC_EnableIRQ(USER_KEY_EXTI_IRQn);
|
||||
break;
|
||||
|
||||
/* case BSP_GPIO_XXX:
|
||||
HAL_NVIC_EnableIRQ(XXX_IRQn);
|
||||
break; */
|
||||
|
||||
default:
|
||||
return BSP_ERR;
|
||||
}
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
int8_t BSP_GPIO_DisableIRQ(BSP_GPIO_t gpio) {
|
||||
switch (gpio) {
|
||||
case BSP_GPIO_USER_KEY:
|
||||
HAL_NVIC_DisableIRQ(USER_KEY_EXTI_IRQn);
|
||||
break;
|
||||
|
||||
/* case BSP_GPIO_XXX:
|
||||
HAL_NVIC_DisableIRQ(XXX_IRQn);
|
||||
break; */
|
||||
|
||||
default:
|
||||
return BSP_ERR;
|
||||
}
|
||||
return BSP_OK;
|
||||
}
|
@ -9,10 +9,7 @@ static void (*I2C_Callback[BSP_I2C_NUM][BSP_I2C_CB_NUM])(void);
|
||||
|
||||
/* Private function -------------------------------------------------------- */
|
||||
static BSP_I2C_t I2C_Get(I2C_HandleTypeDef *hi2c) {
|
||||
if (hi2c->Instance == I2C1)
|
||||
return BSP_I2C_EXAMPLE;
|
||||
// else if (hi2c->Instance == I2CX)
|
||||
// return BSP_I2C_XXX;
|
||||
/* AUTO GENERATED I2C_GET */
|
||||
else
|
||||
return BSP_I2C_ERR;
|
||||
}
|
||||
@ -92,10 +89,7 @@ void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c) {
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
I2C_HandleTypeDef *BSP_I2C_GetHandle(BSP_I2C_t i2c) {
|
||||
switch (i2c) {
|
||||
case BSP_I2C_EXAMPLE:
|
||||
return &hi2c1;
|
||||
// case BSP_I2C_XXX:
|
||||
// return &hi2cX;
|
||||
/* AUTO GENERATED BSP_I2C_GET_HANDLE */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -17,8 +17,10 @@ extern "C" {
|
||||
|
||||
/* I2C实体枚举,与设备对应 */
|
||||
typedef enum {
|
||||
BSP_I2C_EXAMPLE,
|
||||
/* BSP_I2C_XXX,*/
|
||||
/* AUTO GENERATED BSP_I2C_NAME */
|
||||
/* USER BSP_I2C END*/
|
||||
/* USER_I2C_XXX */
|
||||
/* USER BSP_I2C END */
|
||||
BSP_I2C_NUM,
|
||||
BSP_I2C_ERR,
|
||||
} BSP_I2C_t;
|
||||
|
@ -1,50 +0,0 @@
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "bsp/led_gpio.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include <gpio.h>
|
||||
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
static uint32_t led_stats; // 使用位掩码记录每个通道的状态,最多支持32LED
|
||||
|
||||
// 定义 LED 引脚和端口映射表:需要根据自己的修改,添加,或删减。
|
||||
static const BSP_LED_Config_t LED_CONFIGS[] = {
|
||||
{GPIOA, GPIO_PIN_2}, // BSP_LED_1
|
||||
{GPIOA, GPIO_PIN_3}, // BSP_LED_2
|
||||
{GPIOA, GPIO_PIN_4}, // BSP_LED_3
|
||||
};
|
||||
|
||||
#define LED_CHANNEL_COUNT (sizeof(LED_CONFIGS) / sizeof(LED_CONFIGS[0])) // 通道数量
|
||||
|
||||
/* Private function --------------------------------------------------------- */
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
int8_t BSP_LED_Set(BSP_LED_Channel_t ch, BSP_LED_Status_t s)
|
||||
{
|
||||
if (ch < LED_CHANNEL_COUNT)
|
||||
{
|
||||
GPIO_TypeDef *port = LED_CONFIGS[ch].port;
|
||||
uint16_t pin = LED_CONFIGS[ch].pin;
|
||||
switch (s)
|
||||
{
|
||||
case BSP_LED_ON:
|
||||
led_stats |= (1 << ch);
|
||||
HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); // 点亮LED
|
||||
break;
|
||||
case BSP_LED_OFF:
|
||||
led_stats &= ~(1 << ch);
|
||||
HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET); // 熄灭LED
|
||||
break;
|
||||
case BSP_LED_TAGGLE:
|
||||
led_stats ^= (1 << ch);
|
||||
HAL_GPIO_TogglePin(port, pin); // 切换LED状态
|
||||
break;
|
||||
default:
|
||||
return BSP_ERR;
|
||||
}
|
||||
return BSP_OK;
|
||||
}
|
||||
return BSP_ERR;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include <stdint.h>
|
||||
#include "gpio.h"
|
||||
/* Exported constants ------------------------------------------------------- */
|
||||
/* Exported macro ----------------------------------------------------------- */
|
||||
/* Exported types ----------------------------------------------------------- */
|
||||
|
||||
/* LED灯状态,设置用 */
|
||||
typedef enum
|
||||
{
|
||||
BSP_LED_ON,
|
||||
BSP_LED_OFF,
|
||||
BSP_LED_TAGGLE,
|
||||
} BSP_LED_Status_t;
|
||||
|
||||
/* LED通道 */
|
||||
typedef enum
|
||||
{
|
||||
BSP_LED_1,
|
||||
BSP_LED_2,
|
||||
BSP_LED_3,
|
||||
/*BSP_LED_XXX*/
|
||||
} BSP_LED_Channel_t;
|
||||
|
||||
/* LED GPIO 配置 */
|
||||
typedef struct
|
||||
{
|
||||
GPIO_TypeDef *port; // GPIO 端口 (如 GPIOA, GPIOB)
|
||||
uint16_t pin; // GPIO 引脚
|
||||
} BSP_LED_Config_t;
|
||||
|
||||
/* Exported functions prototypes -------------------------------------------- */
|
||||
|
||||
int8_t BSP_LED_Set(BSP_LED_Channel_t ch, BSP_LED_Status_t s);
|
14
assets/User_code/bsp/mm.c
Normal file
14
assets/User_code/bsp/mm.c
Normal file
@ -0,0 +1,14 @@
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "bsp\mm.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
/* Private function -------------------------------------------------------- */
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
inline void *BSP_Malloc(size_t size) { return pvPortMalloc(size); }
|
||||
|
||||
inline void BSP_Free(void *pv) { vPortFree(pv); }
|
@ -1,20 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Exported constants ------------------------------------------------------- */
|
||||
/* Exported macro ----------------------------------------------------------- */
|
||||
/* Exported types ----------------------------------------------------------- */
|
||||
|
||||
/* 设置BUZZER状态 */
|
||||
typedef enum
|
||||
{
|
||||
BSP_BUZZER_ON,
|
||||
BSP_BUZZER_OFF,
|
||||
BSP_BUZZER_TAGGLE,
|
||||
} BSP_Buzzer_Status_t;
|
||||
|
||||
/* Exported functions prototypes -------------------------------------------- */
|
||||
void *BSP_Malloc(size_t size);
|
||||
void BSP_Free(void *pv);
|
||||
|
||||
int8_t BSP_Buzzer_Set(BSP_Buzzer_Status_t s);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -9,12 +9,7 @@ static void (*SPI_Callback[BSP_SPI_NUM][BSP_SPI_CB_NUM])(void);
|
||||
|
||||
/* Private function -------------------------------------------------------- */
|
||||
static BSP_SPI_t SPI_Get(SPI_HandleTypeDef *hspi) {
|
||||
if (hspi->Instance == SPI1)
|
||||
return BSP_SPI_EXAMPLE;
|
||||
/*
|
||||
else if (hspi->Instance == SPIX)
|
||||
return BSP_SPI_XXX;
|
||||
*/
|
||||
/* AUTO GENERATED SPI_GET */
|
||||
else
|
||||
return BSP_SPI_ERR;
|
||||
}
|
||||
@ -87,12 +82,7 @@ void HAL_SPI_AbortCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
SPI_HandleTypeDef *BSP_SPI_GetHandle(BSP_SPI_t spi) {
|
||||
switch (spi) {
|
||||
case BSP_SPI_EXAMPLE:
|
||||
return &hspi1;
|
||||
/*
|
||||
case BSP_SPI_XXX:
|
||||
return &hspiX;
|
||||
*/
|
||||
/* AUTO GENERATED BSP_SPI_GET_HANDLE */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ extern "C" {
|
||||
|
||||
/* SPI实体枚举,与设备对应 */
|
||||
typedef enum {
|
||||
BSP_SPI_EXAMPLE,
|
||||
/* BSP_SPI_XXX,*/
|
||||
/* AUTO GENERATED BSP_SPI_NAME */
|
||||
BSP_SPI_NUM,
|
||||
BSP_SPI_ERR,
|
||||
} BSP_SPI_t;
|
||||
|
@ -9,10 +9,7 @@ static void (*UART_Callback[BSP_UART_NUM][BSP_UART_CB_NUM])(void);
|
||||
|
||||
/* Private function -------------------------------------------------------- */
|
||||
static BSP_UART_t UART_Get(UART_HandleTypeDef *huart) {
|
||||
if (huart->Instance == USART1)
|
||||
return BSP_UART_EXAMPLE;
|
||||
// else if (huart->Instance == USARTX)
|
||||
// return BSP_UART_XXX;
|
||||
/* AUTO GENERATED UART_GET */
|
||||
else
|
||||
return BSP_UART_ERR;
|
||||
}
|
||||
@ -101,10 +98,7 @@ void BSP_UART_IRQHandler(UART_HandleTypeDef *huart) {
|
||||
|
||||
UART_HandleTypeDef *BSP_UART_GetHandle(BSP_UART_t uart) {
|
||||
switch (uart) {
|
||||
case BSP_UART_EXAMPLE:
|
||||
return &huart1;
|
||||
// case BSP_UART_XXX:
|
||||
// return &huartX;
|
||||
/* AUTO GENERATED BSP_UART_GET_HANDLE */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ extern "C" {
|
||||
|
||||
/* UART实体枚举,与设备对应 */
|
||||
typedef enum {
|
||||
BSP_UART_EXAMPLE,
|
||||
/*BSP_UART_XXX*/
|
||||
/* AUTO GENERATED BSP_UART_NAME */
|
||||
BSP_UART_NUM,
|
||||
BSP_UART_ERR,
|
||||
} BSP_UART_t;
|
||||
|
4
assets/User_code/config.csv
Normal file
4
assets/User_code/config.csv
Normal file
@ -0,0 +1,4 @@
|
||||
bsp,can,delay,dwt,,gpio,i2c,mm,spi,uart,
|
||||
component,peripheral,driver,library,hal,freertos,stm32cube
|
||||
device,dr16,ai,nuc
|
||||
module,chassis,gimbal,arm,shoot
|
|
Loading…
Reference in New Issue
Block a user