diff --git a/README.rst b/README.rst index 478b555..7cca8e6 100644 --- a/README.rst +++ b/README.rst @@ -50,6 +50,12 @@ The CAN messages in a SAE J1939 network are called Protocol Data Units (PDUs). This definition is not completely correct, but close enough to think of PDUs as the CAN messages. +============================== =========== +Library Version Python +------------------------------ ----------- + 2.0.13+ 3.9+ +============================== =========== + Features -------- diff --git a/j1939/Dm14Server.py b/j1939/Dm14Server.py index c039a1b..1011e20 100644 --- a/j1939/Dm14Server.py +++ b/j1939/Dm14Server.py @@ -124,48 +124,47 @@ def parse_dm14( self.length = len(data) self.direct = data[1] >> 4 - match self.state: - case ResponseState.IDLE: - self.pgn = pgn - self.sa = sa - self.status = j1939.Dm15Status.PROCEED.value - self.address = data[2 : (self.length - 2)] - self.direct = data[1] >> 4 - self.command = ((data[1] - 1) & 0x0F) >> 1 - self.pointer_type = (data[1] >> 4) & 0x1 - self.object_count = data[0] - self.access_level = (data[self.length - 1] << 8) + data[self.length - 2] - self.data = data - if self._key_from_seed is not None: - self.state = ResponseState.WAIT_FOR_KEY - self._pgn = j1939.ParameterGroupNumber.PGN.DM15 - self._send_dm15( - self.length, - self.direct, - self.status, - self.state, - self.object_count, - self.sa, - ) - else: - self.state = ResponseState.SEND_PROCEED - - case ResponseState.WAIT_FOR_KEY: - self.length = len(data) - self.address = data[2 : (self.length - 2)] - self.command = ((data[1] - 1) & 0x0F) >> 1 - self.object_count = data[0] - self.key = (data[self.length - 1] << 8) + data[self.length - 2] - self.data = data + if self.state == ResponseState.IDLE: + self.pgn = pgn + self.sa = sa + self.status = j1939.Dm15Status.PROCEED.value + self.address = data[2: (self.length - 2)] + self.direct = data[1] >> 4 + self.command = ((data[1] - 1) & 0x0F) >> 1 + self.pointer_type = (data[1] >> 4) & 0x1 + self.object_count = data[0] + self.access_level = (data[self.length - 1] << 8) + data[self.length - 2] + self.data = data + if self._key_from_seed is not None: + self.state = ResponseState.WAIT_FOR_KEY + self._pgn = j1939.ParameterGroupNumber.PGN.DM15 + self._send_dm15( + self.length, + self.direct, + self.status, + self.state, + self.object_count, + self.sa, + ) + else: self.state = ResponseState.SEND_PROCEED - case ResponseState.WAIT_OPERATION_COMPLETE: - self.state = ResponseState.IDLE - self.sa = None - self._ca.unsubscribe(self.parse_dm14) + elif self.state == ResponseState.WAIT_FOR_KEY: + self.length = len(data) + self.address = data[2: (self.length - 2)] + self.command = ((data[1] - 1) & 0x0F) >> 1 + self.object_count = data[0] + self.key = (data[self.length - 1] << 8) + data[self.length - 2] + self.data = data + self.state = ResponseState.SEND_PROCEED - case _: - raise ValueError("Invalid state") + elif self.state == ResponseState.WAIT_OPERATION_COMPLETE: + self.state = ResponseState.IDLE + self.sa = None + self._ca.unsubscribe(self.parse_dm14) + + else: + raise ValueError("Invalid state") def _send_dm15( self, @@ -195,33 +194,33 @@ def _send_dm15( self._pgn = j1939.ParameterGroupNumber.PGN.DM15 data = [0xFF] * length data[1] = (direct << 4) + (status << 1) + 1 - match state: - case ResponseState.WAIT_FOR_KEY: - self.seed = self._seed_generator() - data[0] = 0x00 - data[length - 2] = self.seed & 0xFF - data[length - 1] = self.seed >> 8 - - case ResponseState.SEND_PROCEED: - data[0] = object_count - - case ResponseState.SEND_OPERATION_COMPLETE: - self.command = j1939.Command.OPERATION_COMPLETED.value - data[0] = 0x00 - data[1] = (direct << 4) + (self.command << 1) + 1 - self.state = ResponseState.WAIT_OPERATION_COMPLETE - - case ResponseState.SEND_ERROR: - status = j1939.Dm15Status.OPERATION_FAILED.value - data[0] = 0x00 - data[1] = (direct << 4) + (status << 1) + 1 - data[length - 6] = error & 0xFF - data[length - 5] = (error >> 8) & 0xFF - data[length - 4] = error >> 16 - data[length - 3] = edcp - - case _: - raise ValueError("Invalid state") + if self.state == ResponseState.WAIT_FOR_KEY: + self.seed = self._seed_generator() + data[0] = 0x00 + data[length - 2] = self.seed & 0xFF + data[length - 1] = self.seed >> 8 + + elif self.state == ResponseState.SEND_PROCEED: + data[0] = object_count + + elif self.state == ResponseState.SEND_OPERATION_COMPLETE: + self.command = j1939.Command.OPERATION_COMPLETED.value + data[0] = 0x00 + data[1] = (direct << 4) + (self.command << 1) + 1 + self.state = ResponseState.WAIT_OPERATION_COMPLETE + + elif self.state == ResponseState.SEND_ERROR: + status = j1939.Dm15Status.OPERATION_FAILED.value + data[0] = 0x00 + data[1] = (direct << 4) + (status << 1) + 1 + data[length - 6] = error & 0xFF + data[length - 5] = (error >> 8) & 0xFF + data[length - 4] = error >> 16 + data[length - 3] = edcp + + else: + raise ValueError("Invalid state") + self._ca.send_pgn(0, (pgn >> 8) & 0xFF, sa & 0xFF, 6, data) def _send_dm16(self) -> None: diff --git a/j1939/memory_access.py b/j1939/memory_access.py index 434f798..762d3ae 100644 --- a/j1939/memory_access.py +++ b/j1939/memory_access.py @@ -37,14 +37,50 @@ def _listen_for_dm14( :param data: Data of the PDU """ if pgn == j1939.ParameterGroupNumber.PGN.DM14: - match self.state: - case DMState.IDLE: - if self.server.state.value == DMState.IDLE.value: - self.state = DMState.REQUEST_STARTED - self.server.parse_dm14(priority, pgn, sa, timestamp, data) - if not self.seed_security: - self.state = DMState.WAIT_RESPONSE - self._ca.unsubscribe(self._listen_for_dm14) + if self.state == DMState.IDLE: + if self.server.state.value == DMState.IDLE.value: + self.state = DMState.REQUEST_STARTED + self.server.parse_dm14(priority, pgn, sa, timestamp, data) + if not self.seed_security: + self.state = DMState.WAIT_RESPONSE + self._ca.unsubscribe(self._listen_for_dm14) + if self._proceed_function is not None: + self.proceed = self._proceed_function( + self.server.command, + int.from_bytes( + bytes=self.server.address, + byteorder="little", + signed=False, + ), + self.server.pointer_type, + self.server.length, + self.server.object_count, + 0xFFFF, # placeholder for key + self.server.sa, + self.server.access_level, + 0x0, # placeholder for seed + ) # call proceed function and pass in basic parameters + if self.proceed: + self._notify_query_received() # notify incoming request + else: + self.server.error = 0x100 + self.server.set_busy(True) + self.server.parse_dm14( + priority, pgn, sa, timestamp, data + ) + self.server.set_busy(False) + self.server.reset_query() + self.state = DMState.IDLE + self.server.error = 0x0 + + elif self.state == DMState.REQUEST_STARTED: + self.server.parse_dm14(priority, pgn, sa, timestamp, data) + if self.server.state == j1939.ResponseState.SEND_PROCEED: + self.state = DMState.WAIT_RESPONSE + if self.seed_security: + if self.server.verify_key( + self.server.seed, self.server.key + ): if self._proceed_function is not None: self.proceed = self._proceed_function( self.server.command, @@ -56,10 +92,10 @@ def _listen_for_dm14( self.server.pointer_type, self.server.length, self.server.object_count, - 0xFFFF, # placeholder for key + self.server.key, self.server.sa, self.server.access_level, - 0x0, # placeholder for seed + self.server.seed, ) # call proceed function and pass in basic parameters if self.proceed: self._notify_query_received() # notify incoming request @@ -73,59 +109,22 @@ def _listen_for_dm14( self.server.reset_query() self.state = DMState.IDLE self.server.error = 0x0 + else: + self.server.error = 0x1003 + self.server.set_busy(True) + self.server.parse_dm14( + priority, pgn, sa, timestamp, data + ) + self.server.set_busy(False) + self.state = DMState.IDLE + self.server.error = 0x0 - case DMState.REQUEST_STARTED: - self.server.parse_dm14(priority, pgn, sa, timestamp, data) - if self.server.state == j1939.ResponseState.SEND_PROCEED: - self.state = DMState.WAIT_RESPONSE - if self.seed_security: - if self.server.verify_key( - self.server.seed, self.server.key - ): - if self._proceed_function is not None: - self.proceed = self._proceed_function( - self.server.command, - int.from_bytes( - bytes=self.server.address, - byteorder="little", - signed=False, - ), - self.server.pointer_type, - self.server.length, - self.server.object_count, - self.server.key, - self.server.sa, - self.server.access_level, - self.server.seed, - ) # call proceed function and pass in basic parameters - if self.proceed: - self._notify_query_received() # notify incoming request - else: - self.server.error = 0x100 - self.server.set_busy(True) - self.server.parse_dm14( - priority, pgn, sa, timestamp, data - ) - self.server.set_busy(False) - self.server.reset_query() - self.state = DMState.IDLE - self.server.error = 0x0 - else: - self.server.error = 0x1003 - self.server.set_busy(True) - self.server.parse_dm14( - priority, pgn, sa, timestamp, data - ) - self.server.set_busy(False) - self.state = DMState.IDLE - self.server.error = 0x0 - - case DMState.WAIT_QUERY: - self.server.set_busy(True) - self.server.parse_dm14(priority, pgn, sa, timestamp, data) - self.server.set_busy(False) - case _: - pass + elif self.state == DMState.WAIT_QUERY: + self.server.set_busy(True) + self.server.parse_dm14(priority, pgn, sa, timestamp, data) + self.server.set_busy(False) + else: + pass def respond( self, diff --git a/setup.py b/setup.py index 8885ff7..389e05e 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,9 @@ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Intended Audience :: Developers", "Topic :: Scientific/Engineering" ],