diff --git a/python/lsst/ts/observatory/control/maintel/mtcs.py b/python/lsst/ts/observatory/control/maintel/mtcs.py index 3ad373ca..f4e09a07 100644 --- a/python/lsst/ts/observatory/control/maintel/mtcs.py +++ b/python/lsst/ts/observatory/control/maintel/mtcs.py @@ -1936,6 +1936,31 @@ async def get_m1m3_applied_balance_forces(self) -> salobj.type_hints.BaseMsgType ) ) + def map_slew_setting_to_attribute( + self, setting_enum: MTM1M3.SetSlewControllerSettings + ) -> str: + """ + Maps a SetSlewControllerSettings enum to the corresponding attribute + returned by the evt_slew_controller_settings. + + Parameters + ---------- + setting_enum : MTM1M3.SetSlewControllerSettings + The enum member to be mapped. + + Returns + ------- + str + The corresponding attribute name. + """ + setting_to_attribute = { + "ACCELERATIONFORCES": "useAccelerationForces", + "BALANCEFORCES": "useBalanceForces", + "BOOSTERVALVES": "triggerBoosterValves", + "VELOCITYFORCES": "useVelocityForces", + } + return setting_to_attribute[setting_enum.name] + async def get_m1m3_slew_controller_settings(self) -> dict: """ Retrieve the current M1M3 slew controller settings. @@ -1964,11 +1989,12 @@ async def get_m1m3_slew_controller_settings(self) -> dict: settings = {} for key, attr in expected_attributes.items(): - if not hasattr(settings_event, attr): - raise RuntimeError( - f"Expected attribute '{attr}' not found in slew controller settings event." - ) - settings[key] = getattr(settings_event, attr) + # Convert string key to enum member + enum_member = MTM1M3.SetSlewControllerSettings[key] + mapped_attr = self.map_slew_setting_to_attribute(enum_member) + if not hasattr(settings_event, mapped_attr): + raise RuntimeError(f"Expected attribute '{mapped_attr}' not found.") + settings[key] = getattr(settings_event, mapped_attr) return settings @@ -2115,31 +2141,6 @@ async def wait_m1m3_settle(self) -> None: self.log.debug("Waiting for m1m3 to settle.") await asyncio.sleep(self.m1m3_settle_time) - def _map_m1m3_slew_setting_to_name(self, slew_setting: enum.IntEnum) -> str: - """ - Map the slew setting enumeration to the corresponding key used - in the ``get_m1m3_slew_controller_settings`` method. - - Parameters - ---------- - slew_setting : enum.IntEnum - The slew setting enumeration value. - - Returns - ------- - str - The corresponding key used in the get method. - """ - mapping = { - MTM1M3.SetSlewControllerSettings.ACCELERATIONFORCES: "ACCELERATIONFORCES", - MTM1M3.SetSlewControllerSettings.BALANCEFORCES: "BALANCEFORCES", - MTM1M3.SetSlewControllerSettings.BOOSTERVALVES: "BOOSTERVALVES", - MTM1M3.SetSlewControllerSettings.VELOCITYFORCES: "VELOCITYFORCES", - } - if slew_setting not in mapping: - raise ValueError(f"Invalid slew setting: {slew_setting}") - return mapping[slew_setting] - async def set_m1m3_slew_controller_settings( self, slew_setting: enum.IntEnum, enable_slew_management: bool ) -> None: @@ -2155,7 +2156,11 @@ async def set_m1m3_slew_controller_settings( True to enable, False to disable the specified force component controlled by the slew controller. """ - setting_key = self._map_m1m3_slew_setting_to_name(slew_setting) + if not isinstance(slew_setting, MTM1M3.SetSlewControllerSettings): + raise ValueError(f"Invalid slew setting: {slew_setting}") + + setting_key = slew_setting.name + if setting_key is None: raise ValueError(f"Invalid slew setting: {slew_setting}") diff --git a/python/lsst/ts/observatory/control/mock/mtcs_async_mock.py b/python/lsst/ts/observatory/control/mock/mtcs_async_mock.py index 42cf7aa1..9b420729 100644 --- a/python/lsst/ts/observatory/control/mock/mtcs_async_mock.py +++ b/python/lsst/ts/observatory/control/mock/mtcs_async_mock.py @@ -26,6 +26,7 @@ import numpy as np from lsst.ts import idl, utils +from lsst.ts.idl.enums import MTM1M3 from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages from lsst.ts.observatory.control.mock import RemoteGroupAsyncMock @@ -173,6 +174,13 @@ async def setup_types(self) -> None: self._mthexapod_2_evt_in_position = types.SimpleNamespace(inPosition=True) self._mthexapod_2_move_task = utils.make_done_future() + self._evt_slew_controller_settings = types.SimpleNamespace( + useAccelerationForces=False, + useBalanceForces=False, + triggerBoosterValves=False, + useVelocityForces=False, + ) + async def setup_mocks(self) -> None: await self.setup_mtmount() await self.setup_mtrotator() @@ -245,6 +253,8 @@ async def setup_mtm1m3(self) -> None: "cmd_exitEngineering.start.side_effect": self.mtm1m3_cmd_exit_engineering, "cmd_testHardpoint.set_start.side_effect": self.mtm1m3_cmd_test_hardpoint, "cmd_forceActuatorBumpTest.set_start.side_effect": self.mtm1m3_cmd_force_actuator_bump_test, + "evt_slewControllerSettings.aget.side_effect": self.mtm1m3_evt_slew_controller_flags, + "cmd_setSlewControllerSettings.set_start.side_effect": self.mtm1m3_cmd_set_slew_controller_flags, } # Compatibility with xml>12 @@ -746,6 +756,47 @@ async def _mtm1m3_cmd_force_actuator_bump_test( actuator_sindex ] = utils.current_tai() + async def mtm1m3_cmd_set_slew_controller_flags( + self, *args: typing.Any, **kwargs: typing.Any + ) -> None: + # Extract parameters from kwargs + slew_setting_value = kwargs.get("slewSettings") + enable_slew_management = kwargs.get("enableSlewManagement") + + if slew_setting_value is None or enable_slew_management is None: + raise ValueError( + "slewSettings and enableSlewManagement parameters are required." + ) + + # Validate and convert the integer to the corresponding enumeration + # member name + try: + setting_enum = MTM1M3.SetSlewControllerSettings(slew_setting_value) + except ValueError: + raise ValueError(f"Invalid slew setting value: {slew_setting_value}") + + # Mapping enum names to the expected attributes + setting_attr = self.mtcs.map_slew_setting_to_attribute(setting_enum) + + if setting_attr is None: + raise ValueError(f"Invalid slew setting value: {slew_setting_value}") + + # Update the internal state to reflect the change + if hasattr(self._evt_slew_controller_settings, setting_attr): + setattr( + self._evt_slew_controller_settings, setting_attr, enable_slew_management + ) + else: + raise ValueError( + f"Unexpected error. Setting attribute '{setting_attr}' not found." + ) + + async def mtm1m3_evt_slew_controller_flags( + self, *args: typing.Any, **kwargs: typing.Any + ) -> types.SimpleNamespace: + await asyncio.sleep(self.heartbeat_time / 4.0) + return self._evt_slew_controller_settings + async def _execute_enable_hardpoint_corrections(self) -> float: for force_magnitude in range(0, 2200, 200): self._mtm1m3_evt_applied_balance_forces.forceMagnitude = force_magnitude diff --git a/tests/maintel/test_mtcs.py b/tests/maintel/test_mtcs.py index 05549330..ebc4283a 100644 --- a/tests/maintel/test_mtcs.py +++ b/tests/maintel/test_mtcs.py @@ -2015,15 +2015,12 @@ async def run_set_m1m3_slew_controller_setting_test( desired_setting: MTM1M3.SetSlewControllerSettings, desired_value: bool, ) -> None: - # Prepare initial settings - initial_settings = { - "ACCELERATIONFORCES": initial_setting_value, - "BALANCEFORCES": True, - "VELOCITYFORCES": True, - "BOOSTERVALVES": False, - } - self.mtcs.get_m1m3_slew_controller_settings = unittest.mock.AsyncMock( - return_value=initial_settings + # Set initial state directly in the mock + setting_key = desired_setting.name + setattr( + self.mtcs.rem.mtm1m3.evt_slewControllerSettings, + setting_key, + initial_setting_value, ) # Call the method to set the new setting @@ -2031,20 +2028,13 @@ async def run_set_m1m3_slew_controller_setting_test( desired_setting, desired_value ) - # Update the mock to reflect the new settings - new_settings = initial_settings.copy() - expected_key = self.mtcs._map_m1m3_slew_setting_to_name(desired_setting) - new_settings[expected_key] = desired_value - self.mtcs.get_m1m3_slew_controller_settings = unittest.mock.AsyncMock( - return_value=new_settings - ) + # Prepare expected settings for assertion + expected_settings = {setting_key: desired_value} # Assert that the settings have been correctly applied - await self.assert_m1m3_slew_settings_applied(new_settings) + await self.assert_m1m3_slew_settings_applied(expected_settings) async def test_set_m1m3_slew_controller_settings_with_invalid_setting(self) -> None: - self.mtcs.get_m1m3_slew_controller_settings = unittest.mock.AsyncMock() - # Invalid enum invalid_setting = 999