diff --git a/src/pymodaq_plugins_slmsuite/hardware/slm_controller.py b/src/pymodaq_plugins_slmsuite/hardware/slm_controller.py index 228c4e6..3b2beaf 100644 --- a/src/pymodaq_plugins_slmsuite/hardware/slm_controller.py +++ b/src/pymodaq_plugins_slmsuite/hardware/slm_controller.py @@ -127,5 +127,19 @@ def get_phase(self) -> np.ndarray: phase = self.slm.phase return np.asarray(phase.get() if hasattr(phase, 'get') else phase) + def set_wavelength(self, wav_um: float): + """Change the working wavelength of the open SLM (microns) + + slmsuite reads ``wav_um`` each time it converts a phase into grey levels. The design wavelength follows it if + it was the same (default of slmsuite), keeping ``phase_scaling`` at 1. The Holoeye SDK also has to know it. + """ + old = self.slm.wav_um + if self.slm.wav_design_um == old: + self.slm.wav_design_um = float(wav_um) + self.slm.wav_um = float(wav_um) + slm_lib = getattr(self.slm, 'slm_lib', None) + if self.slm_type == 'Holoeye' and slm_lib is not None: + self.slm._handle_error(slm_lib.setWavelength(wav_um * 1000)) + def close(self): self.slm.close() diff --git a/src/pymodaq_plugins_slmsuite/resources/daq_move_SlmsuiteBase.py b/src/pymodaq_plugins_slmsuite/resources/daq_move_SlmsuiteBase.py index 9c70b18..e1dde92 100644 --- a/src/pymodaq_plugins_slmsuite/resources/daq_move_SlmsuiteBase.py +++ b/src/pymodaq_plugins_slmsuite/resources/daq_move_SlmsuiteBase.py @@ -47,7 +47,8 @@ class DAQ_Move_SlmsuiteBase(DAQ_Move_base): ]}, {'title': 'Wavelength (nm):', 'name': 'wavelength_nm', 'type': 'float', 'value': config('slm', 'wavelength_nm'), 'min': 1., - 'tip': 'Working wavelength, used by slmsuite to convert phases into grey levels. Needs a re-initialization.'}, + 'tip': 'Working wavelength, used by slmsuite to convert phases into grey levels. Imposed by the BeamShaping ' + 'extension (setup preference) when it is loaded. A change is applied directly to the open SLM.'}, {'title': 'Apply phase correction:', 'name': 'phase_correct', 'type': 'bool', 'value': True, 'tip': 'Add the wavefront correction loaded in slmsuite (if any) to the displayed phases'}, {'title': 'Input as grey levels:', 'name': 'input_as_grey_levels', 'type': 'bool', 'value': False, @@ -89,7 +90,8 @@ def close(self): self.controller.close() def commit_settings(self, param: Parameter): - pass + if param.name() == 'wavelength_nm' and self.controller is not None and self.is_master: + self.controller.set_wavelength(param.value() / 1000) def get_actuator_value(self) -> DataActuator: """The phase (radians) that the SLM displays""" diff --git a/tests/test_slmsuite_plugins.py b/tests/test_slmsuite_plugins.py index 5594525..751a762 100644 --- a/tests/test_slmsuite_plugins.py +++ b/tests/test_slmsuite_plugins.py @@ -255,3 +255,33 @@ def test_holoeye_preview_can_be_enabled(monkeypatch): def test_holoeye_sdk_without_preview_option(monkeypatch): _open_holoeye(monkeypatch, FakeHEDSWithoutOption) assert FakeHEDSWithoutOption.SLM.calls == [('index:0',)] + + +class TestWavelengthUpdate: + def test_changed_after_the_init(self, slm): + param = slm.settings.child('wavelength_nm') + param.setValue(800.) + slm.commit_settings(param) # called by the DAQ_Move when a setting changes + slm_object = slm.controller.slm + assert slm_object.wav_um == pytest.approx(0.8) + assert slm_object.phase_scaling == 1 # design wavelength follows the working one + + # the phase is converted with the new wavelength, without re-initialization + slm.controller.show_phase(np.full((HEIGHT, WIDTH), 1.)) + assert slm.initialized + + def test_design_wavelength_chosen_by_the_user_is_kept(self): + controller = SlmController('SimulatedSLM', resolution=(WIDTH, HEIGHT), wav_um=0.5, wav_design_um=1.) + controller.set_wavelength(0.8) + assert (controller.slm.wav_um, controller.slm.wav_design_um) == (0.8, 1.) + controller.close() + + def test_holoeye_sdk_is_told(self): + calls = [] + slm_object = SimpleNamespace(wav_um=0.5, wav_design_um=0.5, _handle_error=calls.append, + slm_lib=SimpleNamespace(setWavelength=lambda nm: calls.append(nm) or 0)) + controller = SlmController.__new__(SlmController) + controller.slm_type, controller.slm = 'Holoeye', slm_object + controller.set_wavelength(0.8) + assert calls == [800., 0] + assert slm_object.wav_um == 0.8