重构完代码结构了

This commit is contained in:
2025-07-26 01:22:52 +08:00
parent 47e0b8419f
commit 501a9ddff4
108 changed files with 224 additions and 2017 deletions

Binary file not shown.

Binary file not shown.

20
app/tools/code_utils.py Normal file
View File

@@ -0,0 +1,20 @@
import re
def preserve_user_region(new_code, old_code, region_name):
"""
替换 new_code 中 region_name 区域为 old_code 中的内容(如果有)
region_name: 如 'USER INCLUDE'
"""
pattern = re.compile(
rf"/\*\s*{region_name}\s*BEGIN\s*\*/(.*?)/\*\s*{region_name}\s*END\s*\*/",
re.DOTALL
)
old_match = pattern.search(old_code or "")
if not old_match:
return new_code # 旧文件没有该区域,直接返回新代码
old_content = old_match.group(1)
def repl(m):
return m.group(0).replace(m.group(1), old_content)
# 替换新代码中的该区域
return pattern.sub(repl, new_code, count=1)

25
app/tools/ioc_config.py Normal file
View File

@@ -0,0 +1,25 @@
class IocConfig:
def __init__(self, ioc_path):
self.ioc_path = ioc_path
self.config = {}
self._parse()
def _parse(self):
with open(self.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)
self.config[key.strip()] = value.strip()
def is_freertos_enabled(self):
ip_keys = [k for k in self.config if k.startswith('Mcu.IP')]
for k in ip_keys:
if self.config[k] == 'FREERTOS':
return True
for k in self.config:
if k.startswith('FREERTOS.'):
return True
return False

View File

@@ -0,0 +1,109 @@
import os
import yaml
import textwrap
from jinja2 import Template
from .code_utils import preserve_user_region
def generate_task_code(task_list, project_path):
# base_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
template_dir = os.path.join(project_root, "User_code", "task")
output_dir = os.path.join(project_path, "User", "task")
os.makedirs(output_dir, exist_ok=True)
user_task_h_tpl = os.path.join(template_dir, "user_task.h.template")
user_task_c_tpl = os.path.join(template_dir, "user_task.c.template")
init_c_tpl = os.path.join(template_dir, "init.c.template")
task_c_tpl = os.path.join(template_dir, "task.c.template")
freq_tasks = [t for t in task_list if t.get("freq_control", True)]
def render_template(path, context):
with open(path, encoding="utf-8") as f:
tpl = Template(f.read())
return tpl.render(**context)
context_h = {
"thread_definitions": "\n".join([f" osThreadId_t {t['name']};" for t in task_list]),
"freq_definitions": "\n".join([f" float {t['name']};" for t in freq_tasks]),
"stack_definitions": "\n".join([f" UBaseType_t {t['name']};" for t in task_list]),
"last_up_time_definitions": "\n".join([f" float {t['name']};" for t in freq_tasks]),
"task_frequency_definitions": "\n".join([f"#define {t['name'].upper()}_FREQ ({t['frequency']})" for t in freq_tasks]),
"task_init_delay_definitions": "\n".join([f"#define {t['name'].upper()}_INIT_DELAY ({t['delay']})" for t in task_list]),
"task_attr_declarations": "\n".join([f"extern const osThreadAttr_t attr_{t['name']};" for t in task_list]),
"task_function_declarations": "\n".join([f"void {t['function']}(void *argument);" for t in task_list]),
}
# ----------- 生成 user_task.h -----------
user_task_h_path = os.path.join(output_dir, "user_task.h")
new_user_task_h = render_template(user_task_h_tpl, context_h)
if os.path.exists(user_task_h_path):
with open(user_task_h_path, "r", encoding="utf-8") as f:
old_code = f.read()
for region in ["USER INCLUDE", "USER MESSAGE", "USER CONFIG"]:
new_user_task_h = preserve_user_region(new_user_task_h, old_code, region)
with open(user_task_h_path, "w", encoding="utf-8") as f:
f.write(new_user_task_h)
# ----------- 生成 user_task.c -----------
context_c = {
"task_attr_definitions": "\n".join([
f"const osThreadAttr_t attr_{t['name']} = {{\n"
f" .name = \"{t['name']}\",\n"
f" .priority = osPriorityNormal,\n"
f" .stack_size = {t['stack']} * 4,\n"
f"}};"
for t in task_list
])
}
user_task_c = render_template(user_task_c_tpl, context_c)
with open(os.path.join(output_dir, "user_task.c"), "w", encoding="utf-8") as f:
f.write(user_task_c)
# ----------- 生成 init.c -----------
thread_creation_code = "\n".join([
f" task_runtime.thread.{t['name']} = osThreadNew({t['function']}, NULL, &attr_{t['name']});"
for t in task_list
])
context_init = {
"thread_creation_code": thread_creation_code,
}
init_c = render_template(init_c_tpl, context_init)
init_c_path = os.path.join(output_dir, "init.c")
if os.path.exists(init_c_path):
with open(init_c_path, "r", encoding="utf-8") as f:
old_code = f.read()
for region in ["USER INCLUDE", "USER CODE", "USER CODE INIT"]:
init_c = preserve_user_region(init_c, old_code, region)
with open(init_c_path, "w", encoding="utf-8") as f:
f.write(init_c)
# ----------- 生成 task.c -----------
for t in task_list:
desc = t.get("description", "")
desc_wrapped = "\n ".join(textwrap.wrap(desc, 20))
context_task = {
"task_name": t["name"],
"task_function": t["function"],
"task_frequency": f"{t['name'].upper()}_FREQ" if t.get("freq_control", True) else None,
"task_delay": f"{t['name'].upper()}_INIT_DELAY",
"task_description": desc_wrapped,
"freq_control": t.get("freq_control", True)
}
with open(task_c_tpl, encoding="utf-8") as f:
tpl = Template(f.read())
code = tpl.render(**context_task)
task_c_path = os.path.join(output_dir, f"{t['name']}.c")
if os.path.exists(task_c_path):
with open(task_c_path, "r", encoding="utf-8") as f:
old_code = f.read()
for region in ["USER INCLUDE", "USER STRUCT", "USER CODE", "USER CODE INIT"]:
code = preserve_user_region(code, old_code, region)
with open(task_c_path, "w", encoding="utf-8") as f:
f.write(code)
# ----------- 保存任务配置到 config.yaml -----------
config_yaml_path = os.path.join(output_dir, "config.yaml")
with open(config_yaml_path, "w", encoding="utf-8") as f:
yaml.safe_dump(task_list, f, allow_unicode=True)

View File

@@ -1,114 +0,0 @@
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout
from qfluentwidgets import TitleLabel, BodyLabel, TableWidget, PushButton, SubtitleLabel, SpinBox, InfoBar, InfoBarPosition, LineEdit, CheckBox
from PyQt5.QtCore import Qt
import yaml
import os
class TaskConfigDialog(QDialog):
def __init__(self, parent=None, config_path=None):
super().__init__(parent)
self.setWindowTitle("任务配置")
self.resize(900, 480)
layout = QVBoxLayout(self)
layout.setContentsMargins(32, 32, 32, 32)
layout.setSpacing(18)
layout.addWidget(TitleLabel("FreeRTOS 任务配置"))
layout.addWidget(BodyLabel("请添加并配置您的任务参数,支持频率控制与描述。"))
self.table = TableWidget(self)
self.table.setColumnCount(6)
self.table.setHorizontalHeaderLabels(["任务名称", "运行频率", "初始化延迟", "堆栈大小", "任务描述", "频率控制"])
self.table.horizontalHeader().setSectionResizeMode(0, self.table.horizontalHeader().Stretch)
self.table.horizontalHeader().setSectionResizeMode(1, self.table.horizontalHeader().ResizeToContents)
self.table.horizontalHeader().setSectionResizeMode(2, self.table.horizontalHeader().ResizeToContents)
self.table.horizontalHeader().setSectionResizeMode(3, self.table.horizontalHeader().ResizeToContents)
self.table.horizontalHeader().setSectionResizeMode(4, self.table.horizontalHeader().Stretch)
self.table.horizontalHeader().setSectionResizeMode(5, self.table.horizontalHeader().ResizeToContents)
self.table.setMinimumHeight(260)
layout.addWidget(self.table)
btn_layout = QHBoxLayout()
self.add_btn = PushButton("添加任务")
self.del_btn = PushButton("删除选中")
self.ok_btn = PushButton("生成")
self.cancel_btn = PushButton("取消")
btn_layout.addWidget(self.add_btn)
btn_layout.addWidget(self.del_btn)
btn_layout.addStretch()
btn_layout.addWidget(self.ok_btn)
btn_layout.addWidget(self.cancel_btn)
layout.addLayout(btn_layout)
self.add_btn.clicked.connect(self.add_row)
self.del_btn.clicked.connect(self.del_row)
self.ok_btn.clicked.connect(self.accept)
self.cancel_btn.clicked.connect(self.reject)
# 自动读取配置文件
if config_path and os.path.exists(config_path):
try:
with open(config_path, "r", encoding="utf-8") as f:
tasks = yaml.safe_load(f)
if tasks:
for t in tasks:
self.add_row(t)
except Exception:
pass
def add_row(self, task=None):
row = self.table.rowCount()
self.table.insertRow(row)
name = LineEdit(task.get("name", f"Task{row+1}") if task else f"Task{row+1}")
freq = SpinBox()
freq.setRange(1, 10000)
freq.setValue(task.get("frequency", 500) if task else 500)
delay = SpinBox()
delay.setRange(0, 10000)
delay.setValue(task.get("delay", 0) if task else 0)
stack = SpinBox()
stack.setRange(128, 8192)
stack.setSingleStep(128)
stack.setValue(task.get("stack", 256) if task else 256)
desc = LineEdit(task.get("description", "") if task else "请填写任务描述")
freq_ctrl = CheckBox("启用")
freq_ctrl.setChecked(task.get("freq_control", True) if task else True)
self.table.setCellWidget(row, 0, name)
self.table.setCellWidget(row, 1, freq)
self.table.setCellWidget(row, 2, delay)
self.table.setCellWidget(row, 3, stack)
self.table.setCellWidget(row, 4, desc)
self.table.setCellWidget(row, 5, freq_ctrl)
def del_row(self):
selected = self.table.selectedItems()
if selected:
rows = set(item.row() for item in selected)
for row in sorted(rows, reverse=True):
self.table.removeRow(row)
def get_tasks(self):
tasks = []
for row in range(self.table.rowCount()):
name = self.table.cellWidget(row, 0).text().strip()
freq = self.table.cellWidget(row, 1).value()
delay = self.table.cellWidget(row, 2).value()
stack = self.table.cellWidget(row, 3).value()
desc = self.table.cellWidget(row, 4).text().strip()
freq_ctrl = self.table.cellWidget(row, 5).isChecked()
# 校验 stack 必须为 128*2^n
if stack < 128 or (stack & (stack - 1)) != 0 or stack % 128 != 0:
raise ValueError(f"{row+1}行任务“{name}”的堆栈大小必须为128、256、512、1024等128*2^n")
task = {
"name": name,
"function": f"Task_{name}",
"delay": delay,
"stack": stack,
"description": desc,
"freq_control": freq_ctrl
}
if freq_ctrl:
task["frequency"] = freq
tasks.append(task)
return tasks