Merge branch 'remove-implicit-relative-imports'
[pycomedi.git] / pycomedi / calibration.pyx
index 49f0028526b4a592d5ff2e2c9f04670e19cdd818..cac765a4345977cad8f7cc0e3fcebf451f6c35fd 100644 (file)
@@ -26,14 +26,15 @@ from libc cimport string as _string
 cimport numpy as _numpy
 import numpy as _numpy
 
-cimport _comedi_h
-cimport _comedilib_h
-import _error
-import constant as _constant
-import utility as _utility
+from pycomedi cimport _comedi_h
+from pycomedi cimport _comedilib_h
+from . import _error
+from . import constant as _constant
+from . import utility as _utility
 
 
-cdef void _python_to_charp(char **charp, object obj, object encoding):
+cdef void _python_to_charp(
+    char **charp, object obj, object encoding) except *:
     """Convert a Python string into a `char *`.
 
     Cython automatically converts string or byte array to a `char *`
@@ -58,7 +59,8 @@ cdef void _python_to_charp(char **charp, object obj, object encoding):
     charp[0] = ret
 
 cdef void _setup_comedi_polynomial_t(
-    _comedilib_h.comedi_polynomial_t *p, coefficients, expansion_origin):
+    _comedilib_h.comedi_polynomial_t *p, coefficients, expansion_origin
+    ) except *:
     """Setup the `comedi_polynomial_t` at `p`
 
     * `coefficients` is an iterable containing polynomial coefficients
@@ -161,11 +163,32 @@ cdef class CalibratedConverter (object):
     1.0
     >>> c.get_to_physical_coefficients()
     array([ 1.,  2.,  3.])
+
+    For some soft-calibrated boards, there is no from_physical
+    conversion polynomial.
+
+    >>> c = CalibratedConverter(
+    ...     from_physical_error=Exception('no conversion polynomial'))
+    >>> c.from_physical(1.0)
+    Traceback (most recent call last):
+      ...
+    Exception: no conversion polynomial
+
+    However, even with the error, you can extract dummy coefficients.
+
+    >>> c.get_from_physical_expansion_origin()
+    0.0
+    >>> c.get_from_physical_coefficients()
+    array([ 0.])
     """
+    def __cinit__(self):
+        self._from_physical_error = None
+
     def __init__(self, to_physical_coefficients=None,
                  to_physical_expansion_origin=0,
                  from_physical_coefficients=None,
-                 from_physical_expansion_origin=0):
+                 from_physical_expansion_origin=0,
+                 from_physical_error=None):
         if to_physical_coefficients:
             _setup_comedi_polynomial_t(
                 &self._to_physical, to_physical_coefficients,
@@ -174,6 +197,7 @@ cdef class CalibratedConverter (object):
             _setup_comedi_polynomial_t(
                 &self._from_physical, from_physical_coefficients,
                  from_physical_expansion_origin)
+        self._from_physical_error = from_physical_error
 
     cdef _str_poly(self, _comedilib_h.comedi_polynomial_t polynomial):
         return '{coefficients:%s origin:%s}' % (
@@ -194,6 +218,8 @@ cdef class CalibratedConverter (object):
                         _constant.CONVERSION_DIRECTION.to_physical)
 
     cpdef from_physical(self, data):
+        if self._from_physical_error is not None:
+            raise self._from_physical_error
         return _convert(&self._from_physical, data,
                         _constant.CONVERSION_DIRECTION.from_physical)
 
@@ -316,11 +342,11 @@ cdef class CalibrationSetting (object):
 
     >>> c = d.parse_calibration()
     >>> s = c.settings[0]
-
     >>> print(s)
     <CalibrationSetting device:/dev/comedi0 subdevice:0>
     >>> print(s.subdevice)  # doctest: +ELLIPSIS
     <pycomedi.subdevice.Subdevice object at 0x...>
+
     >>> for s in c.settings:
     ...     print('{} {}'.format(s.subdevice.index, s.subdevice.get_type()))
     ...     print('  channels: {}'.format(s.channels))
@@ -425,10 +451,33 @@ cdef class CalibrationSetting (object):
         from physical coefficients: [ 0.]
         from physical origin: 0.0
 
+    Test setting various attributes.
+
+    >>> s = c.settings[-1]
+    >>> s.channels = [0, 1, 2]
+    >>> s.channels
+    array([0, 1, 2])
+    >>> s.ranges = [0, 1]
+    >>> s.ranges
+    array([0, 1])
+    >>> s.arefs = [0]
+    >>> s.arefs
+    array([0])
+    >>> caldacs = []
+    >>> for i in range(3):
+    ...     caldac = Caldac()
+    ...     caldac.allocate()
+    ...     caldac.subdevice = i
+    ...     caldac.channel = 2*i
+    ...     caldac.value = 3*i
+    ...     caldacs.append(caldac)
+    >>> s.caldacs = caldacs
+
     >>> d.close()
     """
     def __cinit__(self):
         self.setting = NULL
+        self.subdevice = None
 
     def __init__(self, subdevice):
         super(CalibrationSetting, self).__init__()
@@ -508,6 +557,7 @@ cdef class CalibrationSetting (object):
             self.setting.arefs[i] = x
         for i in range(length, _comedilib_h.CS_MAX_AREFS_LENGTH):
             self.setting.arefs[i] = 0
+        self.setting.num_arefs = length
     arefs = property(fget=_arefs_get, fset=_arefs_set)
 
     def _caldacs_get(self):
@@ -522,6 +572,8 @@ cdef class CalibrationSetting (object):
             c.caldac = &self.setting.caldacs[i]
             ret.append(c)
         return ret
+    cdef _caldacs_set_single(self, index, Caldac caldac):
+        self.setting.caldacs[index] = caldac.caldac[0]
     def _caldacs_set(self, value):
         assert self.setting is not NULL, 'load setting first'
         if self.setting.caldacs is not NULL:
@@ -536,7 +588,7 @@ cdef class CalibrationSetting (object):
         for i,x in enumerate(value):
             if i >= length:
                 raise ValueError((i, length))
-            self.setting.caldacs[i] = x
+            self._caldacs_set_single(i, x)
     caldacs = property(fget=_caldacs_get, fset=_caldacs_set)
 
     def _soft_calibration_get(self):
@@ -608,6 +660,7 @@ cdef class Calibration (object):
     """
     def __cinit__(self):
         self.calibration = NULL
+        self.device = None
 
     def __init__(self, device):
         super(Calibration, self).__init__()
@@ -648,7 +701,7 @@ cdef class Calibration (object):
             return None
         ret = []
         for i in range(self.calibration.num_settings):
-            s = CalibrationSetting(
+            s = <CalibrationSetting> CalibrationSetting(
                 subdevice=self.device.subdevice(
                     index=self.calibration.settings[i].subdevice))
             s.setting = &self.calibration.settings[i]