From 46181bcd7917433930e5651fc420ef7a9e9cef20 Mon Sep 17 00:00:00 2001 From: sonelu Date: Wed, 3 Jun 2020 09:10:32 +0000 Subject: [PATCH 1/7] changed "mask" to "bits" --- roboglia/base/register.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/roboglia/base/register.py b/roboglia/base/register.py index 9c0d450..cf0067d 100644 --- a/roboglia/base/register.py +++ b/roboglia/base/register.py @@ -389,29 +389,29 @@ class BoolRegister(BaseRegister): Parameters ---------- - mask: int or ``None`` - An optional mask to use in the determination of the output of the - register. Default is None and in this case we simply compare the + bits: int or ``None`` + An optional bit pattern to use in the determination of the output of + the register. Default is None and in this case we simply compare the internal value with 0. mode: str ('all' or 'any') - Indicates how the mask should be used: 'all' means all the bits - in the mask must match while 'any' - means any bit that matches the mask is enough to result in a ``True`` - external value. Only used if mask is not ``None``. Default is 'any'. + Indicates how the bit pattern should be used: 'all' means all the bits + in the pattern must match while 'any' + means any bit that matches the pattern is enough to result in a ``True`` + external value. Only used if bits is not ``None``. Default is 'any'. """ - def __init__(self, mask=None, mode='any', **kwargs): + def __init__(self, bits=None, mode='any', **kwargs): super().__init__(**kwargs) - if mask: - check_type(mask, int, 'register', self.name, logger) + if bits: + check_type(bits, int, 'register', self.name, logger) check_options(mode, ['all', 'any'], 'register', self.name, logger) - self.__mask = mask + self.bit = bits self.__mode = mode @property - def mask(self): - """The mask used.""" - return self.__mask + def bits(self): + """The bit pattern used.""" + return self.__bits @property def mode(self): @@ -421,12 +421,12 @@ def mode(self): def value_to_external(self, value): """The external representation of bool register. """ - if self.mask is None: + if self.bits is None: return bool(value) if self.mode == 'any': - return bool(value & self.mask) + return bool(value & self.bits) if self.mode == 'all': - return (value & self.mask) == self.mask + return (value & self.bits) == self.bits raise NotImplementedError def value_to_internal(self, value): @@ -434,8 +434,8 @@ def value_to_internal(self, value): """ if not value: return 0 - if self.mask: - return self.mask + if self.bits: + return self.bits return 1 From 8e065ac390048c9a60fddd7a3ca471551e332ecf Mon Sep 17 00:00:00 2001 From: sonelu Date: Wed, 3 Jun 2020 09:17:29 +0000 Subject: [PATCH 2/7] removed mask; could be handled by the register --- roboglia/base/sensor.py | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/roboglia/base/sensor.py b/roboglia/base/sensor.py index 01a9fe3..756d47c 100644 --- a/roboglia/base/sensor.py +++ b/roboglia/base/sensor.py @@ -27,7 +27,7 @@ class Sensor(): to a register in that device that represents the value the sensor is representing. In addition a sensor can have an optional register used to activate or deactivate the device and can publish a ``value`` that - can be either boolean if the ``mask`` parameter is used or float, in + can be either boolean if the ``bits`` parameter is used or float, in which case the sensor can also apply an ``inverse`` and and ``offset`` to the values read from the device registry. @@ -53,19 +53,12 @@ class Sensor(): Indicates if the value read from the register should be inverted before being presented to the user in the :py:meth:`value`. The inverse operation is performed before the ``offset`` (see below). - Default is ``False``. It is ignored if ``mask`` property is used. + Default is ``False``. It is ignored if ``bits`` property is used. offset: float Indicates an offest to be adder to the value read from the register (after ``inverse`` if ``True``). Default is 0.0. It is ignored if - ``mask`` property is used. - - mask: int - A bit mask used to AND the value read from device. After the AND is - performed the :py:meth:`value` will return ``True`` or ``False`` if - the result is different than 0 or not. If ``mask`` is used, the - paramters ``inverse`` and ``offset`` are ignored. If no mask is - needed, use ``None``. This is also the default. + ``bits`` property is used. auto: bool Indicates if the sensor should be automatically activated when the @@ -73,7 +66,7 @@ class Sensor(): Default is ``True``. """ def __init__(self, name='SENSOR', device=None, value_read=None, - activate=None, inverse=False, offset=0.0, mask=None, + activate=None, inverse=False, offset=0.0, auto=True, **kwargs): self.__name = name check_not_empty(device, 'device', 'sensor', self.name, logger) @@ -95,7 +88,6 @@ def __init__(self, name='SENSOR', device=None, value_read=None, self.__inverse = inverse check_type(offset, float, 'sensor', self.name, logger) self.__offset = offset - self.__mask = mask check_options(auto, [True, False], 'joint', self.name, logger) self.__auto_activate = auto @@ -165,10 +157,6 @@ def offset(self): """(read-only) The offset between sensor coords and device coords.""" return self.__offset - @property - def mask(self): - """The (optional) bit mask to interpret the sensor data.""" - return self.__mask @property def value(self): @@ -177,17 +165,14 @@ def value(self): Returns ------- bool or float: - If ``mask`` is used the sensor is assumed to produce a ``float`` - response resulted from the AND between the value of the register - in the device and the mask. If not mask is used the sensor is - assumed to produce a float value that is adjusted with the + The value of the register is adjusted with the ``offset`` and the ``inverse`` attributes. """ reg_value = self.read_register.value - if self.mask: - # boolean value - return (reg_value & self.mask) != 0 - # float value + if isinstance(reg_value, bool): + # bool return + return ~ reg_value if self.inverse else reg_value + # float return if self.inverse: reg_value = - reg_value return reg_value + self.offset From c22d281dadbb10ab9e38c3e6cf11f435ae95968c Mon Sep 17 00:00:00 2001 From: sonelu Date: Wed, 3 Jun 2020 09:31:13 +0000 Subject: [PATCH 3/7] changed mask to bits --- roboglia/base/devices/DUMMY.yml | 6 +++--- roboglia/dynamixel/devices/AX-12A.yml | 28 +++++++++++++-------------- roboglia/dynamixel/devices/AX-18A.yml | 28 +++++++++++++-------------- tests/i2c_robot.yml | 4 ++-- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/roboglia/base/devices/DUMMY.yml b/roboglia/base/devices/DUMMY.yml index 08cf58f..f42e125 100644 --- a/roboglia/base/devices/DUMMY.yml +++ b/roboglia/base/devices/DUMMY.yml @@ -114,7 +114,7 @@ registers: address: 99 clone: True class: BoolRegister - mask: 0b00000001 + bits: 0b00000001 status_2and3: @@ -122,12 +122,12 @@ registers: clone: True access: RW class: BoolRegister - mask: 0b00000110 + bits: 0b00000110 mode: all status_2or3: address: 99 clone: True class: BoolRegister - mask: 0b00000110 + bits: 0b00000110 mode: any diff --git a/roboglia/dynamixel/devices/AX-12A.yml b/roboglia/dynamixel/devices/AX-12A.yml index 583fec9..3a0825b 100644 --- a/roboglia/dynamixel/devices/AX-12A.yml +++ b/roboglia/dynamixel/devices/AX-12A.yml @@ -140,49 +140,49 @@ registers: clone: True class: BoolRegister access: RW - mask: 0b01000000 + bits: 0b01000000 alarm_overload_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00100000 + bits: 0b00100000 alarm_checksum_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00010000 + bits: 0b00010000 alarm_range_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00001000 + bits: 0b00001000 alarm_overheating_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000100 + bits: 0b00000100 alarm_anglelimit_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000010 + bits: 0b00000010 alarm_inputvoltage_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000001 + bits: 0b00000001 shutdown: address: 18 @@ -194,49 +194,49 @@ registers: clone: True class: BoolRegister access: RW - mask: 0b01000000 + bits: 0b01000000 shutdown_overload_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00100000 + bits: 0b00100000 shutdown_checksum_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00010000 + bits: 0b00010000 shutdown_range_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00001000 + bits: 0b00001000 shutdown_overheating_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000100 + bits: 0b00000100 shutdown_anglelimit_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000010 + bits: 0b00000010 shutdown_inputvoltage_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000001 + bits: 0b00000001 torque_enable: class: BoolRegister diff --git a/roboglia/dynamixel/devices/AX-18A.yml b/roboglia/dynamixel/devices/AX-18A.yml index fbe663d..b1dc409 100644 --- a/roboglia/dynamixel/devices/AX-18A.yml +++ b/roboglia/dynamixel/devices/AX-18A.yml @@ -140,49 +140,49 @@ registers: clone: True class: BoolRegister access: RW - mask: 0b01000000 + bits: 0b01000000 alarm_overload_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00100000 + bits: 0b00100000 alarm_checksum_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00010000 + bits: 0b00010000 alarm_range_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00001000 + bits: 0b00001000 alarm_overheating_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000100 + bits: 0b00000100 alarm_anglelimit_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000010 + bits: 0b00000010 alarm_inputvoltage_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000001 + bits: 0b00000001 shutdown: address: 18 @@ -194,49 +194,49 @@ registers: clone: True class: BoolRegister access: RW - mask: 0b01000000 + bits: 0b01000000 shutdown_overload_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00100000 + bits: 0b00100000 shutdown_checksum_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00010000 + bits: 0b00010000 shutdown_range_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00001000 + bits: 0b00001000 shutdown_overheating_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000100 + bits: 0b00000100 shutdown_anglelimit_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000010 + bits: 0b00000010 shutdown_inputvoltage_error: address: 17 clone: True class: BoolRegister access: RW - mask: 0b00000001 + bits: 0b00000001 torque_enable: class: BoolRegister diff --git a/tests/i2c_robot.yml b/tests/i2c_robot.yml index 1199a63..11e1656 100644 --- a/tests/i2c_robot.yml +++ b/tests/i2c_robot.yml @@ -58,13 +58,13 @@ i2crobot: class: Sensor device: imu value_read: status - mask: 0b00000001 + bits: 0b00000001 status1: class: Sensor device: imu value_read: status - mask: 0b00000010 + bits: 0b00000010 groups: imu: From 7dc8b1fd2fdd2349aced911cccd131fd4f39bdbe Mon Sep 17 00:00:00 2001 From: sonelu Date: Wed, 3 Jun 2020 09:53:18 +0000 Subject: [PATCH 4/7] updated from mask to bits and test --- roboglia/base/register.py | 7 ++++--- roboglia/base/sensor.py | 1 - roboglia/i2c/devices/DUMMY.yml | 15 +++++++++++++++ tests.py | 5 +++-- tests/i2c_robot.yml | 6 ++---- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/roboglia/base/register.py b/roboglia/base/register.py index cf0067d..1979e64 100644 --- a/roboglia/base/register.py +++ b/roboglia/base/register.py @@ -397,15 +397,16 @@ class BoolRegister(BaseRegister): mode: str ('all' or 'any') Indicates how the bit pattern should be used: 'all' means all the bits in the pattern must match while 'any' - means any bit that matches the pattern is enough to result in a ``True`` - external value. Only used if bits is not ``None``. Default is 'any'. + means any bit that matches the pattern is enough to result in a + ``True`` external value. Only used if bits is not ``None``. Default + is 'any'. """ def __init__(self, bits=None, mode='any', **kwargs): super().__init__(**kwargs) if bits: check_type(bits, int, 'register', self.name, logger) check_options(mode, ['all', 'any'], 'register', self.name, logger) - self.bit = bits + self.__bits = bits self.__mode = mode @property diff --git a/roboglia/base/sensor.py b/roboglia/base/sensor.py index 756d47c..893e04b 100644 --- a/roboglia/base/sensor.py +++ b/roboglia/base/sensor.py @@ -157,7 +157,6 @@ def offset(self): """(read-only) The offset between sensor coords and device coords.""" return self.__offset - @property def value(self): """Returns the value of the sensor. diff --git a/roboglia/i2c/devices/DUMMY.yml b/roboglia/i2c/devices/DUMMY.yml index 7866549..4720f71 100644 --- a/roboglia/i2c/devices/DUMMY.yml +++ b/roboglia/i2c/devices/DUMMY.yml @@ -94,3 +94,18 @@ registers: address: 23 access: RW default: 0b01010101 + + status01: + address: 23 + class: BoolRegister + access: RW + clone: True + bits: 0b00000001 + + status10: + address: 23 + class: BoolRegister + access: RW + clone: True + bits: 0b00000010 + \ No newline at end of file diff --git a/tests.py b/tests.py index 65fce27..5c2af82 100644 --- a/tests.py +++ b/tests.py @@ -276,7 +276,7 @@ def test_sensor_info(self, mock_robot): assert s.read_register == d.current_voltage assert s.activate_register is None assert s.active - assert s.mask is None + # assert s.bits is None assert s.offset == 0 assert not s.inverse assert s.auto_activate @@ -865,7 +865,8 @@ def test_i2c_sensor(self, mock_robot_init, caplog): assert s.read_register == d.temp assert s.activate_register == d.activate_temp assert not s.active - assert s.mask is None + # removed the masking in sensor + # assert s.bits is None assert s.offset == 0 assert s.inverse assert s.auto_activate diff --git a/tests/i2c_robot.yml b/tests/i2c_robot.yml index 11e1656..c4380bd 100644 --- a/tests/i2c_robot.yml +++ b/tests/i2c_robot.yml @@ -57,14 +57,12 @@ i2crobot: status0: class: Sensor device: imu - value_read: status - bits: 0b00000001 + value_read: status01 status1: class: Sensor device: imu - value_read: status - bits: 0b00000010 + value_read: status10 groups: imu: From 58a6db42c4650958f08dd17fef47d14b83ba5a21 Mon Sep 17 00:00:00 2001 From: sonelu Date: Wed, 3 Jun 2020 10:37:47 +0000 Subject: [PATCH 5/7] added partial bit masking "mask" fix #74 --- roboglia/base/devices/DUMMY.yml | 11 +++++++++-- roboglia/base/register.py | 35 +++++++++++++++++++++++++++------ tests.py | 7 +++++++ 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/roboglia/base/devices/DUMMY.yml b/roboglia/base/devices/DUMMY.yml index f42e125..efb7310 100644 --- a/roboglia/base/devices/DUMMY.yml +++ b/roboglia/base/devices/DUMMY.yml @@ -109,14 +109,12 @@ registers: access: RW class: BoolRegister - status_one: address: 99 clone: True class: BoolRegister bits: 0b00000001 - status_2and3: address: 99 clone: True @@ -131,3 +129,12 @@ registers: class: BoolRegister bits: 0b00000110 mode: any + + status_masked: + address: 99 + clone: True + access: RW + class: BoolRegister + bits: 0b10100000 + mask: 0b11110000 + mode: all diff --git a/roboglia/base/register.py b/roboglia/base/register.py index 1979e64..4989f24 100644 --- a/roboglia/base/register.py +++ b/roboglia/base/register.py @@ -400,14 +400,24 @@ class BoolRegister(BaseRegister): means any bit that matches the pattern is enough to result in a ``True`` external value. Only used if bits is not ``None``. Default is 'any'. + + mask: int or ``None`` + An optional maks that allows for partial bit handling on the + internal values. This mask permits handling only the specified bits + without affecting the other ones in the internal value. For instance + if the mask is 0b00001111 then the operations (setter, getter) will + only affect the most significant 4 bits of the register. """ - def __init__(self, bits=None, mode='any', **kwargs): + def __init__(self, bits=None, mode='any', mask=None, **kwargs): super().__init__(**kwargs) if bits: check_type(bits, int, 'register', self.name, logger) check_options(mode, ['all', 'any'], 'register', self.name, logger) + if mask: + check_type(mask, int, 'register', self.name, logger) self.__bits = bits self.__mode = mode + self.__mask = mask @property def bits(self): @@ -419,11 +429,19 @@ def mode(self): """The bitmasking mode ('all' or 'any').""" return self.__mode + @property + def mask(self): + """The partial bitmask for the handling of the bits.""" + return self.__mask + def value_to_external(self, value): """The external representation of bool register. """ if self.bits is None: return bool(value) + # this assumes that if a mask is used the bits in the ``bits`` + # attribute are all 0 already and we don't need to AND the ``mask`` + # with the bits if self.mode == 'any': return bool(value & self.bits) if self.mode == 'all': @@ -433,11 +451,16 @@ def value_to_external(self, value): def value_to_internal(self, value): """The internal representation of the register's value. """ - if not value: - return 0 - if self.bits: - return self.bits - return 1 + if not self.mask: + if not value: + return 0 + if self.bits: + return self.bits + return 1 + else: + # the int() below is to remove a linter error + masked_int_value = self.int_value & (~ int(self.mask)) + return self.bits | masked_int_value class RegisterWithConversion(BaseRegister): diff --git a/tests.py b/tests.py index 5c2af82..3311bec 100644 --- a/tests.py +++ b/tests.py @@ -88,6 +88,13 @@ def test_register_bool(self, mock_robot): assert device.status_2and3.value assert device.status_2and3.int_value == 0b00000110 + def test_register_bool_with_mask(self, mock_robot): + device = mock_robot.devices['d03'] + assert not device.status_masked.value + device.status_masked.value = True + assert device.status_masked.value + assert device.status_masked.int_value == 0b10100101 + def test_register_with_conversion(self, mock_robot, caplog): reg = mock_robot.devices['d03'].desired_pos assert isinstance(reg, RegisterWithConversion) From 61a82db325e468f0523d4843161a64bd17009c4e Mon Sep 17 00:00:00 2001 From: sonelu Date: Wed, 3 Jun 2020 10:39:50 +0000 Subject: [PATCH 6/7] fix #72 --- roboglia/dynamixel/sync.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/roboglia/dynamixel/sync.py b/roboglia/dynamixel/sync.py index 46755b1..20c1236 100644 --- a/roboglia/dynamixel/sync.py +++ b/roboglia/dynamixel/sync.py @@ -66,8 +66,7 @@ def atomic(self): result = self.gsw.txPacket() self.bus.stop_using() # !! as soon as possible error = self.gsw.ph.getTxRxResult(result) - logger.debug(f'[sync write {self.name}] for register ' - f'{reg_name}, result: {error}') + logger.debug(f'[sync write {self.name}], result: {error}') if result != 0: logger.error(f'failed to execute SyncWrite {self.name}: ' f'cerr={error}') From 335705df9dd92820274b5d094962b7de536eba47 Mon Sep 17 00:00:00 2001 From: sonelu Date: Wed, 3 Jun 2020 10:57:49 +0000 Subject: [PATCH 7/7] codefactor --- roboglia/base/devices/DUMMY.yml | 2 +- roboglia/base/register.py | 6 +++--- roboglia/i2c/devices/DUMMY.yml | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/roboglia/base/devices/DUMMY.yml b/roboglia/base/devices/DUMMY.yml index efb7310..e1f7036 100644 --- a/roboglia/base/devices/DUMMY.yml +++ b/roboglia/base/devices/DUMMY.yml @@ -137,4 +137,4 @@ registers: class: BoolRegister bits: 0b10100000 mask: 0b11110000 - mode: all + mode: all diff --git a/roboglia/base/register.py b/roboglia/base/register.py index 4989f24..659aca4 100644 --- a/roboglia/base/register.py +++ b/roboglia/base/register.py @@ -457,10 +457,10 @@ def value_to_internal(self, value): if self.bits: return self.bits return 1 - else: + # else: not really needed # the int() below is to remove a linter error - masked_int_value = self.int_value & (~ int(self.mask)) - return self.bits | masked_int_value + masked_int_value = self.int_value & (~ int(self.mask)) + return self.bits | masked_int_value class RegisterWithConversion(BaseRegister): diff --git a/roboglia/i2c/devices/DUMMY.yml b/roboglia/i2c/devices/DUMMY.yml index 4720f71..b5b5c7b 100644 --- a/roboglia/i2c/devices/DUMMY.yml +++ b/roboglia/i2c/devices/DUMMY.yml @@ -108,4 +108,3 @@ registers: access: RW clone: True bits: 0b00000010 - \ No newline at end of file