|  |  |  |  | import inspect | 
					
						
							|  |  |  |  | import os.path | 
					
						
							|  |  |  |  | import tkinter as tk | 
					
						
							|  |  |  |  | from tkinter import ttk | 
					
						
							|  |  |  |  | from .base_page import BasePage | 
					
						
							|  |  |  |  | from protocol import DbgGlobalConfig | 
					
						
							|  |  |  |  | from config import Cmd | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class GlobalParamsPage(BasePage): | 
					
						
							|  |  |  |  |     def __init__(self, parent, tcp_client): | 
					
						
							|  |  |  |  |         # 先定义同步模式映射关系 | 
					
						
							|  |  |  |  |         self.sync_mode_mapping = { | 
					
						
							|  |  |  |  |             "PT外同步,B码外同步": 0, | 
					
						
							|  |  |  |  |             "PT内同步,B码外同步": 1,  | 
					
						
							|  |  |  |  |             "PT外同步,B码内同步": 2, | 
					
						
							|  |  |  |  |             "PT内同步,B码内同步": 3 | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         self.reverse_sync_mode_mapping = {v: k for k, v in self.sync_mode_mapping.items()} | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         # 然后调用父类的__init__ | 
					
						
							|  |  |  |  |         super().__init__(parent, tcp_client, "全局参数") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # 配置样式 | 
					
						
							|  |  |  |  |         self.configure_styles() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # 注册回调 | 
					
						
							|  |  |  |  |         tcp_client.register_callback(Cmd.GLOBAL_PARAM_GET, self.on_data_received) | 
					
						
							|  |  |  |  |         tcp_client.register_callback(Cmd.GLOBAL_PARAM_SET, self.on_set_response) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # self.create_widgets() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def configure_styles(self): | 
					
						
							|  |  |  |  |         """配置界面样式""" | 
					
						
							|  |  |  |  |         style = ttk.Style() | 
					
						
							|  |  |  |  |         style.configure('Readonly.TEntry', | 
					
						
							|  |  |  |  |                         fieldbackground='#f0f0f0', | 
					
						
							|  |  |  |  |                         foreground='#666666') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def create_widgets(self): | 
					
						
							|  |  |  |  |         """创建界面控件""" | 
					
						
							|  |  |  |  |         print(f"file:{os.path.basename(__file__)} func:{inspect.currentframe().f_code.co_name}") | 
					
						
							|  |  |  |  |         super().create_widgets() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # 创建主框架 | 
					
						
							|  |  |  |  |         main_frame = ttk.Frame(self) | 
					
						
							|  |  |  |  |         main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # 创建两列 | 
					
						
							|  |  |  |  |         left_frame = ttk.Frame(main_frame) | 
					
						
							|  |  |  |  |         left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         right_frame = ttk.Frame(main_frame) | 
					
						
							|  |  |  |  |         right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # 定义所有字段 | 
					
						
							|  |  |  |  |         self.fields = [ | 
					
						
							|  |  |  |  |             # 左列 | 
					
						
							|  |  |  |  |             {"label": "采样频率", "attr": "sample_frequency", "type": "spin", "args": (1, 1000), "unit": "MHz", | 
					
						
							|  |  |  |  |              "readonly": False}, | 
					
						
							|  |  |  |  |             {"label": "触发采样长度", "attr": "trigger_sample_numbers", "type": "spin", "args": (1, 10000), | 
					
						
							|  |  |  |  |              "unit": "us", "readonly": False}, | 
					
						
							|  |  |  |  |             {"label": "预触发百分比", "attr": "pre_trigger_percent", "type": "spin", "args": (0, 100), "unit": "%", | 
					
						
							|  |  |  |  |              "readonly": False}, | 
					
						
							|  |  |  |  |             {"label": "触发电平", "attr": "trigLevel", "type": "spin", "args": (0, 5000), "unit": "mv", | 
					
						
							|  |  |  |  |              "readonly": False}, | 
					
						
							|  |  |  |  |             {"label": "趋势上升周期", "attr": "trend_up_period", "type": "spin", "args": (1, 1000), "unit": "", | 
					
						
							|  |  |  |  |              "readonly": False}, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             # 右列 | 
					
						
							|  |  |  |  |             {"label": "心跳包周期", "attr": "heartbeat_period", "type": "spin", "args": (1, 3600), "unit": "s", | 
					
						
							|  |  |  |  |              "readonly": False}, | 
					
						
							|  |  |  |  |             {"label": "通道使能掩码", "attr": "ch_en_mask", "type": "hex_entry", "unit": "", "readonly": False}, | 
					
						
							|  |  |  |  |             {"label": "同步模式", "attr": "sync_mode", "type": "combo",  | 
					
						
							|  |  |  |  |              "options": list(self.sync_mode_mapping.keys()),  # 使用映射的键作为选项 | 
					
						
							|  |  |  |  |              "readonly": False}, | 
					
						
							|  |  |  |  |             {"label": "内同步频率", "attr": "pt_internal_period", "type": "spin", "args": (40, 300), "unit": "", | 
					
						
							|  |  |  |  |              "readonly": False}, | 
					
						
							|  |  |  |  |         ] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # 创建字段控件 | 
					
						
							|  |  |  |  |         self.create_field_controls(left_frame, self.fields[:5])  # 左列前5个 | 
					
						
							|  |  |  |  |         self.create_field_controls(right_frame, self.fields[5:])  # 右列后4个 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # 创建按钮 | 
					
						
							|  |  |  |  |         self.create_buttons() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def create_field_controls(self, parent, fields): | 
					
						
							|  |  |  |  |         """创建字段控件""" | 
					
						
							|  |  |  |  |         for i, field in enumerate(fields): | 
					
						
							|  |  |  |  |             # 创建标签 | 
					
						
							|  |  |  |  |             label_text = field["label"] + ":" | 
					
						
							|  |  |  |  |             if "unit" in field and field["unit"]: | 
					
						
							|  |  |  |  |                 label_text += f" ({field['unit']})" | 
					
						
							|  |  |  |  |             ttk.Label(parent, text=label_text).grid( | 
					
						
							|  |  |  |  |                 row=i, column=0, sticky='e', padx=2, pady=2) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             # 创建输入控件 | 
					
						
							|  |  |  |  |             if field["type"] == "spin": | 
					
						
							|  |  |  |  |                 var = tk.IntVar() | 
					
						
							|  |  |  |  |                 spinbox = ttk.Spinbox(parent, from_=field["args"][0], to=field["args"][1], | 
					
						
							|  |  |  |  |                                       textvariable=var, width=12) | 
					
						
							|  |  |  |  |                 spinbox.grid(row=i, column=1, sticky='w', padx=2, pady=2) | 
					
						
							|  |  |  |  |                 if field["readonly"]: | 
					
						
							|  |  |  |  |                     spinbox.configure(state='readonly', style='Readonly.TEntry') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             elif field["type"] == "hex_entry": | 
					
						
							|  |  |  |  |                 var = tk.StringVar() | 
					
						
							|  |  |  |  |                 entry = ttk.Entry(parent, textvariable=var, width=12) | 
					
						
							|  |  |  |  |                 entry.grid(row=i, column=1, sticky='w', padx=2, pady=2) | 
					
						
							|  |  |  |  |                 if field["readonly"]: | 
					
						
							|  |  |  |  |                     entry.configure(state='readonly', style='Readonly.TEntry') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             elif field["type"] == "combo": | 
					
						
							|  |  |  |  |                 var = tk.StringVar()  # 使用StringVar存储显示文本 | 
					
						
							|  |  |  |  |                 combobox = ttk.Combobox(parent, textvariable=var, | 
					
						
							|  |  |  |  |                                         values=field["options"], state="readonly", width=15)  # 增加宽度以适应更长的文本 | 
					
						
							|  |  |  |  |                 combobox.grid(row=i, column=1, sticky='w', padx=2, pady=2) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             else:  # entry | 
					
						
							|  |  |  |  |                 var = tk.StringVar() | 
					
						
							|  |  |  |  |                 entry = ttk.Entry(parent, textvariable=var, width=15) | 
					
						
							|  |  |  |  |                 entry.grid(row=i, column=1, sticky='w', padx=2, pady=2) | 
					
						
							|  |  |  |  |                 if field["readonly"]: | 
					
						
							|  |  |  |  |                     entry.configure(state='readonly', style='Readonly.TEntry') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             # 存储变量引用 | 
					
						
							|  |  |  |  |             setattr(self, f"{field['attr']}_var", var) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def create_buttons(self): | 
					
						
							|  |  |  |  |         """创建按钮""" | 
					
						
							|  |  |  |  |         btn_frame = ttk.Frame(self) | 
					
						
							|  |  |  |  |         btn_frame.pack(pady=10) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         ttk.Button(btn_frame, text="读取", command=self.read_data, width=10).pack(side=tk.LEFT, padx=5) | 
					
						
							|  |  |  |  |         ttk.Button(btn_frame, text="设置", command=self.set_data, width=10).pack(side=tk.LEFT, padx=5) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def read_data(self): | 
					
						
							|  |  |  |  |         """读取全局参数""" | 
					
						
							|  |  |  |  |         print(f"发送命令: {Cmd.GLOBAL_PARAM_GET}") | 
					
						
							|  |  |  |  |         if not self.tcp_client.connected: | 
					
						
							|  |  |  |  |             self.show_error("未连接设备") | 
					
						
							|  |  |  |  |             return | 
					
						
							|  |  |  |  |         self.tcp_client.send_packet(Cmd.GLOBAL_PARAM_GET) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def set_data(self): | 
					
						
							|  |  |  |  |         """设置全局参数""" | 
					
						
							|  |  |  |  |         if not self.tcp_client.connected: | 
					
						
							|  |  |  |  |             self.show_error("未连接设备") | 
					
						
							|  |  |  |  |             return | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         try: | 
					
						
							|  |  |  |  |             config = DbgGlobalConfig() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             # 设置字段值 | 
					
						
							|  |  |  |  |             config.sample_frequency = self.sample_frequency_var.get() | 
					
						
							|  |  |  |  |             config.trigger_sample_numbers = self.trigger_sample_numbers_var.get() | 
					
						
							|  |  |  |  |             config.pre_trigger_percent = self.pre_trigger_percent_var.get() | 
					
						
							|  |  |  |  |             config.trigLevel = self.trigLevel_var.get() | 
					
						
							|  |  |  |  |             config.trend_up_period = self.trend_up_period_var.get() | 
					
						
							|  |  |  |  |             config.heartbeat_period = self.heartbeat_period_var.get() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             # 通道使能掩码(16进制转整数) | 
					
						
							|  |  |  |  |             ch_en_mask_str = self.ch_en_mask_var.get().strip() | 
					
						
							|  |  |  |  |             if ch_en_mask_str.startswith(('0x', '0X')): | 
					
						
							|  |  |  |  |                 ch_en_mask_str = ch_en_mask_str[2:] | 
					
						
							|  |  |  |  |             config.ch_en_mask = int(ch_en_mask_str, 16) if ch_en_mask_str else 0 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             # 同步模式:将文本转换为对应的数字值 | 
					
						
							|  |  |  |  |             sync_mode_text = self.sync_mode_var.get() | 
					
						
							|  |  |  |  |             config.sync_mode = self.sync_mode_mapping.get(sync_mode_text, 0) | 
					
						
							|  |  |  |  |              | 
					
						
							|  |  |  |  |             config.pt_internal_period = self.pt_internal_period_var.get() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             self.tcp_client.send_packet(Cmd.GLOBAL_PARAM_SET, config.to_bytes()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         except ValueError as e: | 
					
						
							|  |  |  |  |             self.show_error(f"参数格式错误: {e}") | 
					
						
							|  |  |  |  |         except Exception as e: | 
					
						
							|  |  |  |  |             self.show_error(f"设置失败: {e}") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def on_data_received(self, header, body): | 
					
						
							|  |  |  |  |         """处理接收到的数据""" | 
					
						
							|  |  |  |  |         print(f"file:{os.path.basename(__file__)} func:{inspect.currentframe().f_code.co_name}") | 
					
						
							|  |  |  |  |         print(f"收到数据: 命令={header.cmd}, 数据长度={len(body)}") | 
					
						
							|  |  |  |  |         try: | 
					
						
							|  |  |  |  |             config = DbgGlobalConfig.from_bytes(body) | 
					
						
							|  |  |  |  |             print(f"解析成功: sample_frequency={config.sample_frequency}, trigger_sample_numbers={config.trigger_sample_numbers}") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             # 更新界面字段 | 
					
						
							|  |  |  |  |             self.sample_frequency_var.set(config.sample_frequency) | 
					
						
							|  |  |  |  |             self.trigger_sample_numbers_var.set(config.trigger_sample_numbers) | 
					
						
							|  |  |  |  |             self.pre_trigger_percent_var.set(config.pre_trigger_percent) | 
					
						
							|  |  |  |  |             self.trigLevel_var.set(config.trigLevel) | 
					
						
							|  |  |  |  |             self.trend_up_period_var.set(config.trend_up_period) | 
					
						
							|  |  |  |  |             self.heartbeat_period_var.set(config.heartbeat_period) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             # 通道使能掩码显示为16进制 | 
					
						
							|  |  |  |  |             self.ch_en_mask_var.set(f"0x{config.ch_en_mask:02X}") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             # 同步模式:将数字值转换为对应的文本显示 | 
					
						
							|  |  |  |  |             sync_mode_text = self.reverse_sync_mode_mapping.get(config.sync_mode, "PT外同步,B码外同步") | 
					
						
							|  |  |  |  |             self.sync_mode_var.set(sync_mode_text) | 
					
						
							|  |  |  |  |              | 
					
						
							|  |  |  |  |             self.pt_internal_period_var.set(config.pt_internal_period) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             print(f"同步模式设置: {config.sync_mode} -> {sync_mode_text}") | 
					
						
							|  |  |  |  |             print("全局参数读取成功") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         except Exception as e: | 
					
						
							|  |  |  |  |             print(f"解析全局参数失败: {e}") | 
					
						
							|  |  |  |  |             self.show_error("解析全局参数失败") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def on_set_response(self, header, body): | 
					
						
							|  |  |  |  |         """处理设置响应""" | 
					
						
							|  |  |  |  |         self.show_info("全局参数设置成功") |