From 77bd8324ab840dbd9fa418b13c7a1c97426d6d78 Mon Sep 17 00:00:00 2001 From: HuangMason320 Date: Thu, 31 Jul 2025 01:13:49 +0800 Subject: [PATCH] feat: Add Upload Firmware checkbox to Model Node properties panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add upload_fw property with enhanced UI checkbox styling - Connect checkbox to inference pipeline process - Enable/disable firmware upload based on user selection - Add visual feedback and logging for firmware upload status 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../core/functions/InferencePipeline.py | 2 +- cluster4npu_ui/core/functions/Multidongle.py | 20 +++--- cluster4npu_ui/core/nodes/exact_nodes.py | 3 +- cluster4npu_ui/ui/windows/dashboard.py | 62 +++++++++++++++++-- 4 files changed, 70 insertions(+), 17 deletions(-) diff --git a/cluster4npu_ui/core/functions/InferencePipeline.py b/cluster4npu_ui/core/functions/InferencePipeline.py index b50e323..f8dbc40 100644 --- a/cluster4npu_ui/core/functions/InferencePipeline.py +++ b/cluster4npu_ui/core/functions/InferencePipeline.py @@ -17,7 +17,7 @@ class StageConfig: scpu_fw_path: str ncpu_fw_path: str model_path: str - upload_fw: bool = False + upload_fw: bool max_queue_size: int = 50 # Inter-stage processing input_preprocessor: Optional[PreProcessor] = None # Before this stage diff --git a/cluster4npu_ui/core/functions/Multidongle.py b/cluster4npu_ui/core/functions/Multidongle.py index 9e51c5d..ad68057 100644 --- a/cluster4npu_ui/core/functions/Multidongle.py +++ b/cluster4npu_ui/core/functions/Multidongle.py @@ -293,16 +293,16 @@ class MultiDongle: print('[Set Device Timeout]') print(' - Skipped (prevents camera connection crashes)') - # if self.upload_fw: - try: - print('[Upload Firmware]') - kp.core.load_firmware_from_file(device_group=self.device_group, - scpu_fw_path=self.scpu_fw_path, - ncpu_fw_path=self.ncpu_fw_path) - print(' - Success') - except kp.ApiKPException as exception: - print('Error: upload firmware failed, error = \'{}\''.format(str(exception))) - sys.exit(1) + if self.upload_fw: + try: + print('[Upload Firmware]') + kp.core.load_firmware_from_file(device_group=self.device_group, + scpu_fw_path=self.scpu_fw_path, + ncpu_fw_path=self.ncpu_fw_path) + print(' - Success') + except kp.ApiKPException as exception: + print('Error: upload firmware failed, error = \'{}\''.format(str(exception))) + sys.exit(1) # upload model to device try: diff --git a/cluster4npu_ui/core/nodes/exact_nodes.py b/cluster4npu_ui/core/nodes/exact_nodes.py index fb43081..9df208c 100644 --- a/cluster4npu_ui/core/nodes/exact_nodes.py +++ b/cluster4npu_ui/core/nodes/exact_nodes.py @@ -122,7 +122,8 @@ class ExactModelNode(BaseNode): 'model_path': {'type': 'file_path', 'filter': 'NEF Model files (*.nef)'}, 'scpu_fw_path': {'type': 'file_path', 'filter': 'SCPU Firmware files (*.bin)'}, 'ncpu_fw_path': {'type': 'file_path', 'filter': 'NCPU Firmware files (*.bin)'}, - 'port_id': {'placeholder': 'e.g., 8080 or auto'} + 'port_id': {'placeholder': 'e.g., 8080 or auto'}, + 'upload_fw': {'type': 'bool', 'default': True, 'description': 'Upload firmware to dongle if needed'} } # Create custom properties dictionary for UI compatibility diff --git a/cluster4npu_ui/ui/windows/dashboard.py b/cluster4npu_ui/ui/windows/dashboard.py index 75b8e8a..28d0b1a 100644 --- a/cluster4npu_ui/ui/windows/dashboard.py +++ b/cluster4npu_ui/ui/windows/dashboard.py @@ -1170,7 +1170,7 @@ class IntegratedPipelineDashboard(QMainWindow): 'fps': node.get_property('fps') if hasattr(node, 'get_property') else 30 } elif 'Model' in node_type: - # Exact ModelNode properties from original + # Exact ModelNode properties from original - including upload_fw checkbox properties = { 'model_path': node.get_property('model_path') if hasattr(node, 'get_property') else '', 'scpu_fw_path': node.get_property('scpu_fw_path') if hasattr(node, 'get_property') else '', @@ -1211,9 +1211,13 @@ class IntegratedPipelineDashboard(QMainWindow): # Create widget based on property type and name widget = self.create_property_widget_enhanced(node, prop_name, prop_value) - # Add to form - label = prop_name.replace('_', ' ').title() - form_layout.addRow(f"{label}:", widget) + # Add to form with appropriate labels + if prop_name == 'upload_fw': + # For upload_fw, don't show a separate label since the checkbox has its own text + form_layout.addRow(widget) + else: + label = prop_name.replace('_', ' ').title() + form_layout.addRow(f"{label}:", widget) else: # Show available properties for debugging info_text = f"Node type: {node.__class__.__name__}\n" @@ -1338,13 +1342,61 @@ class IntegratedPipelineDashboard(QMainWindow): widget.currentTextChanged.connect(on_change) elif isinstance(prop_value, bool): - # Boolean property + # Boolean property (like upload_fw checkbox) widget = QCheckBox() widget.setChecked(prop_value) + # Add special styling for upload_fw checkbox + if prop_name == 'upload_fw': + widget.setText("Upload Firmware to Device") + widget.setStyleSheet(""" + QCheckBox { + color: #cdd6f4; + font-size: 11px; + padding: 2px; + } + QCheckBox::indicator { + width: 16px; + height: 16px; + border-radius: 3px; + border: 2px solid #45475a; + background-color: #313244; + } + QCheckBox::indicator:checked { + background-color: #89b4fa; + border-color: #89b4fa; + } + QCheckBox::indicator:hover { + border-color: #74c7ec; + } + """) + else: + widget.setStyleSheet(""" + QCheckBox { + color: #cdd6f4; + font-size: 11px; + padding: 2px; + } + QCheckBox::indicator { + width: 14px; + height: 14px; + border-radius: 2px; + border: 1px solid #45475a; + background-color: #313244; + } + QCheckBox::indicator:checked { + background-color: #a6e3a1; + border-color: #a6e3a1; + } + """) + def on_change(state): if hasattr(node, 'set_property'): node.set_property(prop_name, state == 2) + # For upload_fw, also print confirmation + if prop_name == 'upload_fw': + status = "enabled" if state == 2 else "disabled" + print(f"Upload Firmware {status} for {node.name()}") widget.stateChanged.connect(on_change)