diff --git a/schunk_egu_egk_gripper_dummy/config/data.json b/schunk_egu_egk_gripper_dummy/config/data.json index 6f6eabe..371216e 100644 --- a/schunk_egu_egk_gripper_dummy/config/data.json +++ b/schunk_egu_egk_gripper_dummy/config/data.json @@ -1,6 +1,6 @@ { "0x0040": [ - "800000800000A25800000000000000EF" + "800000800000A25800000000D90000EF" ], "0x0048": [ "05000000000000000000000000000000" diff --git a/schunk_egu_egk_gripper_dummy/doc/plc_diagnostics_double_word.png b/schunk_egu_egk_gripper_dummy/doc/plc_diagnostics_double_word.png new file mode 100644 index 0000000..f16354b Binary files /dev/null and b/schunk_egu_egk_gripper_dummy/doc/plc_diagnostics_double_word.png differ diff --git a/schunk_egu_egk_gripper_dummy/src/dummy.py b/schunk_egu_egk_gripper_dummy/src/dummy.py index 1fde9fe..15b09be 100644 --- a/schunk_egu_egk_gripper_dummy/src/dummy.py +++ b/schunk_egu_egk_gripper_dummy/src/dummy.py @@ -15,6 +15,8 @@ def __init__(self): self.data = None self.plc_input = "0x0040" self.plc_output = "0x0048" + self.error_byte = 12 + self.diagnostics_byte = 15 self.reserved_status_bits = [10, 15] + list(range(18, 31)) enum_config = os.path.join( @@ -122,3 +124,25 @@ def get_status_bit(self, bit: int) -> int | bool: return False byte_index, bit_index = divmod(bit, 8) return 1 if self.plc_input_buffer[byte_index] & (1 << bit_index) != 0 else 0 + + def set_status_error(self, error: str) -> bool: + try: + self.plc_input_buffer[self.error_byte] = int(error, 16) + return True + except ValueError: + return False + + def get_status_error(self) -> str: + return hex(self.plc_input_buffer[self.error_byte]).replace("0x", "").upper() + + def set_status_diagnostics(self, diagnostics: str) -> bool: + try: + self.plc_input_buffer[self.diagnostics_byte] = int(diagnostics, 16) + return True + except ValueError: + return False + + def get_status_diagnostics(self) -> str: + return ( + hex(self.plc_input_buffer[self.diagnostics_byte]).replace("0x", "").upper() + ) 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 3a719a3..1034227 100644 --- a/schunk_egu_egk_gripper_dummy/tests/test_plc_communication.py +++ b/schunk_egu_egk_gripper_dummy/tests/test_plc_communication.py @@ -52,17 +52,46 @@ def test_dummy_only_touches_specified_bits(): assert dummy.get_plc_input() == before +def test_dummy_supports_reading_and_writing_status_error(): + dummy = Dummy() + error_codes = ["AA", "bb", "0xcc"] + expected = ["AA", "BB", "CC"] + for error, expected in zip(error_codes, expected): + dummy.set_status_error(error) + assert dummy.get_status_error() == expected + + +def test_dummy_rejects_writing_invalid_status_error(): + dummy = Dummy() + invalid_codes = ["zz", "-1", "aaa"] + for error in invalid_codes: + assert not dummy.set_status_error(error) + + +def test_dummy_supports_reading_and_writing_status_diagnostics(): + dummy = Dummy() + diagnostics_code = "EF" + dummy.set_status_diagnostics(diagnostics_code) + assert dummy.get_status_diagnostics() == diagnostics_code + + +def test_dummy_rejects_writing_invalid_status_diagnostics(): + dummy = Dummy() + invalid_codes = ["zz", "-1", "aaa"] + for code in invalid_codes: + assert not dummy.set_status_diagnostics(code) + + # See p. 24 in # Booting and establishing operational readiness [1] -@pytest.mark.skip() def test_dummy_starts_in_error_state(): dummy = Dummy() - query = {"inst": dummy.plc_input, "count": 1} - data = dummy.get_data(query)[0] - assert data[0:2] == "80" - assert data[30:] == "D9" # ERR_FAST_STOP + assert dummy.get_status_bit(0) == 0 # not ready for operation + assert dummy.get_status_bit(7) == 1 # there's an error + assert dummy.get_status_error() == "D9" # ERR_FAST_STOP + assert dummy.get_status_diagnostics() == "EF" # ERR_COMM_LOST @pytest.mark.skip()