From d2bb9589df068508886929ef958f0ae90b1779f0 Mon Sep 17 00:00:00 2001 From: Stefan Scherzinger Date: Tue, 30 Jul 2024 19:15:38 +0200 Subject: [PATCH] Implement reading and writing bits in the plc status dword --- schunk_egu_egk_gripper_dummy/src/dummy.py | 21 +++++++++++ .../tests/test_plc_communication.py | 36 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/schunk_egu_egk_gripper_dummy/src/dummy.py b/schunk_egu_egk_gripper_dummy/src/dummy.py index 4e451cc..1fde9fe 100644 --- a/schunk_egu_egk_gripper_dummy/src/dummy.py +++ b/schunk_egu_egk_gripper_dummy/src/dummy.py @@ -15,6 +15,7 @@ def __init__(self): self.data = None self.plc_input = "0x0040" self.plc_output = "0x0048" + self.reserved_status_bits = [10, 15] + list(range(18, 31)) enum_config = os.path.join( Path(__file__).resolve().parents[1], "config/enum.json" @@ -101,3 +102,23 @@ def get_plc_input(self): def get_plc_output(self): return [self.plc_output_buffer.hex().upper()] + + def set_status_bit(self, bit: int, value: bool) -> bool: + if bit < 0 or bit > 31: + return False + if bit in self.reserved_status_bits: + return False + byte_index, bit_index = divmod(bit, 8) + if value: + self.plc_input_buffer[byte_index] |= 1 << bit_index + else: + self.plc_input_buffer[byte_index] &= ~(1 << bit_index) + return True + + def get_status_bit(self, bit: int) -> int | bool: + if bit < 0 or bit > 31: + return False + if bit in self.reserved_status_bits: + return False + byte_index, bit_index = divmod(bit, 8) + return 1 if self.plc_input_buffer[byte_index] & (1 << bit_index) != 0 else 0 diff --git a/schunk_egu_egk_gripper_dummy/tests/test_plc_communication.py b/schunk_egu_egk_gripper_dummy/tests/test_plc_communication.py index cfd9c73..3a719a3 100644 --- a/schunk_egu_egk_gripper_dummy/tests/test_plc_communication.py +++ b/schunk_egu_egk_gripper_dummy/tests/test_plc_communication.py @@ -16,6 +16,42 @@ def test_dummy_returns_plc_data(): assert dummy.data[dummy.plc_output] == dummy.get_plc_output() +def test_dummy_rejects_writing_reserved_status_bits(): + dummy = Dummy() + invalid_bits = [-1, 999] + for bit in invalid_bits + dummy.reserved_status_bits: + assert not dummy.set_status_bit(bit, True) + + +def test_dummy_rejects_reading_reserved_status_bits(): + dummy = Dummy() + for bit in dummy.reserved_status_bits: + assert isinstance(dummy.get_status_bit(bit), bool) # call fails + assert not dummy.get_status_bit(bit) + + +def test_dummy_supports_reading_and_writing_bits_in_plc_status(): + dummy = Dummy() + valid_bits = list(range(0, 10)) + [11, 12, 13, 14, 16, 17, 31] + for bit in valid_bits: + dummy.set_status_bit(bit=bit, value=True) + result = dummy.get_status_bit(bit=bit) + assert isinstance(result, int) # successful calls get the bit's value + assert result == 1 + + +def test_dummy_only_touches_specified_bits(): + dummy = Dummy() + before = dummy.get_plc_input() + valid_bits = list(range(0, 10)) + [11, 12, 13, 14, 16, 17, 31] + for bit in valid_bits: + initial_value = dummy.get_status_bit(bit=bit) + dummy.set_status_bit(bit=bit, value=True) + dummy.set_status_bit(bit=bit, value=initial_value) + + assert dummy.get_plc_input() == before + + # See p. 24 in # Booting and establishing operational readiness [1]