diff options
| -rw-r--r-- | devices/arduino_device.py | 1 | ||||
| -rw-r--r-- | devices/base_device.py | 1 | ||||
| -rw-r--r-- | devices/digital_io.py | 1 | ||||
| -rw-r--r-- | devices/nidaqmx_device.py | 1 | ||||
| -rw-r--r-- | devices/serial_device.py | 9 | ||||
| -rw-r--r-- | ui/control_editor.py | 6 | ||||
| -rw-r--r-- | ui/control_panel.py | 6 |
7 files changed, 21 insertions, 4 deletions
diff --git a/devices/arduino_device.py b/devices/arduino_device.py index 7c1d21b..f2407e6 100644 --- a/devices/arduino_device.py +++ b/devices/arduino_device.py @@ -108,6 +108,7 @@ class ArduinoDevice(BaseDevice): channels.append(ChannelConfig( channel_id=f"do{i}", name=f"DO {i}", unit="", min_value=0.0, max_value=1.0, + writable=True, color=_DO_COLORS[i % len(_DO_COLORS)], )) diff --git a/devices/base_device.py b/devices/base_device.py index 32fe787..83b8536 100644 --- a/devices/base_device.py +++ b/devices/base_device.py @@ -29,6 +29,7 @@ class ChannelConfig: max_value: float = 100.0 enabled: bool = True color: str = "#00d4ff" + writable: bool = False # True if this channel accepts write_channel() calls extra: Dict[str, Any] = field(default_factory=dict) diff --git a/devices/digital_io.py b/devices/digital_io.py index 53395dc..111224d 100644 --- a/devices/digital_io.py +++ b/devices/digital_io.py @@ -60,6 +60,7 @@ class DigitalIODevice(BaseDevice): channel_id=f"do{i}", name=f"DO {i}", unit="", min_value=0.0, max_value=1.0, color=_OUT_COLORS[i % len(_OUT_COLORS)], + writable=True, )) info = DeviceInfo( diff --git a/devices/nidaqmx_device.py b/devices/nidaqmx_device.py index 88bb932..38cf93d 100644 --- a/devices/nidaqmx_device.py +++ b/devices/nidaqmx_device.py @@ -69,6 +69,7 @@ class NidaqmxDevice(BaseDevice): channel_id=f"do{i}", name=f"DO {i}", unit="", min_value=0.0, max_value=1.0, color=_DO_COLORS[i % len(_DO_COLORS)], + writable=True, )) info = DeviceInfo( diff --git a/devices/serial_device.py b/devices/serial_device.py index 067656a..8062624 100644 --- a/devices/serial_device.py +++ b/devices/serial_device.py @@ -264,6 +264,7 @@ class SerialDevice(BaseDevice): unit=sc.get("unit", ""), min_value=-1e9, max_value=1e9, color=_COLORS[i % len(_COLORS)], + writable=bool(sc.get("write_cmd")), ) for i, sc in enumerate(self._scpi_channels) ] @@ -275,6 +276,8 @@ class SerialDevice(BaseDevice): unit=mc.get("unit", ""), min_value=-1e9, max_value=1e9, color=_COLORS[i % len(_COLORS)], + # Holding registers (FC03) accept writes (FC06); input registers (FC04) don't. + writable=(mc.get("function_code", 0x03) == 0x03), ) for i, mc in enumerate(self._mb_channels) ] @@ -284,8 +287,8 @@ class SerialDevice(BaseDevice): ChannelConfig("force", "Force", "N", -5000.0, 5000.0, color=_COLORS[0]), ChannelConfig("unit_code", "Unit Code", "", 0.0, float(len(_MARK10_UNITS) - 1), color=_COLORS[1]), # Write-only action channels (no reading — for control buttons) - ChannelConfig("zero", "Zero Gauge", "", 0.0, 1.0, color=_COLORS[2]), - ChannelConfig("cycle_units", "Cycle Units", "", 0.0, 1.0, color=_COLORS[3]), + ChannelConfig("zero", "Zero Gauge", "", 0.0, 1.0, color=_COLORS[2], writable=True), + ChannelConfig("cycle_units", "Cycle Units", "", 0.0, 1.0, color=_COLORS[3], writable=True), ] elif fmt == "cml": _CMD_UNITS = {"TP": "counts", "TV": "counts/s", "TC": "%×10", "TS": "flags"} @@ -311,6 +314,7 @@ class SerialDevice(BaseDevice): unit=_WRITE_UNITS.get(cmd, ""), min_value=-1e6, max_value=1e6, color=_COLORS[color_idx % len(_COLORS)], + writable=True, )) color_idx += 1 # Write-only action channels — motor must be enabled (ME) before VS/MA take effect @@ -321,6 +325,7 @@ class SerialDevice(BaseDevice): unit="", min_value=0.0, max_value=1.0, color=_COLORS[color_idx % len(_COLORS)], + writable=True, )) color_idx += 1 return channels or [ChannelConfig("M1_TP", "M1 TP", "counts", color=_COLORS[0])] diff --git a/ui/control_editor.py b/ui/control_editor.py index 48de21d..5140bf3 100644 --- a/ui/control_editor.py +++ b/ui/control_editor.py @@ -360,8 +360,12 @@ class ControlEditorDialog(QDialog): dev = self.registry.get_instance(dev_id) if not dev: return - # Add actual channels + # Add actual channels (skip disabled — can't be driven while switched + # off — and skip read-only channels — a control writes, so a channel + # with no write mapping should never be offered as a target) for ch in dev.info.channels: + if not ch.enabled or not ch.writable: + continue self._ch_cb.addItem(f"{ch.channel_id} ({ch.name})", userData=ch.channel_id) # For Arduino backends also suggest digital pins for output diff --git a/ui/control_panel.py b/ui/control_panel.py index 2b936c4..22229ee 100644 --- a/ui/control_panel.py +++ b/ui/control_panel.py @@ -120,7 +120,11 @@ class ControlWidget(QFrame): if self.registry and self.device_id and self.channel_id: dev = self.registry.get_instance(self.device_id) if dev: - if dev.status not in (DeviceStatus.CONNECTED, DeviceStatus.SIMULATED): + ch = dev.get_channel(self.channel_id) + if ch is not None and not ch.enabled: + print(f"[Control] write_channel({self.channel_id}, {value}) skipped on " + f"{self.device_id} — channel is disabled") + elif dev.status not in (DeviceStatus.CONNECTED, DeviceStatus.SIMULATED): print(f"[Control] write_channel({self.channel_id}, {value}) skipped on " f"{self.device_id} — device status is {dev.status.value}, not connected") else: |
