コード例 #1
0
    def test_change_setpoint(self):
        self.hwc.abs_acceleration = float('inf')

        # Changing the setpoint while the pump is off shouldn't affect the
        # frequency immediately.
        self.parameters[24].value[0] = Uint(1234, 16)
        time.sleep(2 * self.hwc.step)
        reply = self.send(flag_bits=[])
        self.assertEqual(reply.frequency, 0)

        # However, after sending the on command the frequency becomes equal to
        # the checkpoint.
        # Send the on command.
        self.send(flag_bits=[ControlBits.COMMAND, ControlBits.ON])
        time.sleep(2 * self.hwc.step)
        # Ask for pump status.
        reply = self.send(flag_bits=[ControlBits.COMMAND, ControlBits.ON])
        self.assertEqual(reply.frequency, 1234)

        # Change the setpoint to a bigger value.
        self.parameters[24].value[0] = Uint(4567, 16)
        time.sleep(2 * self.hwc.step)
        reply = self.send(flag_bits=[ControlBits.COMMAND, ControlBits.ON])
        self.assertEqual(reply.frequency, 4567)

        # Change the setpoint to a smaller value.
        self.parameters[24].value[0] = Uint(89, 16)
        time.sleep(2 * self.hwc.step)
        reply = self.send(flag_bits=[ControlBits.COMMAND, ControlBits.ON])
        self.assertEqual(reply.frequency, 89)
コード例 #2
0
def dummy_parameter(number=1, 
                    name='Test parameter',  
                    indices=range(0), 
                    min_value=Uint(0, 16), 
                    max_value=Uint(65535, 16),
                    default=Uint(0, 16), 
                    unit='', 
                    writable=True, 
                    datatype=Uint, 
                    bits=16, 
                    description='Test description.'):
    """Create a Parameter object where all fields take default values unless 
    otherwise specified in the arguments.
    """
    return Parameter(number=number,
                     name=name,
                     indices=indices, 
                     min_value=min_value, 
                     max_value=max_value, 
                     default=default, 
                     unit=unit, 
                     writable=writable, 
                     datatype=datatype,
                     bits=bits,
                     description=description)
コード例 #3
0
    def set_up_parameters(self):
        def dp(number, indexed, default):
            indices = range(1, 4) if indexed else range(0)
            return dummy_parameter(number=number,
                                   indices=indices,
                                   default=default)

        self.unindexed = dp(1, False, Uint(1, 16))
        self.single = dp(2, True, Uint(2, 16))
        self.multiple = dp(3, True, [Uint(3, 16), Uint(4, 16), Uint(5, 16)])

        parameters = [self.unindexed, self.single, self.multiple]
        return {p.number: p for p in parameters}
コード例 #4
0
ファイル: telegram.py プロジェクト: fkivela/TurboCtl
    def parameter_error(self):
        """Return the parameter error.
        
        Returns:
            A member of the :class:`~turboctl.telegram.codes.ParameterError` 
            enum, or ``None``, if :attr:`parameter_mode` isn't ``'error'``.
            
        Raises:
            ValueError: If the error number isn't valid.
        """
        # The error code could be easily read from parameter_value
        # (which could be changed to always give the value as an Uint if
        # parameter_mode is 'error'). This property mostly exists to aid in
        # debugging; __str__ displays its value, which makes it easy to see
        # which error has occurred without looking up the meaning of the error
        # code.
        # There's no equivalent TelegramBuilder.set_error_code method, because
        # it isn't really needed, and adding that bit of symmetry wouldn't be
        # worth the increased complexity.

        if self.parameter_mode != 'error':
            return None
        
        number = Uint(self.telegram.parameter_value).value
        try:
            return ParameterError(number)
        except KeyError:
            raise ValueError(f'invalid parameter error number: {number}')
コード例 #5
0
 def test_indexed_multiple(self):
     """Test an indexed parameter with multiple default values."""
     values = [Uint(x, 16) for x in (3, 4, 5)]
     self.assertEqual(self.pc.parameters[3].value, values)
     self.read_test(self.multiple.number, value=3, index=1)
     self.read_test(self.multiple.number, value=4, index=2)
     self.read_test(self.multiple.number, value=5, index=3)
コード例 #6
0
 def test_default_int(self):
     parameter = dummy_parameter_from_line(default='10')
     self.assertEqual(parameter.default, Uint(10, 16))
     
     parameter = dummy_parameter_from_line(
         default='-10', format_='s16')
     self.assertEqual(parameter.default, Sint(-10, 16))
コード例 #7
0
ファイル: telegram.py プロジェクト: fkivela/TurboCtl
 def set_parameter_number(self, value: int):
     """Set the parameter number.
     
     Raises:
         ValueError: If there isn't a parameter with the specified number.
     """
     self._kwargs['parameter_number'] = Uint(value, 11)
     return self
コード例 #8
0
ファイル: telegram.py プロジェクト: fkivela/TurboCtl
 def __init__(self, parameters=PARAMETERS):
     """
     __init__(parameters=PARAMETERS)
     
     Initialize a new :class:`TelegramBuilder`.
     
     Args:
         parameters: The object to be assigned to :attr:`parameters`.
     """
     self.parameters = parameters
     
     # Keyword arguments used to create a telegram.
     self._kwargs = {
         'parameter_code':   Bin(4 * '0', bits=4),
         'parameter_number': Uint(0,  bits=11),
         'parameter_index':  Uint(0,  bits=8),
         'parameter_value':  Uint(0,  bits=32),
         'flag_bits':        Bin(16 * '0', bits=16),
         'frequency':        Uint(0,  bits=16),
         'temperature':      Sint(0,  bits=16),
         'current':          Uint(0,  bits=16,),
         'voltage':          Uint(0,  bits=16),
     }
     # parameter_value and parameter_mode are special cases.
     # These variables store the values given by the user, and the final
     # values used as arguments are only determined when the telegram is
     # created.
     
     # __init__ and set_parameter_value set this to a int or a float,
     # and from_bytes to a bytes object.
     self._parameter_value = 0
     
     # __init__ and set_parameter_mode set this to a string, and from_bytes
     # to a Bin object.
     self._parameter_mode = 'none'
コード例 #9
0
 def test_all_maxes_are_data_or_references(self):
     
     for parameter in PARAMETERS.values():
         value = parameter.max_value
         
         # Convert a string value 'P<number>' to an Uint:
         try:
             if value[0] == 'P':
                 value = Uint(int(value[1:]))
         except (TypeError, ValueError):
             pass
         
         self.assertIsInstance(value, (Uint, Sint, Float))  
コード例 #10
0
ファイル: telegram.py プロジェクト: fkivela/TurboCtl
    def from_bytes(self, bytes_):
        """Read the contents of the telegram from a :class:`bytes` object.
        
        The type of :attr:`parameter_value <Telegram.parameter_value>`
        depends on :attr:`parameter_number <Telegram.parameter_number>`,
        and is assigned automatically. If *bytes_* contains a parameter 
        number that doesn't exist, a :class:`ValueError` is raised.
        
        If the parameter isn't accessed (i.e. the parameter mode is set to 
        ``'none'`` or code to ``'0000'``), invalid parameter numbers, such as
        the default value of 0, are permitted.
        In that case, the parameter type is set to
        :class:`~turboctl.telegram.datatypes.Uint`.
        
        Note that this isn't a class method; a :class:`TelegramBuilder` must
        first be initialized normally with :meth:`__init__`, after which
        this method may be called.
        
        Raises:
            ValueError: If *bytes_* doesn't represent a valid telegram.
        """
        self._check_valid_telegram(bytes_)
        
        code_and_number_bits = Bin(bytes_[3:5])    
        self._kwargs = {
            'parameter_number':     Uint(code_and_number_bits[5:16]),
            'parameter_index':      Uint(bytes_[6]),
            'flag_bits':            Bin(bytes_[11:13])[::-1],
            'frequency':            Uint(bytes_[13:15]),
            'temperature':          Sint(bytes_[15:17]),
            'current':              Uint(bytes_[17:19]),
            'voltage':              Uint(bytes_[21:23])        
        }
        
        self._parameter_value = bytes_[7:11]
        self._parameter_mode = Bin(code_and_number_bits[0:4])

        return self
コード例 #11
0
ファイル: telegram.py プロジェクト: fkivela/TurboCtl
 def __bytes__(self):
     """Return the telegram as a :class:`bytes` object.
     
     The checksum is computed automatically and added to the end.
     """
     bytes_ = bytes(
         Uint(2, 8) +
         Uint(22, 8) +
         Uint(0, 8) +
         self.parameter_code + 
         Bin('0') + 
         self.parameter_number + 
         Uint(0, 8) + 
         self.parameter_index + 
         self.parameter_value +
         self.flag_bits[::-1] +    
         self.frequency +
         self.temperature +
         self.current + 
         Uint(0, 16) +
         self.voltage
     )
     return bytes_ + bytes([checksum(bytes_)])
コード例 #12
0
ファイル: telegram.py プロジェクト: fkivela/TurboCtl
 def set_parameter_index(self, value: int):
     """Set the parameter index."""
     self._kwargs['parameter_index'] = Uint(value, bits=8)
     return self
コード例 #13
0
 def test_uint_with_negative_value_raises_ValueError(self):
     with self.assertRaises(ValueError):
         Uint(-123)
コード例 #14
0
 def test_indexed_default_with_a_single_value(self):
     parameter = dummy_parameter_from_line(number='1[1:3]', default='3')
     self.assertEqual(parameter.default, Uint(3, 16))
コード例 #15
0
 def test_indexed_default_with_multiple_values(self):
     parameter = dummy_parameter_from_line(
         number='1[1:3]', default='[3,2,1]')
     
     self.assertEqual(
         parameter.default, [Uint(3, 16), Uint(2, 16), Uint(1, 16)])
コード例 #16
0
ファイル: telegram.py プロジェクト: fkivela/TurboCtl
 def set_current(self, value):
     """Set the current."""
     self._kwargs['current'] = Uint(value, bits=16)
     return self
コード例 #17
0
ファイル: telegram.py プロジェクト: fkivela/TurboCtl
 def set_frequency(self, value: int):
     """Set the frequency."""
     self._kwargs['frequency'] = Uint(value, bits=16)
     return self
コード例 #18
0
 def test_indexed_one(self):
     """Test an indexed parameter with one default value."""
     values = 3 * [Uint(2, 16)]
     self.assertEqual(self.pc.parameters[2].value, values)
     self.read_test(self.single.number, 2)
コード例 #19
0
 def test_unindexed(self):
     """Test an unindexed parameter."""
     self.assertEqual(self.pc.parameters[1].value, [Uint(1, 16)])
     self.read_test(self.unindexed.number, 1)
コード例 #20
0
ファイル: telegram.py プロジェクト: fkivela/TurboCtl
 def set_voltage(self, value):
     """Set the voltage."""
     self._kwargs['voltage'] = Uint(value, bits=16)
     return self
コード例 #21
0
 def test_uint_from_int_sets_attributes_correctly(self, i_and_bits):
     i, bits = i_and_bits
     uint = Uint(i, bits)
     self.assertEqual(uint.value, i)
     self.assertEqual(uint.bits, bits)
コード例 #22
0
 def test_bits_default_value(self):
     self.assertEqual(Uint(1).bits, 8)
     self.assertEqual(Sint(-1).bits, 8)
     self.assertEqual(Float(1.0).bits, 32)
     self.assertEqual(Float(1).bits, 32)
     self.assertEqual(Bin(1).bits, 8)