Also fix decimal handling for Melcor floats based on DECIMAL_1 during writes.
[pypid.git] / pypid / backend / melcor.py
index f0a5c92e5e25fe0e02378c9280c03d6582ad951c..c3924d3e1095c78e138f8458f9c532935942be4c 100644 (file)
@@ -26,6 +26,7 @@ from .. import LOG as _LOG
 from . import Backend as _Backend
 from . import ManualMixin as _ManualMixin
 from . import PIDMixin as _PIDMixin
+from . import TemperatureMixin as _TemperatureMixin
 
 
 class Register (object):
@@ -94,16 +95,14 @@ class FloatRegister (Register):
         return _struct.unpack('h', _struct.pack('H', melcor))[0] / decimal
 
     def encode(self, value, **kwargs):
-        if self.decimal:
-            decimal = self.decimal
-        elif self.decimal_offset:
+        decimal = self.decimal
+        if self.decimal_offset:
             decimal *= self.decimal_offset
         return self._float2melcor(value, decimal)
 
     def decode(self, value, decimal=None):
-        if self.decimal:
-            decimal = self.decimal
-        elif self.decimal_offset:
+        decimal = self.decimal
+        if self.decimal_offset:
             decimal *= self.decimal_offset
         return self._melcor2float(value, decimal)
 
@@ -124,9 +123,17 @@ class BoundedFloatRegister (FloatRegister):
         return super(BoundedFloatRegister, self).decode(value, **kwargs)
 
 
-class MelcorBackend (_Backend, _ManualMixin, _PIDMixin):
+class MelcorBackend (_Backend, _ManualMixin, _PIDMixin, _TemperatureMixin):
     """Temperature control backend for a Melcor MTCA Temperature Controller
+
+    * PV: process temperature
+    * PV-units: degrees Celsius
+    * MV: controller current
+    * MV-units: amps
     """
+    pv_units = 'C'
+    mv_units = 'A'
+
     # Relative register addresses from back page of Melcor Manual.
     # Then I went through Chapter 6 tables looking for missing
     # registers.  References are from Series MTCA Thermoelectric
@@ -447,8 +454,10 @@ class MelcorBackend (_Backend, _ManualMixin, _PIDMixin):
         register = self._register[register_name]
         if 'r' not in register.direction:
             raise ValueError(register_name)
-        if register.needs_decimal and not self._decimal:
-            self._decimal = self._get_decimal()
+        if register.needs_decimal:
+            if not self._decimal:
+                self._decimal = self._get_decimal()
+            register.decimal = self._decimal
         rc = self._client.read_holding_registers(
             address=register.value, count=1, unit=self._controller)
         assert rc.function_code < 0x80
@@ -461,8 +470,10 @@ class MelcorBackend (_Backend, _ManualMixin, _PIDMixin):
         register = self._register[register_name]
         if 'w' not in register.direction:
             raise ValueError(register_name)
-        if register.needs_decimal and not self._decimal:
-            self._decimal = self._get_decimal()
+        if register.needs_decimal:
+            if not self._decimal:
+                self._decimal = self._get_decimal()
+            register.decimal = self._decimal
         v = register.encode(value, decimal=self._decimal)
         _LOG.info('write %s: %s (%s)' % (register_name, v, value))
         rc = self._client.write_register(
@@ -474,13 +485,13 @@ class MelcorBackend (_Backend, _ManualMixin, _PIDMixin):
 
     # Support for Backend methods
 
-    def get_temp(self):
+    def get_pv(self):
         return self._read('HIGH_RESOLUTION')
 
-    def get_ambient_temp(self):
+    def get_ambient_pv(self):
         return self._convert_F_to_C(self._read('AMBIENT_TEMPERATURE'))
 
-    def set_max_current(self, max):
+    def set_max_mv(self, max):
         """Set the max current in Amps
 
         0.2 A is the default max current since it seems ok to use
@@ -496,7 +507,7 @@ class MelcorBackend (_Backend, _ManualMixin, _PIDMixin):
         self._write('HIGH_POWER_LIMIT_BELOW', max_percent)
         self._max_current = max
 
-    def get_max_current(self):
+    def get_max_mv(self):
         percent = self._read('HIGH_POWER_LIMIT_ABOVE')
         above = percent/100. * self._spec_max_current
         percent = self._read('HIGH_POWER_LIMIT_BELOW')
@@ -506,7 +517,7 @@ class MelcorBackend (_Backend, _ManualMixin, _PIDMixin):
         self._max_current = above
         return above
 
-    def get_current(self):
+    def get_mv(self):
         pout = self._read('PERCENT_OUTPUT')
         cur = self._spec_max_current * pout / 100.0
         return cur
@@ -529,7 +540,7 @@ class MelcorBackend (_Backend, _ManualMixin, _PIDMixin):
 
     # ManualMixin methods
 
-    def set_current(self, current):
+    def set_mv(self, current):
         if current > self._spec_max_current:
             raise ValueError('current {} exceeds spec maximum {}'.format(
                     current, self._spec_max_current))
@@ -588,22 +599,21 @@ class MelcorBackend (_Backend, _ManualMixin, _PIDMixin):
         proportional = max_current/propband
         return (proportional, integral, derivative)
 
-    def set_cooling_gains(self, proportional=None, integral=None,
-                          derivative=None):
+    def set_down_gains(self, proportional=None, integral=None,
+                       derivative=None):
         self._set_gains(
             output=1, proportional=proportional, integral=integral,
             derivative=derivative)
 
-    def get_cooling_gains(self):
+    def get_down_gains(self):
         return self._get_gains(output=1)
 
-    def set_heating_gains(self, proportional=None, integral=None,
-                          derivative=None):
+    def set_up_gains(self, proportional=None, integral=None, derivative=None):
         self._set_gains(
             output=2, proportional=proportional, integral=integral,
             derivative=derivative)
 
-    def get_heating_gains(self):
+    def get_up_gains(self):
         return self._get_gains(output=2)
 
     def get_feedback_terms(self):