diff --git a/src/dodal/devices/detector/detector.py b/src/dodal/devices/detector/detector.py index 7156456c9b..eecabe2bac 100644 --- a/src/dodal/devices/detector/detector.py +++ b/src/dodal/devices/detector/detector.py @@ -43,6 +43,9 @@ class DetectorParams(BaseModel): detector_size_constants: DetectorSizeConstants = EIGER2_X_16M_SIZE beam_xy_converter: DetectorDistanceToBeamXYConverter run_number: int + enable_dev_shm: bool = ( + False # Remove in https://github.com/DiamondLightSource/hyperion/issues/1395 + ) class Config: arbitrary_types_allowed = True diff --git a/src/dodal/devices/eiger.py b/src/dodal/devices/eiger.py index 8a590974ca..53c22f5d93 100644 --- a/src/dodal/devices/eiger.py +++ b/src/dodal/devices/eiger.py @@ -144,6 +144,9 @@ def stop(self, *args): self.disarm_detector() stop_status &= self.disable_roi_mode() stop_status.wait(self.GENERAL_STATUS_TIMEOUT) + # See https://github.com/DiamondLightSource/hyperion/issues/1395 + LOGGER.info("Turning off Eiger dev/shm streaming") + self.odin.fan.dev_shm_enable.set(0).wait() LOGGER.info("Eiger has successfully been stopped") def disable_roi_mode(self): @@ -320,6 +323,10 @@ def forward_bit_depth_to_filewriter(self): self.GENERAL_STATUS_TIMEOUT ) + def change_dev_shm(self, enable_dev_shm: bool): + LOGGER.info(f"{'Enabling' if enable_dev_shm else 'Disabling'} dev shm") + return self.odin.fan.dev_shm_enable.set(1 if enable_dev_shm else 0) + def disarm_detector(self): self.cam.acquire.set(0).wait(self.GENERAL_STATUS_TIMEOUT) @@ -330,6 +337,7 @@ def do_arming_chain(self) -> Status: functions_to_do_arm.append(self.enable_roi_mode) arming_sequence_funcs = [ + lambda: self.change_dev_shm(detector_params.enable_dev_shm), lambda: self.set_detector_threshold(detector_params.expected_energy_ev), self.set_cam_pvs, self.set_odin_number_of_frame_chunks, diff --git a/src/dodal/devices/eiger_odin.py b/src/dodal/devices/eiger_odin.py index 91dbea12be..ccc945e29e 100644 --- a/src/dodal/devices/eiger_odin.py +++ b/src/dodal/devices/eiger_odin.py @@ -19,6 +19,7 @@ class EigerFan(Device): series = Component(EpicsSignalRO, "CurrentSeries_RBV") offset = Component(EpicsSignalRO, "CurrentOffset_RBV") forward_stream = Component(EpicsSignalWithRBV, "ForwardStream") + dev_shm_enable = Component(EpicsSignalWithRBV, "DevShmCache") class OdinMetaListener(Device): diff --git a/tests/devices/unit_tests/test_eiger.py b/tests/devices/unit_tests/test_eiger.py index f8a57db967..4da5bf3ee5 100644 --- a/tests/devices/unit_tests/test_eiger.py +++ b/tests/devices/unit_tests/test_eiger.py @@ -346,13 +346,16 @@ def test_given_failing_odin_when_stage_then_exception_raised(fake_eiger): assert error_contents in e.value.__str__() +def set_up_eiger_to_stage_happily(fake_eiger: EigerDetector): + fake_eiger.odin.nodes.clear_odin_errors = MagicMock() + fake_eiger.odin.check_odin_initialised = MagicMock(return_value=(True, "")) + fake_eiger.odin.file_writer.file_path.put(True) + + @patch("dodal.devices.eiger.await_value") def test_stage_runs_successfully(mock_await, fake_eiger: EigerDetector): mock_await.return_value = finished_status() - fake_eiger.odin.nodes.clear_odin_errors = MagicMock() - fake_eiger.odin.check_odin_initialised = MagicMock() - fake_eiger.odin.check_odin_initialised.return_value = (True, "") - fake_eiger.odin.file_writer.file_path.put(True) + set_up_eiger_to_stage_happily(fake_eiger) fake_eiger.stage() fake_eiger.arming_status.wait(1) # This should complete long before 1s @@ -363,9 +366,7 @@ def test_given_stale_parameters_goes_high_before_callbacks_then_stale_parameters fake_eiger: EigerDetector, ): mock_await.return_value = Status(done=True) - fake_eiger.odin.nodes.clear_odin_errors = MagicMock() - fake_eiger.odin.check_odin_initialised = MagicMock(return_value=(True, "")) - fake_eiger.odin.file_writer.file_path.put(True) + set_up_eiger_to_stage_happily(fake_eiger) mock_eiger_odin_statuses(fake_eiger) @@ -689,3 +690,35 @@ def test_stop_eiger_waits_for_status_functions_to_complete( ): fake_eiger.stop() mock_wait.assert_called() + + +@pytest.mark.parametrize( + "enable_dev_shm, expected_set", + [ + (True, 1), + (False, 0), + ], +) +@patch("dodal.devices.eiger.await_value") +def test_given_dev_shm_when_stage_then_correctly_enable_disable_dev_shm( + mock_await, + enable_dev_shm: bool, + expected_set: int, + fake_eiger: EigerDetector, +): + mock_await.return_value = finished_status() + set_up_eiger_to_stage_happily(fake_eiger) + + fake_eiger.detector_params.enable_dev_shm = enable_dev_shm # type:ignore + + fake_eiger.stage() + + assert fake_eiger.odin.fan.dev_shm_enable.get() == expected_set + + +def test_when_eiger_is_stopped_then_dev_shm_disabled(fake_eiger: EigerDetector): + fake_eiger.odin.fan.dev_shm_enable.sim_put(1) # type:ignore + + fake_eiger.stop() + + assert fake_eiger.odin.fan.dev_shm_enable.get() == 0