提交一下代码

This commit is contained in:
RB 2025-04-27 14:45:44 +08:00
parent 4c697b011f
commit 51e946c04e

352
MRobot.py
View File

@ -4,6 +4,8 @@ import threading
import shutil import shutil
import re import re
from git import Repo from git import Repo
from collections import defaultdict
# 配置常量 # 配置常量
REPO_DIR = "MRobot_repo" REPO_DIR = "MRobot_repo"
@ -14,6 +16,7 @@ class MRobotApp:
self.ioc_data = None self.ioc_data = None
self.add_gitignore_var = None # 延迟初始化 self.add_gitignore_var = None # 延迟初始化
self.header_file_vars = {} self.header_file_vars = {}
self.task_vars = [] # 用于存储任务的变量
# 克隆仓库 # 克隆仓库
def clone_repo(self): def clone_repo(self):
@ -100,20 +103,29 @@ class MRobotApp:
# 定义需要处理的文件夹 # 定义需要处理的文件夹
folders = ["bsp", "component", "device", "module"] folders = ["bsp", "component", "device", "module"]
# 遍历每个文件夹,复制选中的 .h 和 .c 文件
for folder in folders: for folder in folders:
folder_dir = os.path.join(REPO_DIR, "User", folder) folder_dir = os.path.join(REPO_DIR, "User", folder)
for file_name, var in self.header_file_vars.items(): if not os.path.exists(folder_dir):
if var.get(): continue # 如果文件夹不存在,跳过
# 复制 .h 文件
h_file_src = os.path.join(folder_dir, f"{file_name}.h")
h_file_dest = os.path.join("User", folder, f"{file_name}.h")
self.copy_file_from_repo(h_file_src, h_file_dest)
# 复制同名 .c 文件(如果存在) for file_name in os.listdir(folder_dir):
c_file_src = os.path.join(folder_dir, f"{file_name}.c") file_base, file_ext = os.path.splitext(file_name)
c_file_dest = os.path.join("User", folder, f"{file_name}.c") if file_ext not in [".h", ".c"]:
if os.path.exists(c_file_src): continue # 只处理 .h 和 .c 文件
self.copy_file_from_repo(c_file_src, c_file_dest)
# 强制复制与文件夹同名的文件
if file_base == folder:
src_path = os.path.join(folder_dir, file_name)
dest_path = os.path.join("User", folder, file_name)
self.copy_file_from_repo(src_path, dest_path)
continue # 跳过后续检查,直接复制
# 检查是否选中了对应的文件
if file_base in self.header_file_vars and self.header_file_vars[file_base].get():
src_path = os.path.join(folder_dir, file_name)
dest_path = os.path.join("User", folder, file_name)
self.copy_file_from_repo(src_path, dest_path)
threading.Thread(target=task).start() threading.Thread(target=task).start()
@ -158,42 +170,84 @@ class MRobotApp:
# 显示主窗口 # 显示主窗口
def show_main_window(self): def show_main_window(self):
root = tk.Tk() root = tk.Tk()
root.title("MRobot自动生成脚本") root.title("MRobot 自动生成脚本")
root.geometry("700x700") # 调整窗口大小 root.geometry("800x600") # 调整窗口大小以适应布局
# 初始化 BooleanVar # 初始化 BooleanVar
self.add_gitignore_var = tk.BooleanVar(value=True) self.add_gitignore_var = tk.BooleanVar(value=True)
# 创建主框架
main_frame = tk.Frame(root)
main_frame.pack(fill="both", expand=True)
# 添加标题 # 添加标题
title_label = tk.Label(root, text="MRobot 自动生成脚本", font=("Arial", 16, "bold")) title_label = tk.Label(main_frame, text="MRobot 自动生成脚本", font=("Arial", 16, "bold"))
title_label.pack(pady=10) title_label.pack(pady=10)
# 添加复选框
gitignore_frame = tk.Frame(root)
gitignore_frame.pack(pady=10)
tk.Checkbutton(gitignore_frame, text="添加 .gitignore", variable=self.add_gitignore_var).pack(anchor="w")
# 添加 FreeRTOS 状态标签 # 添加 FreeRTOS 状态标签
freertos_status_label = tk.Label(root, text="FreeRTOS 状态: 检测中...", font=("Arial", 12)) freertos_status_label = tk.Label(main_frame, text="FreeRTOS 状态: 检测中...", font=("Arial", 12))
freertos_status_label.pack(pady=10) freertos_status_label.pack(pady=10)
self.update_freertos_status(freertos_status_label) self.update_freertos_status(freertos_status_label)
# 显示 .h 文件复选框 # 模块文件选择和任务管理框架
header_files_frame = tk.LabelFrame(root, text="模块文件选择", padx=10, pady=10, font=("Arial", 10, "bold")) module_task_frame = tk.Frame(main_frame)
header_files_frame.pack(pady=10, fill="both", expand=True) module_task_frame.pack(fill="both", expand=True, padx=10, pady=10)
# 模块文件选择框
header_files_frame = tk.LabelFrame(module_task_frame, text="模块文件选择", padx=10, pady=10, font=("Arial", 10, "bold"))
header_files_frame.pack(side="left", fill="both", expand=True, padx=5)
self.header_files_frame = header_files_frame self.header_files_frame = header_files_frame
self.update_header_files() self.update_header_files()
# 添加生成按钮 # 任务管理框
button_frame = tk.Frame(root) task_frame = tk.LabelFrame(module_task_frame, text="任务管理", padx=10, pady=10, font=("Arial", 10, "bold"))
button_frame.pack(pady=20) task_frame.pack(side="left", fill="both", expand=True, padx=5)
self.task_frame = task_frame
self.update_task_ui()
# 生成按钮和 .gitignore 选项
button_frame = tk.Frame(main_frame)
button_frame.pack(fill="x", pady=10)
generate_button = tk.Button(button_frame, text="一键自动生成MR架构", command=self.generate_action, bg="green", fg="white", font=("Arial", 12, "bold")) generate_button = tk.Button(button_frame, text="一键自动生成MR架构", command=self.generate_action, bg="green", fg="white", font=("Arial", 12, "bold"))
generate_button.pack() generate_button.pack(side="left", padx=10)
tk.Checkbutton(button_frame, text="添加 .gitignore", variable=self.add_gitignore_var).pack(side="left", padx=10)
# 在程序关闭时清理 # 在程序关闭时清理
root.protocol("WM_DELETE_WINDOW", lambda: self.on_closing(root)) root.protocol("WM_DELETE_WINDOW", lambda: self.on_closing(root))
root.mainloop() root.mainloop()
# 更新任务管理 UI
def update_task_ui(self):
for widget in self.task_frame.winfo_children():
widget.destroy()
# 设置任务管理框的固定宽度
self.task_frame.config(width=300) # 将宽度固定为 300 像素
# 显示任务列表
for i, task_var in enumerate(self.task_vars):
task_row = tk.Frame(self.task_frame, width=300) # 设置任务行的宽度
task_row.pack(fill="x", pady=5)
# 调整输入框和按钮的宽度
tk.Entry(task_row, textvariable=task_var, width=25).pack(side="left", padx=5) # 输入框宽度
tk.Button(task_row, text="删除", command=lambda idx=i: self.remove_task(idx), bg="red", fg="white").pack(side="left", padx=5)
# 添加新任务按钮
add_task_button = tk.Button(self.task_frame, text="添加任务", command=self.add_task, bg="blue", fg="white")
add_task_button.pack(pady=10)
# 添加任务
def add_task(self):
new_task_var = tk.StringVar(value=f"Task_{len(self.task_vars) + 1}")
self.task_vars.append(new_task_var)
self.update_task_ui()
# 删除任务
def remove_task(self, idx):
del self.task_vars[idx]
self.update_task_ui()
# 更新文件夹显示 # 更新文件夹显示
def update_folder_display(self): def update_folder_display(self):
for widget in self.folder_frame.winfo_children(): for widget in self.folder_frame.winfo_children():
@ -223,22 +277,205 @@ class MRobotApp:
module_frame = tk.LabelFrame(self.header_files_frame, text=folder.capitalize(), padx=10, pady=10, font=("Arial", 10, "bold")) module_frame = tk.LabelFrame(self.header_files_frame, text=folder.capitalize(), padx=10, pady=10, font=("Arial", 10, "bold"))
module_frame.pack(fill="x", pady=5) module_frame.pack(fill="x", pady=5)
# 创建一个横向布局的容器 # 使用 grid 布局管理器实现自动换行
row_frame = tk.Frame(module_frame) row, col = 0, 0
row_frame.pack(fill="x", pady=5)
for file in os.listdir(folder_dir): for file in os.listdir(folder_dir):
if file.endswith(".h"): file_base, file_ext = os.path.splitext(file)
file_name_without_extension = os.path.splitext(file)[0] # 去掉 .h 后缀 if file_ext == ".h" and file_base != folder: # 过滤掉与文件夹同名的文件
var = tk.BooleanVar(value=False) var = tk.BooleanVar(value=False)
self.header_file_vars[file_name_without_extension] = var self.header_file_vars[file_base] = var
# 显示复选框,横向排列
tk.Checkbutton( # 创建复选框并添加到 grid 中
row_frame, checkbox = tk.Checkbutton(
text=file_name_without_extension, module_frame,
variable=var text=file_base,
).pack(side="left", padx=5, pady=5) variable=var,
# 生成操作 wraplength=150 # 设置文本换行宽度
)
checkbox.grid(row=row, column=col, padx=5, pady=5, sticky="w")
# 控制列数,达到一定数量后换行
col += 1
if col >= 6: # 每行最多显示 3 个复选框
col = 0
row += 1
# 在 MRobotApp 类中添加以下方法
def generate_task_files(self):
try:
template_file_path = os.path.join(REPO_DIR, "User", "task", "task.c.template")
task_dir = os.path.join("User", "task")
# 检查模板文件是否存在
if not os.path.exists(template_file_path):
print(f"模板文件 {template_file_path} 不存在,无法生成 task.c 文件!")
return
# 创建目标目录(如果不存在)
os.makedirs(task_dir, exist_ok=True)
# 读取模板内容
with open(template_file_path, "r", encoding="utf-8") as f:
template_content = f.read()
# 为每个任务生成对应的 task.c 文件
for task_var in self.task_vars:
task_name = task_var.get()
task_file_path = os.path.join(task_dir, f"{task_name.lower()}.c")
# 替换模板中的占位符
task_content = template_content.replace("{{task_name}}", task_name)
task_content = task_content.replace("{{task_function}}", task_name)
task_content = task_content.replace("{{task_frequency}}", f"TASK_FREQ_{task_name.upper()}")
task_content = task_content.replace("{{task_delay}}", f"TASK_INIT_DELAY_{task_name.upper()}")
task_content = task_content.replace("{{task_variable}}", task_name)
# 写入生成的内容到文件
with open(task_file_path, "w", encoding="utf-8") as f:
f.write(task_content)
print(f"已成功生成 {task_file_path} 文件!")
except Exception as e:
print(f"生成 task.c 文件时出错: {e}")
# 修改 user_task.c 文件
def modify_user_task_file(self):
try:
template_file_path = os.path.join(REPO_DIR, "User", "task", "user_task.c.template")
generated_task_file_path = os.path.join("User", "task", "user_task.c")
if not os.path.exists(template_file_path):
print(f"模板文件 {template_file_path} 不存在,无法生成 user_task.c 文件!")
return
os.makedirs(os.path.dirname(generated_task_file_path), exist_ok=True)
with open(template_file_path, "r", encoding="utf-8") as f:
template_content = f.read()
# 打印模板内容
# print(f"模板内容: {template_content}")
# 生成任务属性定义
task_attr_definitions = "\n".join([
f"""const osThreadAttr_t attr_{task_var.get().lower()} = {{
.name = "{task_var.get()}",
.priority = osPriorityNormal,
.stack_size = 128 * 4,
}};"""
for task_var in self.task_vars
])
# 打印生成的任务属性定义
# print(f"生成的任务属性定义: {task_attr_definitions}")
# 替换模板中的占位符
task_content = template_content.replace("{{task_attr_definitions}}", task_attr_definitions)
with open(generated_task_file_path, "w", encoding="utf-8") as f:
f.write(task_content)
print(f"已成功生成 {generated_task_file_path} 文件!")
except Exception as e:
print(f"修改 user_task.c 文件时出错: {e}")
import traceback
traceback.print_exc()
# 生成 user_task.h 文件
def generate_user_task_header(self):
try:
template_file_path = os.path.join(REPO_DIR, "User", "task", "user_task.h.template")
header_file_path = os.path.join("User", "task", "user_task.h")
if not os.path.exists(template_file_path):
print(f"模板文件 {template_file_path} 不存在,无法生成 user_task.h 文件!")
return
os.makedirs(os.path.dirname(header_file_path), exist_ok=True)
with open(template_file_path, "r", encoding="utf-8") as f:
template_content = f.read()
# 打印模板内容
# print(f"模板内容: {template_content}")
# 定义占位符内容
thread_definitions = "\n".join([f" osThreadId_t {task_var.get()};" for task_var in self.task_vars])
heap_water_mark_definitions = "\n".join([f" uint32_t {task_var.get()};" for task_var in self.task_vars])
freq_definitions = "\n".join([f" float {task_var.get()};" for task_var in self.task_vars])
last_up_time_definitions = "\n".join([f" uint32_t {task_var.get()};" for task_var in self.task_vars])
task_handle_definitions = "\n".join([f" osThreadId_t {task_var.get()};" for task_var in self.task_vars])
task_attr_declarations = "\n".join([f"extern const osThreadAttr_t attr_{task_var.get().lower()};" for task_var in self.task_vars])
task_function_declarations = "\n".join([f"void {task_var.get()}(void *argument);" for task_var in self.task_vars])
task_frequency_definitions = "\n".join([f"#define TASK_FREQ_{task_var.get().upper()} (100u)" for task_var in self.task_vars])
task_init_delay_definitions = "\n".join([f"#define TASK_INIT_DELAY_{task_var.get().upper()} (100u)" for task_var in self.task_vars])
# 打印生成的占位符内容
# print(f"thread_definitions: {thread_definitions}")
# print(f"heap_water_mark_definitions: {heap_water_mark_definitions}")
# print(f"freq_definitions: {freq_definitions}")
# print(f"last_up_time_definitions: {last_up_time_definitions}")
# print(f"task_handle_definitions: {task_handle_definitions}")
# print(f"task_attr_declarations: {task_attr_declarations}")
# print(f"task_function_declarations: {task_function_declarations}")
# print(f"task_frequency_definitions: {task_frequency_definitions}")
# print(f"task_init_delay_definitions: {task_init_delay_definitions}")
# 替换模板中的占位符
header_content = template_content.replace("{{thread_definitions}}", thread_definitions)
header_content = header_content.replace("{{heap_water_mark_definitions}}", heap_water_mark_definitions)
header_content = header_content.replace("{{freq_definitions}}", freq_definitions)
header_content = header_content.replace("{{last_up_time_definitions}}", last_up_time_definitions)
header_content = header_content.replace("{{task_handle_definitions}}", task_handle_definitions)
header_content = header_content.replace("{{task_attr_declarations}}", task_attr_declarations)
header_content = header_content.replace("{{task_function_declarations}}", task_function_declarations)
header_content = header_content.replace("{{task_frequency_definitions}}", task_frequency_definitions)
header_content = header_content.replace("{{task_init_delay_definitions}}", task_init_delay_definitions)
with open(header_file_path, "w", encoding="utf-8") as f:
f.write(header_content)
print(f"已成功生成 {header_file_path} 文件!")
except Exception as e:
print(f"生成 user_task.h 文件时出错: {e}")
import traceback
traceback.print_exc()
def generate_init_file(self):
try:
# 定义模板文件路径和生成文件路径
template_file_path = os.path.join(REPO_DIR, "User", "task", "init.c.template")
generated_file_path = os.path.join("User", "task", "init.c")
# 检查模板文件是否存在
if not os.path.exists(template_file_path):
print(f"模板文件 {template_file_path} 不存在,无法生成 init.c 文件!")
return
# 创建目标目录(如果不存在)
os.makedirs(os.path.dirname(generated_file_path), exist_ok=True)
# 读取模板内容
with open(template_file_path, "r", encoding="utf-8") as f:
template_content = f.read()
# 生成任务创建代码
thread_creation_code = "\n".join([
f" task_runtime.thread.{task_var.get().lower()} = osThreadNew({task_var.get()}, NULL, &attr_{task_var.get().lower()});"
for task_var in self.task_vars
])
# 替换模板中的占位符
init_content = template_content.replace("{{thread_creation_code}}", thread_creation_code)
# 写入生成的内容到文件
with open(generated_file_path, "w", encoding="utf-8") as f:
f.write(init_content)
print(f"已成功生成 {generated_file_path} 文件!")
except Exception as e:
print(f"生成 init.c 文件时出错: {e}")
# 修改 generate_action 方法
def generate_action(self): def generate_action(self):
def task(): def task():
# 检查并创建目录 # 检查并创建目录
@ -263,13 +500,34 @@ class MRobotApp:
if file_ext not in [".h", ".c"]: if file_ext not in [".h", ".c"]:
continue # 只处理 .h 和 .c 文件 continue # 只处理 .h 和 .c 文件
# 强制复制与文件夹同名的文件
if file_base == folder:
src_path = os.path.join(folder_dir, file_name)
dest_path = os.path.join("User", folder, file_name)
self.copy_file_from_repo(src_path, dest_path)
print(f"强制复制与文件夹同名的文件: {file_name}")
continue # 跳过后续检查,直接复制
# 检查是否选中了对应的文件 # 检查是否选中了对应的文件
if file_base in self.header_file_vars and self.header_file_vars[file_base].get(): if file_base in self.header_file_vars and self.header_file_vars[file_base].get():
src_path = os.path.join(folder_dir, file_name) src_path = os.path.join(folder_dir, file_name)
dest_path = os.path.join("User", folder, file_name) dest_path = os.path.join("User", folder, file_name)
self.copy_file_from_repo(src_path, dest_path) self.copy_file_from_repo(src_path, dest_path)
# 修改 user_task.c 文件
self.modify_user_task_file()
# 生成 user_task.h 文件
self.generate_user_task_header()
# 生成 init.c 文件
self.generate_init_file()
# 生成 task.c 文件
self.generate_task_files()
threading.Thread(target=task).start() threading.Thread(target=task).start()
# 程序关闭时清理 # 程序关闭时清理
def on_closing(self, root): def on_closing(self, root):
self.delete_repo() self.delete_repo()