diff --git a/src/dodal/beamlines/i22.py b/src/dodal/beamlines/i22.py index 7e72200c63..b1358c0b57 100644 --- a/src/dodal/beamlines/i22.py +++ b/src/dodal/beamlines/i22.py @@ -113,6 +113,7 @@ def i0( "-EA-XBPM-02:", wait_for_connection, fake_with_ophyd_sim, + type="Cividec Diamond XBPM", directory_provider=get_directory_provider(), ) @@ -127,6 +128,7 @@ def it( "-EA-TTRM-02:", wait_for_connection, fake_with_ophyd_sim, + type="PIN Diode", directory_provider=get_directory_provider(), ) diff --git a/src/dodal/devices/synchrotron.py b/src/dodal/devices/synchrotron.py index ae9eabe8ca..7715fa7cc5 100644 --- a/src/dodal/devices/synchrotron.py +++ b/src/dodal/devices/synchrotron.py @@ -1,6 +1,6 @@ from enum import Enum -from ophyd_async.core import StandardReadable +from ophyd_async.core import ConfigSignal, StandardReadable, soft_signal_r_and_setter from ophyd_async.epics.signal import epics_signal_r @@ -40,31 +40,26 @@ def __init__( status_prefix=Prefix.STATUS, topup_prefix=Prefix.TOP_UP, ): - self.ring_current = epics_signal_r(float, signal_prefix + Suffix.SIGNAL) - self.synchrotron_mode = epics_signal_r( - SynchrotronMode, status_prefix + Suffix.MODE - ) + with self.add_children_as_readables(): + self.current = epics_signal_r(float, signal_prefix + Suffix.SIGNAL) + self.energy = epics_signal_r(float, status_prefix + Suffix.BEAM_ENERGY) + + with self.add_children_as_readables(ConfigSignal): + self.probe, _ = soft_signal_r_and_setter(str, initial_value="x-ray") + self.type, _ = soft_signal_r_and_setter( + str, initial_value="Synchrotron X-ray Source" + ) + self.synchrotron_mode = epics_signal_r( + SynchrotronMode, status_prefix + Suffix.MODE + ) self.machine_user_countdown = epics_signal_r( float, status_prefix + Suffix.USER_COUNTDOWN ) - self.beam_energy = epics_signal_r(float, status_prefix + Suffix.BEAM_ENERGY) - self.topup_start_countdown = epics_signal_r( + self.top_up_start_countdown = epics_signal_r( float, topup_prefix + Suffix.COUNTDOWN ) self.top_up_end_countdown = epics_signal_r( float, topup_prefix + Suffix.END_COUNTDOWN ) - self.set_readable_signals( - read=[ - self.ring_current, - self.machine_user_countdown, - self.topup_start_countdown, - self.top_up_end_countdown, - ], - config=[ - self.beam_energy, - self.synchrotron_mode, - ], - ) super().__init__(name=name) diff --git a/src/dodal/devices/tetramm.py b/src/dodal/devices/tetramm.py index ebd539af78..a78f0a6d73 100644 --- a/src/dodal/devices/tetramm.py +++ b/src/dodal/devices/tetramm.py @@ -12,6 +12,7 @@ ShapeProvider, StandardDetector, set_and_wait_for_value, + soft_signal_r_and_setter, ) from ophyd_async.epics.areadetector.utils import stop_busy_record from ophyd_async.epics.areadetector.writers import HDFWriter, NDFileHDF @@ -219,11 +220,22 @@ def __init__( prefix: str, directory_provider: DirectoryProvider, name: str, + type: str | None = None, **scalar_sigs: str, ) -> None: self.drv = TetrammDriver(prefix + "DRV:") self.hdf = NDFileHDF(prefix + "HDF5:") controller = TetrammController(self.drv) + config_signals = [ + self.drv.values_per_reading, + self.drv.averaging_time, + self.drv.sample_time, + ] + if type: + self.type, _ = soft_signal_r_and_setter(str, type) + config_signals.append(self.type) + else: + self.type = None super().__init__( controller, HDFWriter( @@ -233,11 +245,7 @@ def __init__( TetrammShapeProvider(controller), **scalar_sigs, ), - [ - self.drv.values_per_reading, - self.drv.averaging_time, - self.drv.sample_time, - ], + config_signals, name, ) diff --git a/src/dodal/plans/check_topup.py b/src/dodal/plans/check_topup.py index 78110d70c5..2e1bfa1d29 100644 --- a/src/dodal/plans/check_topup.py +++ b/src/dodal/plans/check_topup.py @@ -42,10 +42,10 @@ def _delay_to_avoid_topup(total_run_time, time_to_topup): def wait_for_topup_complete(synchrotron: Synchrotron): LOGGER.info("Waiting for topup to complete") - start = yield from bps.rd(synchrotron.topup_start_countdown) + start = yield from bps.rd(synchrotron.top_up_start_countdown) while start == COUNTDOWN_DURING_TOPUP: yield from bps.sleep(0.1) - start = yield from bps.rd(synchrotron.topup_start_countdown) + start = yield from bps.rd(synchrotron.top_up_start_countdown) def check_topup_and_wait_if_necessary( @@ -65,7 +65,7 @@ def check_topup_and_wait_if_necessary( """ machine_mode = yield from bps.rd(synchrotron.synchrotron_mode) assert isinstance(machine_mode, SynchrotronMode) - time_to_topup = yield from bps.rd(synchrotron.topup_start_countdown) + time_to_topup = yield from bps.rd(synchrotron.top_up_start_countdown) if _in_decay_mode(time_to_topup) or not _gating_permitted(machine_mode): yield from bps.null() return @@ -77,6 +77,6 @@ def check_topup_and_wait_if_necessary( yield from bps.sleep(time_to_wait) - check_start = yield from bps.rd(synchrotron.topup_start_countdown) + check_start = yield from bps.rd(synchrotron.top_up_start_countdown) if check_start == COUNTDOWN_DURING_TOPUP: yield from wait_for_topup_complete(synchrotron) diff --git a/tests/devices/unit_tests/test_synchrotron.py b/tests/devices/unit_tests/test_synchrotron.py index 2a585d54f5..73d2034b00 100644 --- a/tests/devices/unit_tests/test_synchrotron.py +++ b/tests/devices/unit_tests/test_synchrotron.py @@ -11,43 +11,43 @@ SynchrotronMode, ) -RING_CURRENT = 0.556677 +CURRENT = 0.556677 USER_COUNTDOWN = 55.0 START_COUNTDOWN = 66.0 END_COUNTDOWN = 77.0 -BEAM_ENERGY = 3.0158 +ENERGY = 3.0158 MODE = SynchrotronMode.INJECTION +PROBE = "x-ray" +TYPE = "Synchrotron X-ray Source" NUMBER = "number" STRING = "string" EMPTY_LIST: List = [] -READINGS = [RING_CURRENT, USER_COUNTDOWN, START_COUNTDOWN, END_COUNTDOWN] -CONFIGS = [BEAM_ENERGY, MODE.value] +READINGS = [CURRENT, ENERGY] +CONFIGS = [PROBE, MODE.value, TYPE] READING_FIELDS = ["value", "alarm_severity"] DESCRIPTION_FIELDS = ["source", "dtype", "shape"] READING_ADDRESSES = [ "mock+ca://SR-DI-DCCT-01:SIGNAL", - "mock+ca://CS-CS-MSTAT-01:USERCOUNTDN", - "mock+ca://SR-CS-FILL-01:COUNTDOWN", - "mock+ca://SR-CS-FILL-01:ENDCOUNTDN", + "mock+ca://CS-CS-MSTAT-01:BEAMENERGY", ] CONFIG_ADDRESSES = [ - "mock+ca://CS-CS-MSTAT-01:BEAMENERGY", + "mock+soft://synchrotron-probe", "mock+ca://CS-CS-MSTAT-01:MODE", + "mock+soft://synchrotron-type", ] READ_SIGNALS = [ - "synchrotron-ring_current", - "synchrotron-machine_user_countdown", - "synchrotron-topup_start_countdown", - "synchrotron-top_up_end_countdown", + "synchrotron-current", + "synchrotron-energy", ] CONFIG_SIGNALS = [ - "synchrotron-beam_energy", + "synchrotron-probe", "synchrotron-synchrotron_mode", + "synchrotron-type", ] EXPECTED_READ_RESULT = f"""{{ @@ -58,25 +58,21 @@ "{READ_SIGNALS[1]}": {{ "{READING_FIELDS[0]}": {READINGS[1]}, "{READING_FIELDS[1]}": 0 - }}, - "{READ_SIGNALS[2]}": {{ - "{READING_FIELDS[0]}": {READINGS[2]}, - "{READING_FIELDS[1]}": 0 - }}, - "{READ_SIGNALS[3]}": {{ - "{READING_FIELDS[0]}": {READINGS[3]}, - "{READING_FIELDS[1]}": 0 }} }}""" EXPECTED_READ_CONFIG_RESULT = f"""{{ "{CONFIG_SIGNALS[0]}":{{ - "{READING_FIELDS[0]}": {CONFIGS[0]}, + "{READING_FIELDS[0]}": "{CONFIGS[0]}", "{READING_FIELDS[1]}": 0 }}, "{CONFIG_SIGNALS[1]}":{{ "{READING_FIELDS[0]}": "{CONFIGS[1]}", "{READING_FIELDS[1]}": 0 + }}, + "{CONFIG_SIGNALS[2]}":{{ + "{READING_FIELDS[0]}": "{CONFIGS[2]}", + "{READING_FIELDS[1]}": 0 }} }}""" @@ -90,29 +86,24 @@ "{DESCRIPTION_FIELDS[0]}": "{READING_ADDRESSES[1]}", "{DESCRIPTION_FIELDS[1]}": "{NUMBER}", "{DESCRIPTION_FIELDS[2]}": {EMPTY_LIST} - }}, - "{READ_SIGNALS[2]}":{{ - "{DESCRIPTION_FIELDS[0]}": "{READING_ADDRESSES[2]}", - "{DESCRIPTION_FIELDS[1]}": "{NUMBER}", - "{DESCRIPTION_FIELDS[2]}": {EMPTY_LIST} - }}, - "{READ_SIGNALS[3]}":{{ - "{DESCRIPTION_FIELDS[0]}": "{READING_ADDRESSES[3]}", - "{DESCRIPTION_FIELDS[1]}": "{NUMBER}", - "{DESCRIPTION_FIELDS[2]}": {EMPTY_LIST} }} }}""" EXPECTED_DESCRIBE_CONFIG_RESULT = f"""{{ "{CONFIG_SIGNALS[0]}":{{ "{DESCRIPTION_FIELDS[0]}": "{CONFIG_ADDRESSES[0]}", - "{DESCRIPTION_FIELDS[1]}": "{NUMBER}", + "{DESCRIPTION_FIELDS[1]}": "{STRING}", "{DESCRIPTION_FIELDS[2]}": {EMPTY_LIST} }}, "{CONFIG_SIGNALS[1]}":{{ "{DESCRIPTION_FIELDS[0]}": "{CONFIG_ADDRESSES[1]}", "{DESCRIPTION_FIELDS[1]}": "{STRING}", "{DESCRIPTION_FIELDS[2]}": {EMPTY_LIST} + }}, + "{CONFIG_SIGNALS[2]}":{{ + "{DESCRIPTION_FIELDS[0]}": "{CONFIG_ADDRESSES[2]}", + "{DESCRIPTION_FIELDS[1]}": "{STRING}", + "{DESCRIPTION_FIELDS[2]}": {EMPTY_LIST} }} }}""" @@ -121,11 +112,11 @@ async def sim_synchrotron() -> Synchrotron: async with DeviceCollector(mock=True): sim_synchrotron = Synchrotron() - set_mock_value(sim_synchrotron.ring_current, RING_CURRENT) + set_mock_value(sim_synchrotron.current, CURRENT) set_mock_value(sim_synchrotron.machine_user_countdown, USER_COUNTDOWN) - set_mock_value(sim_synchrotron.topup_start_countdown, START_COUNTDOWN) + set_mock_value(sim_synchrotron.top_up_start_countdown, START_COUNTDOWN) set_mock_value(sim_synchrotron.top_up_end_countdown, END_COUNTDOWN) - set_mock_value(sim_synchrotron.beam_energy, BEAM_ENERGY) + set_mock_value(sim_synchrotron.energy, ENERGY) set_mock_value(sim_synchrotron.synchrotron_mode, MODE) return sim_synchrotron @@ -175,9 +166,8 @@ async def test_synchrotron_count(RE: RunEngine, sim_synchrotron: Synchrotron): cfg_data_keys = docs[1]["configuration"][sim_synchrotron.name]["data_keys"] for sig, addr in zip(CONFIG_SIGNALS, CONFIG_ADDRESSES): assert sig in cfg_data_keys - dtype = NUMBER if sig == CONFIG_SIGNALS[0] else STRING assert cfg_data_keys[sig][DESCRIPTION_FIELDS[0]] == addr - assert cfg_data_keys[sig][DESCRIPTION_FIELDS[1]] == dtype + assert cfg_data_keys[sig][DESCRIPTION_FIELDS[1]] == STRING assert cfg_data_keys[sig][DESCRIPTION_FIELDS[2]] == EMPTY_LIST cfg_data = docs[1]["configuration"][sim_synchrotron.name]["data"] for sig, value in zip(CONFIG_SIGNALS, CONFIGS): diff --git a/tests/plans/test_topup_plan.py b/tests/plans/test_topup_plan.py index 7e7a1854ec..11745a0176 100644 --- a/tests/plans/test_topup_plan.py +++ b/tests/plans/test_topup_plan.py @@ -24,7 +24,7 @@ def test_when_topup_before_end_of_collection_wait( fake_sleep: MagicMock, fake_wait: MagicMock, synchrotron: Synchrotron, RE: RunEngine ): set_mock_value(synchrotron.synchrotron_mode, SynchrotronMode.USER) - set_mock_value(synchrotron.topup_start_countdown, 20.0) + set_mock_value(synchrotron.top_up_start_countdown, 20.0) set_mock_value(synchrotron.top_up_end_countdown, 60.0) RE( @@ -64,7 +64,7 @@ def fake_generator(value): def test_no_waiting_if_decay_mode( fake_null: MagicMock, fake_sleep: MagicMock, synchrotron: Synchrotron, RE: RunEngine ): - set_mock_value(synchrotron.topup_start_countdown, -1) + set_mock_value(synchrotron.top_up_start_countdown, -1) RE( check_topup_and_wait_if_necessary( @@ -81,7 +81,7 @@ def test_no_waiting_if_decay_mode( def test_no_waiting_when_mode_does_not_allow_gating( fake_null: MagicMock, synchrotron: Synchrotron, RE: RunEngine ): - set_mock_value(synchrotron.topup_start_countdown, 1.0) + set_mock_value(synchrotron.top_up_start_countdown, 1.0) set_mock_value(synchrotron.synchrotron_mode, SynchrotronMode.SHUTDOWN) RE(