You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

276 lines
11 KiB
Python

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import os
import threading
from .base_page import BasePage
from protocol import DbgUpgradeData
from protocol import DbgUpgradeResponseData
from config import Cmd
class UpgradePage(BasePage):
def __init__(self, parent, tcp_client):
# 升级类型映射字典
self.upgrade_types = {
"CMU+FPGA": 0,
"CMU": 1,
"FPGA": 2,
"其他": 3
}
super().__init__(parent, tcp_client, "固件升级")
self.upgrade_file = None
self.upgrade_data = None
self.current_index = 0
self.total_packets = 0
self.upgrading = False
self.waiting_response = False
tcp_client.register_callback(Cmd.UPGRADE_DATA, self.on_upgrade_response)
# self.create_widgets()
def create_widgets(self):
"""创建界面控件"""
# 升级类型选择
type_frame = ttk.Frame(self)
type_frame.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(type_frame, text="升级类型:").pack(side=tk.LEFT, padx=5)
self.upgrade_type_var = tk.StringVar(value="CMU+FPGA") # 默认值
# 创建下拉框,显示文本但存储对应的数值
upgrade_combo = ttk.Combobox(type_frame, textvariable=self.upgrade_type_var,
values=list(self.upgrade_types.keys()),
state="readonly", width=12)
upgrade_combo.pack(side=tk.LEFT, padx=5)
# 文件选择
file_frame = ttk.Frame(self)
file_frame.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(file_frame, text="升级文件:").pack(side=tk.LEFT, padx=5)
self.file_path_var = tk.StringVar()
ttk.Entry(file_frame, textvariable=self.file_path_var, width=50, state='readonly').pack(side=tk.LEFT, padx=5)
ttk.Button(file_frame, text="浏览", command=self.browse_file).pack(side=tk.LEFT, padx=5)
# 进度显示
progress_frame = ttk.Frame(self)
progress_frame.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(progress_frame, text="进度:").pack(side=tk.LEFT, padx=5)
self.progress_var = tk.DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var, maximum=100)
progress_bar.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
self.progress_label = ttk.Label(progress_frame, text="0/0")
self.progress_label.pack(side=tk.RIGHT, padx=5)
# 状态显示
status_frame = ttk.Frame(self)
status_frame.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(status_frame, text="状态:").pack(side=tk.LEFT, padx=5)
self.status_var = tk.StringVar(value="就绪")
ttk.Label(status_frame, textvariable=self.status_var).pack(side=tk.LEFT, padx=5)
# 按钮区域
button_frame = ttk.Frame(self)
button_frame.pack(pady=10)
self.start_button = ttk.Button(button_frame, text="开始升级", command=self.start_upgrade)
self.start_button.pack(side=tk.LEFT, padx=5)
self.stop_button = ttk.Button(button_frame, text="停止升级", command=self.stop_upgrade, state='disabled')
self.stop_button.pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="清除状态", command=self.clear_status).pack(side=tk.LEFT, padx=5)
def get_upgrade_type_code(self):
"""获取当前选择的升级类型代码"""
selected_text = self.upgrade_type_var.get()
return self.upgrade_types.get(selected_text, 0) # 默认返回0
def get_upgrade_type_text(self, code=None):
"""根据代码获取升级类型文本,或获取当前选择的文本"""
if code is not None:
# 根据代码找文本
for text, value in self.upgrade_types.items():
if value == code:
return text
return "其他"
else:
# 返回当前选择的文本
return self.upgrade_type_var.get()
def browse_file(self):
"""选择升级文件"""
if self.upgrading:
messagebox.showerror("错误", "升级进行中,无法选择文件")
return
file_path = filedialog.askopenfilename(
title="选择升级文件",
filetypes=[("二进制文件", "*.bin"), ("固件文件", "*.fw"), ("所有文件", "*.*")]
)
if file_path:
self.file_path_var.set(file_path)
self.upgrade_file = file_path
file_size = os.path.getsize(file_path)
upgrade_type_text = self.get_upgrade_type_text()
self.status_var.set(f"已选择{upgrade_type_text}文件: {os.path.basename(file_path)} ({file_size} 字节)")
def start_upgrade(self):
"""开始升级流程"""
if not self.tcp_client.connected:
messagebox.showerror("错误", "未连接到设备")
return
if not self.upgrade_file or not os.path.exists(self.upgrade_file):
messagebox.showerror("错误", "请选择有效的升级文件")
return
# 获取升级类型代码
upgrade_type_code = self.get_upgrade_type_code()
upgrade_type_text = self.get_upgrade_type_text()
# 读取升级文件
try:
with open(self.upgrade_file, 'rb') as f:
self.upgrade_data = f.read()
except Exception as e:
messagebox.showerror("错误", f"读取文件失败: {e}")
return
# 计算总包数
self.total_packets = (len(self.upgrade_data) + 1023) // 1024
self.current_index = 0
self.upgrading = True
self.waiting_response = False
# 更新界面状态
self.start_button.config(state='disabled')
self.stop_button.config(state='normal')
self.progress_var.set(0)
self.progress_label.config(text=f"0/{self.total_packets}")
self.status_var.set(f"开始{upgrade_type_text}升级...")
# 发送第一个数据包
self.send_next_packet()
def stop_upgrade(self):
"""停止升级"""
if self.upgrading:
self.upgrading = False
self.waiting_response = False
upgrade_type_text = self.get_upgrade_type_text()
self.status_var.set(f"{upgrade_type_text}升级已停止")
self.start_button.config(state='normal')
self.stop_button.config(state='disabled')
def clear_status(self):
"""清除状态"""
if not self.upgrading:
self.status_var.set("就绪")
self.progress_var.set(0)
self.progress_label.config(text="0/0")
def send_next_packet(self):
"""发送下一个数据包"""
if not self.upgrading or not self.upgrade_data or self.waiting_response:
return
if self.current_index >= self.total_packets:
self.complete_upgrade()
return
# 计算当前数据包范围
packet_size = 1024
start = self.current_index * packet_size
end = min(start + packet_size, len(self.upgrade_data))
# 准备升级数据包头
upgrade_header = DbgUpgradeData()
upgrade_header.type = self.get_upgrade_type_code() # 设置升级类型代码
upgrade_header.index = self.current_index
upgrade_header.sum = self.total_packets
upgrade_header.len = end - start
# 组合数据包头和数据
packet_data = upgrade_header.to_bytes() + self.upgrade_data[start:end]
# 发送数据包
if self.tcp_client.send_packet(Cmd.UPGRADE_DATA, packet_data):
self.waiting_response = True
# 更新状态显示
upgrade_type_text = self.get_upgrade_type_text()
self.status_var.set(f"{upgrade_type_text}升级: {self.current_index + 1}/{self.total_packets}")
# 更新进度
progress = (self.current_index * packet_size) / len(self.upgrade_data) * 100
self.progress_var.set(min(progress, 100))
self.progress_label.config(text=f"{self.current_index}/{self.total_packets}")
else:
self.upgrading = False
self.status_var.set("发送失败")
self.start_button.config(state='normal')
self.stop_button.config(state='disabled')
def complete_upgrade(self):
"""完成升级"""
self.upgrading = False
self.waiting_response = False
upgrade_type_text = self.get_upgrade_type_text()
self.status_var.set(f"{upgrade_type_text}升级完成")
self.progress_var.set(100)
self.start_button.config(state='normal')
self.stop_button.config(state='disabled')
messagebox.showinfo("成功", f"{upgrade_type_text}升级完成")
def on_upgrade_response(self, header, body):
"""处理升级响应"""
if not self.upgrading or not self.waiting_response:
return
try:
response = DbgUpgradeResponseData.from_bytes(body)
# 检查响应是否正确
if response.index == self.current_index:
# 当前包发送成功,继续下一个
self.current_index += 1
self.waiting_response = False
# 更新进度显示
packet_size = 1024
progress = (self.current_index * packet_size) / len(self.upgrade_data) * 100
self.progress_var.set(min(progress, 100))
self.progress_label.config(text=f"{self.current_index}/{self.total_packets}")
# 发送下一个包或完成升级
if self.current_index < self.total_packets:
upgrade_type_text = self.get_upgrade_type_text()
self.status_var.set(f"继续{upgrade_type_text}升级...")
self.send_next_packet()
else:
self.complete_upgrade()
else:
self.status_var.set(f"响应包索引不匹配,重发")
self.waiting_response = False
self.send_next_packet()
except Exception as e:
self.status_var.set(f"解析响应失败: {e}")
# 重发当前包
self.waiting_response = False
self.send_next_packet()