diff --git a/hardwarelibrary/sources/millennia.py b/hardwarelibrary/sources/millennia.py index 8f5750e..5f5b9cd 100644 --- a/hardwarelibrary/sources/millennia.py +++ b/hardwarelibrary/sources/millennia.py @@ -80,10 +80,13 @@ def doInitializeDevice(self): self.port = SerialPort(portPath=self.portPath) self.port.open(baudRate=self.defaultBaudRate) self.readIdentity() - except Exception: + except Exception as error: if self.port is not None and self.port.isOpen: self.port.close() - raise PhysicalDevice.UnableToInitialize() + # Preserve the underlying error (e.g. pyserial's "[Errno 16] + # Resource busy") so callers can tell a busy port from a missing + # one instead of seeing a bare, info-less UnableToInitialize. + raise PhysicalDevice.UnableToInitialize(error) from error def readIdentity(self): # The eV identifies via the SCPI-style *IDN? query. The ?IDN form in @@ -197,6 +200,20 @@ def doGetPower(self) -> float: # token. return float(self.queryString("?P").split()[0]) + # Status snapshot + + def doGetStatusUserInfo(self) -> dict: + # Single-call snapshot for PhysicalDevice.startBackgroundStatusUpdates() + # (posted as PhysicalDeviceNotification.status) and for GUI polling: the + # output power plus the diode (emission) and shutter states. Without this + # override the base returns None, so the monitoring loop posts nothing + # useful for the eV. + return { + "power": self.doGetPower(), + "isLaserOn": self.doGetOnOffState(), + "isShutterOpen": self.doGetShutterState(), + } + class DebugMillenniaEv25Device(MillenniaEv25Device): classIdVendor = 0xFFFF diff --git a/hardwarelibrary/tests/testMillennia.py b/hardwarelibrary/tests/testMillennia.py index cb80f67..77fd1bc 100644 --- a/hardwarelibrary/tests/testMillennia.py +++ b/hardwarelibrary/tests/testMillennia.py @@ -104,6 +104,15 @@ def testShutterIsIndependentOfOnOff(self): self.assertFalse(self.laser.isLaserOn()) self.assertTrue(self.laser.isShutterOpen()) # off, shutter unchanged + def testStatusUserInfoSnapshotsPowerOnOffAndShutter(self): + self.laser.setPower(7.5) + self.laser.turnOn() + self.laser.openShutter() + self.assertEqual( + self.laser.doGetStatusUserInfo(), + {"power": 7.5, "isLaserOn": True, "isShutterOpen": True}, + ) + class TestMillenniaEv25Device(unittest.TestCase): def setUp(self):