From a12d41956940ff113205a8ad698e822a628e72d4 Mon Sep 17 00:00:00 2001
From: awatlet <arnaud.watlet@umons.ac.be>
Date: Sun, 15 Oct 2023 21:10:59 +0200
Subject: [PATCH] Adds pwr_state in pwr module and refactors turn_on turn_off

---
 .../abstract_hardware_components.py           | 44 +++++++++++++------
 ohmpi/hardware_components/mb_2023_0_X.py      | 12 ++---
 ohmpi/hardware_components/pwr_batt.py         | 14 +++---
 ohmpi/hardware_components/pwr_dps5005.py      | 40 +++++++++++++----
 ohmpi/hardware_system.py                      | 29 ++++++++++--
 ohmpi/ohmpi.py                                |  3 +-
 6 files changed, 102 insertions(+), 40 deletions(-)

diff --git a/ohmpi/hardware_components/abstract_hardware_components.py b/ohmpi/hardware_components/abstract_hardware_components.py
index a3644e47..eb854748 100644
--- a/ohmpi/hardware_components/abstract_hardware_components.py
+++ b/ohmpi/hardware_components/abstract_hardware_components.py
@@ -50,7 +50,7 @@ class PwrAbstract(ABC):
         self._voltage = np.nan
         self.current_adjustable = kwargs.pop('current_adjustable', False)
         self._current = np.nan
-        self._state = 'off'
+        self._pwr_state = 'off'
         self._current_min = kwargs.pop('current_min', 0.)
         self._current_max = kwargs.pop('current_max', 0.)
         self._voltage_min = kwargs.pop('voltage_min', 0.)
@@ -69,16 +69,30 @@ class PwrAbstract(ABC):
     def current(self, value, **kwargs):
         # add actions to set the DPS current
         pass
+    #
+    # @abstractmethod
+    # def turn_off(self):
+    #     self.exec_logger.debug(f'Switching {self.model} off')
+    #     self._state = 'off'
+    #
+    # @abstractmethod
+    # def turn_on(self):
+    #     self.exec_logger.debug(f'Switching {self.model} on')
+    #     self._state = 'on'
 
-    @abstractmethod
-    def turn_off(self):
-        self.exec_logger.debug(f'Switching {self.model} off')
-        self._state = 'off'
+    @property
+    def pwr_state(self):
+        return self._pwr_state
+
+    @pwr_state.setter
+    def pwr_state(self, state):
+        if state == 'on':
+            self._pwr_state = 'on'
+            self.exec_logger.debug(f'{self.model} cannot be switched on')
+        elif state == 'off':
+            self._pwr_state = 'off'
+            self.exec_logger.debug(f'{self.model} cannot be switched off')
 
-    @abstractmethod
-    def turn_on(self):
-        self.exec_logger.debug(f'Switching {self.model} on')
-        self._state = 'on'
 
     @property
     @abstractmethod
@@ -292,7 +306,7 @@ class TxAbstract(ABC):
         pass
 
     @abstractmethod
-    def current_pulse(self, **kwargs):
+    def current_pulse(self, **kurwargs):
         pass
 
     @abstractmethod
@@ -313,16 +327,16 @@ class TxAbstract(ABC):
             injection_duration = self._injection_duration
         if np.abs(polarity) > 0:
             if switch_pwr:
-                self.pwr.turn_on()
+                self.pwr.pwr_state('on')
             self.tx_sync.set()
             time.sleep(injection_duration)
             self.tx_sync.clear()
             if switch_pwr:
-                self.pwr.turn_off()
+                self.pwr.pwr_state('off')
         else:
             self.tx_sync.set()
             if switch_pwr:
-                self.pwr.turn_off()
+                self.pwr.pwr_state('off')
             time.sleep(injection_duration)
             self.tx_sync.clear()
 
@@ -382,11 +396,13 @@ class TxAbstract(ABC):
 
     @pwr_state.setter
     def pwr_state(self, state):
-        self.exec_logger.debug(f'Power source cannot be switched on or off on {self.model}')
+
         if state == 'on':
             self._pwr_state = 'on'
+            self.exec_logger.debug(f'{self.model} cannot switch on power source')
         elif state == 'off':
             self._pwr_state = 'off'
+            self.exec_logger.debug(f'{self.model} cannot switch off power source')
 
 class RxAbstract(ABC):
     def __init__(self, **kwargs):
diff --git a/ohmpi/hardware_components/mb_2023_0_X.py b/ohmpi/hardware_components/mb_2023_0_X.py
index 43446c31..dd193360 100644
--- a/ohmpi/hardware_components/mb_2023_0_X.py
+++ b/ohmpi/hardware_components/mb_2023_0_X.py
@@ -173,12 +173,12 @@ class Tx(TxAbstract):
             self.pin0.value = False
             self.pin1.value = False
             time.sleep(self._release_delay)
-
-    def turn_off(self):
-        self.pwr.turn_off(self)
-
-    def turn_on(self):
-        self.pwr.turn_on(self)
+    #
+    # def turn_off(self):
+    #     self.pwr.turn_off(self)
+    #
+    # def turn_on(self):
+    #     self.pwr.turn_on(self)
 
     @property
     def tx_bat(self):
diff --git a/ohmpi/hardware_components/pwr_batt.py b/ohmpi/hardware_components/pwr_batt.py
index c392c38a..650b5dcd 100644
--- a/ohmpi/hardware_components/pwr_batt.py
+++ b/ohmpi/hardware_components/pwr_batt.py
@@ -25,7 +25,7 @@ class Pwr(PwrAbstract):
             self.exec_logger.event(f'{self.model}\tpwr_init\tbegin\t{datetime.datetime.utcnow()}')
         self._voltage = kwargs['voltage']
         self._current = np.nan
-        self._state = 'on'
+        # self._state = 'on'
         if not subclass_init:
             self.exec_logger.event(f'{self.model}\tpwr_init\tend\t{datetime.datetime.utcnow()}')
 
@@ -36,12 +36,12 @@ class Pwr(PwrAbstract):
     @current.setter
     def current(self, value, **kwargs):
         self.exec_logger.debug(f'Current cannot be set on {self.model}')
-
-    def turn_off(self):
-        self.exec_logger.debug(f'{self.model} cannot be turned off')
-
-    def turn_on(self):
-        self.exec_logger.debug(f'{self.model} is always on')
+    #
+    # def turn_off(self):
+    #     self.exec_logger.debug(f'{self.model} cannot be turned off')
+    #
+    # def turn_on(self):
+    #     self.exec_logger.debug(f'{self.model} is always on')
 
     @property
     def voltage(self):
diff --git a/ohmpi/hardware_components/pwr_dps5005.py b/ohmpi/hardware_components/pwr_dps5005.py
index 140924bd..c6e3a600 100644
--- a/ohmpi/hardware_components/pwr_dps5005.py
+++ b/ohmpi/hardware_components/pwr_dps5005.py
@@ -40,6 +40,7 @@ class Pwr(PwrAbstract):
         self.voltage_adjustable = True
         self.current_adjustable = False
         self._current = np.nan
+        self._pwr_state = 'off'
         if not subclass_init:
             self.exec_logger.event(f'{self.model}\tpwr_init\tend\t{datetime.datetime.utcnow()}')
 
@@ -51,14 +52,14 @@ class Pwr(PwrAbstract):
     def current(self, value, **kwargs):
         self.exec_logger.debug(f'Current cannot be set on {self.model}')
 
-    def turn_off(self):
-        self.connection.write_register(0x09, 0)
-        self.exec_logger.debug(f'{self.model} is off')
-
-    def turn_on(self):
-        self.connection.write_register(0x09, 1)
-        self.exec_logger.debug(f'{self.model} is on')
-        time.sleep(.3)
+    # def turn_off(self):
+    #     self.connection.write_register(0x09, 0)
+    #     self.exec_logger.debug(f'{self.model} is off')
+    #
+    # def turn_on(self):
+    #     self.connection.write_register(0x09, 1)
+    #     self.exec_logger.debug(f'{self.model} is on')
+    #     time.sleep(.3)
 
     @property
     def voltage(self):
@@ -76,3 +77,26 @@ class Pwr(PwrAbstract):
 
     def current_max(self, value):
         self.connection.write_register(0x0001, value * 10, 0)
+
+   def pwr_state(self):
+        return self._pwr_state
+
+    @pwr_state.setter
+    def pwr_state(self, state, latency=.3):
+        """Switches pwr on or off.
+
+            Parameters
+            ----------
+            state : str
+                'on', 'off'
+            """
+        if state == 'on':
+            self.connection.write_register(0x09, 1)
+            self._pwr_state = 'on'
+            self.exec_logger.debug(f'{self.model} is on')
+            time.sleep(latency) # from pwr specs
+
+        elif state == 'off':
+            self.connection.write_register(0x09, 0)
+            self._pwr_state = 'off'
+            self.exec_logger.debug(f'{self.model} is off')
diff --git a/ohmpi/hardware_system.py b/ohmpi/hardware_system.py
index edb8f8b1..377e624a 100644
--- a/ohmpi/hardware_system.py
+++ b/ohmpi/hardware_system.py
@@ -340,7 +340,14 @@ class OhmPiHardware:
         vab_max = np.abs(vab_max)
         vmn_min = np.abs(vmn_min)
         vab = np.min([np.abs(tx_volt), vab_max])
-        self.tx.turn_on()
+        # self.tx.turn_on()
+        switch_pwr_off, switch_tx_pwr_off = False, False #TODO: check if these should be moved in kwargs
+        if self.tx.pwr_state == 'off':
+            self.tx.pwr_state = 'on'
+            switch_tx_pwr_off = True
+        if self.tx.pwr.pwr_state == 'off':
+            self.tx.pwr.pwr_state = 'on'
+            switch_pwr_off = True
         if 1. / self.rx.sampling_rate > pulse_duration:
             sampling_rate = 1. / pulse_duration  # TODO: check this...
         else:
@@ -362,7 +369,11 @@ class OhmPiHardware:
             self.tx.exec_logger.warning(f'Unknown strategy {strategy} for setting VAB! Using {vab} V')
         else:
             self.tx.exec_logger.debug(f'Constant strategy for setting VAB, using {vab} V')
-        self.tx.turn_off()
+        # self.tx.turn_off()
+        if switch_pwr_off:
+            self.tx.pwr.pwr_state = 'off'
+        if switch_tx_pwr_off:
+            self.tx.pwr_state = 'off'
         rab = (np.abs(vab) * 1000.) / iab
         self.exec_logger.debug(f'RAB = {rab:.2f} Ohms')
         if vmn < 0:
@@ -401,9 +412,12 @@ class OhmPiHardware:
     def vab_square_wave(self, vab, cycle_duration, sampling_rate=None, cycles=3, polarity=1, duty_cycle=1.,
                         append=False):
         self.exec_logger.event(f'OhmPiHardware\tvab_square_wave\tbegin\t{datetime.datetime.utcnow()}')
-        switch_pwr_off = False
+        switch_pwr_off, switch_tx_pwr_off = False, False
         if self.tx.pwr_state == 'off':
             self.tx.pwr_state = 'on'
+            switch_tx_pwr_off = True
+        if self.tx.pwr.pwr_state == 'off':
+            self.tx.pwr.pwr_state = 'on'
             switch_pwr_off = True
         self._gain_auto()
         assert 0. <= duty_cycle <= 1.
@@ -419,6 +433,8 @@ class OhmPiHardware:
         self._vab_pulses(vab, durations, sampling_rate, polarities=polarities,  append=append)
         self.exec_logger.event(f'OhmPiHardware\tvab_square_wave\tend\t{datetime.datetime.utcnow()}')
         if switch_pwr_off:
+            self.tx.pwr.pwr_state = 'off'
+        if switch_tx_pwr_off:
             self.tx.pwr_state = 'off'
     def _vab_pulse(self, vab=None, duration=1., sampling_rate=None, polarity=1, append=False):
         """ Gets VMN and IAB from a single voltage pulse
@@ -442,10 +458,13 @@ class OhmPiHardware:
         self.tx.polarity = 0   #TODO: is this necessary?
 
     def _vab_pulses(self, vab, durations, sampling_rate, polarities=None, append=False):
-        switch_pwr_off = False
+        switch_pwr_off, switch_tx_pwr_off = False, False
         if self.tx.pwr_state == 'off':
             self.tx.pwr_state = 'on'
             switch_pwr_off = True
+        if self.tx.pwr.pwr_state == 'off':
+            self.tx.pwr.pwr_state = 'on'
+            switch_pwr_off = True
         n_pulses = len(durations)
         self.exec_logger.debug(f'n_pulses: {n_pulses}')
         if self.tx.pwr.voltage_adjustable:
@@ -464,6 +483,8 @@ class OhmPiHardware:
             self._vab_pulse(vab=vab, duration=durations[i], sampling_rate=sampling_rate, polarity=polarities[i],
                             append=True)
         if switch_pwr_off:
+            self.tx.pwr.pwr_state = 'off'
+        if switch_tx_pwr_off:
             self.tx.pwr_state = 'off'
     def switch_mux(self, electrodes, roles=None, state='off', **kwargs):
         """Switches on multiplexer relays for given quadrupole.
diff --git a/ohmpi/ohmpi.py b/ohmpi/ohmpi.py
index e4724a51..135cf0cb 100644
--- a/ohmpi/ohmpi.py
+++ b/ohmpi/ohmpi.py
@@ -423,7 +423,7 @@ class OhmPi(object):
         # TODO: add sampling_interval -> impact on _hw.rx.sampling_rate (store the current value, change the _hw.rx.sampling_rate, do the measurement, reset the sampling_rate to the previous value)
         # TODO: default value of tx_volt and other parameters set to None should be given in config.py and used in function definition
         # TODO: add rs_check option (or propose an other way to do this)
-        # TODO: better way of handling default settings
+        # TODO: implement compute_tx_volt for injection strategies
         """Measures on a quadrupole and returns transfer resistance.
 
         Parameters
@@ -871,6 +871,7 @@ class OhmPi(object):
             - export_path (path where to export the data, timestamp will be added to filename ;
                             if export_path is given, it goes over export_dir and export_name)
 
+
         Parameters
         ----------
         settings : str, dict
-- 
GitLab