Skip to content

Commit 976b197

Browse files
authored
Refactoring J2534 (#289)
Refactoring J2534 - More readable TxStatus, ConnectFlags and RxStatus; - Add method check_connection_opened(); - Fixing overcalling PassThruReadMsgs: Increase Timeout(from 1 to 100 ms) in call PassThruReadMsgs. - Ignore start_of_message, limit=20 - Improve KLine connection - Improve K-Line set filters
1 parent 7cea1dc commit 976b197

2 files changed

Lines changed: 147 additions & 108 deletions

File tree

udsoncan/connections.py

Lines changed: 50 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
_import_isotp_err = e
2424

2525
try:
26-
from udsoncan.j2534 import J2534, TxStatusFlag, Protocol_ID, Error_ID, Ioctl_Flags, Ioctl_ID, SCONFIG_LIST
26+
from udsoncan.j2534 import J2534, Protocol_ID, Error_ID, Ioctl_Flags, Ioctl_ID, SCONFIG_LIST
2727
_import_j2534_err = None
2828
except Exception as e:
2929
_import_j2534_err = e
@@ -63,8 +63,7 @@ def send(self, data: Union[bytes, Request, Response], timeout: Optional[float] =
6363
6464
:returns: None
6565
"""
66-
if not self.is_open():
67-
raise RuntimeError("Connection is not opened")
66+
self.check_connection_opened()
6867

6968
if isinstance(data, Request) or isinstance(data, Response):
7069
payload = data.get_payload()
@@ -79,6 +78,10 @@ def send(self, data: Union[bytes, Request, Response], timeout: Optional[float] =
7978
else:
8079
self.specific_send(payload)
8180

81+
def check_connection_opened(self) -> None:
82+
if not self.is_open():
83+
raise RuntimeError(self.__class__.__name__ + ' is not opened')
84+
8285
def wait_frame(self, timeout: Optional[float] = None, exception: bool = False) -> Optional[bytes]:
8386
"""Waits for the reception of a frame of data from the underlying transport protocol
8487
@@ -92,8 +95,7 @@ def wait_frame(self, timeout: Optional[float] = None, exception: bool = False) -
9295
:returns: Received data
9396
:rtype: bytes or None
9497
"""
95-
if not self.is_open():
96-
raise RuntimeError("Connection is not opened")
98+
self.check_connection_opened()
9799

98100
try:
99101
frame = self.specific_wait_frame(timeout=timeout)
@@ -243,21 +245,13 @@ def specific_send(self, payload: bytes, timeout: Optional[float] = None) -> None
243245
self.sock.send(payload)
244246

245247
def specific_wait_frame(self, timeout: Optional[float] = None) -> Optional[bytes]:
246-
if not self.opened:
247-
raise RuntimeError("Connection is not open")
248+
self.check_connection_opened()
248249

249-
timedout = False
250-
frame = None
251250
try:
252-
frame = self.rxqueue.get(block=True, timeout=timeout)
251+
return self.rxqueue.get(block=True, timeout=timeout)
253252
except queue.Empty:
254-
timedout = True
255-
256-
if timedout:
257253
raise TimeoutException("Did not received frame in time (timeout=%s sec)" % timeout)
258254

259-
return frame
260-
261255
def empty_rxqueue(self) -> None:
262256
while not self.rxqueue.empty():
263257
self.rxqueue.get()
@@ -359,22 +353,13 @@ def specific_send(self, payload: bytes, timeout: Optional[float] = None) -> None
359353
self.tpsock.send(payload)
360354

361355
def specific_wait_frame(self, timeout: Optional[float] = None) -> Optional[bytes]:
362-
if not self.opened:
363-
raise RuntimeError("Connection is not open")
356+
self.check_connection_opened()
364357

365-
timedout = False
366-
frame = None
367358
try:
368-
frame = self.rxqueue.get(block=True, timeout=timeout)
369-
359+
return self.rxqueue.get(block=True, timeout=timeout)
370360
except queue.Empty:
371-
timedout = True
372-
373-
if timedout:
374361
raise TimeoutException("Did not received ISOTP frame in time (timeout=%s sec)" % timeout)
375362

376-
return frame
377-
378363
def empty_rxqueue(self) -> None:
379364
while not self.rxqueue.empty():
380365
self.rxqueue.get()
@@ -442,17 +427,12 @@ def specific_send(self, payload: bytes, timeout: Optional[float] = None) -> None
442427
self.touserqueue.put(payload, block=True, timeout=timeout)
443428

444429
def specific_wait_frame(self, timeout: Optional[float] = None) -> Optional[bytes]:
445-
if not self.opened:
446-
raise RuntimeError("Connection is not open")
430+
self.check_connection_opened()
447431

448-
timedout = False
449432
frame = None
450433
try:
451434
frame = self.fromuserqueue.get(block=True, timeout=timeout)
452435
except queue.Empty:
453-
timedout = True
454-
455-
if timedout:
456436
raise TimeoutException("Did not receive frame from user queue in time (timeout=%s sec)" % timeout)
457437

458438
if self.mtu is not None:
@@ -577,8 +557,7 @@ def specific_send(self, payload: bytes, timeout: Optional[float] = None) -> None
577557
self.isotp_layer.send(payload, send_timeout=timeout)
578558

579559
def specific_wait_frame(self, timeout: Optional[float] = None) -> Optional[bytes]:
580-
if not self.opened:
581-
raise RuntimeError("Connection is not opened")
560+
self.check_connection_opened()
582561

583562
frame = self.isotp_layer.recv(block=True, timeout=timeout)
584563
if frame is None:
@@ -649,25 +628,15 @@ def specific_send(self, payload: bytes, timeout: Optional[float] = None):
649628
self.toIsoTPQueue.put(bytearray(payload)) # isotp.protocol.TransportLayer uses byte array. udsoncan is strict on bytes format
650629

651630
def specific_wait_frame(self, timeout: Optional[float] = None) -> Optional[bytes]:
652-
if not self.opened:
653-
raise RuntimeError("Connection is not open")
631+
self.check_connection_opened()
654632

655-
timedout = False
656-
frame = None
657633
try:
658634
frame = self.fromIsoTPQueue.get(block=True, timeout=timeout)
635+
# isotp.protocol.TransportLayer uses bytearray. udsoncan is strict on bytes format
636+
return bytes(frame)
659637
except queue.Empty:
660-
timedout = True
661-
662-
if timedout:
663638
raise TimeoutException("Did not receive IsoTP frame from the Transport layer in time (timeout=%s sec)" % timeout)
664639

665-
if frame is None:
666-
return None
667-
668-
# isotp.protocol.TransportLayer uses bytearray. udsoncan is strict on bytes format
669-
return bytes(frame)
670-
671640
def empty_rxqueue(self) -> None:
672641
while not self.fromIsoTPQueue.empty():
673642
self.fromIsoTPQueue.get()
@@ -776,13 +745,26 @@ def __init__(self,
776745
self.result, self.channelID = self.interface.PassThruConnect(self.devID, self.protocol.value, self.baudrate)
777746
self.log_last_operation("PassThruConnect", with_raise=True)
778747

779-
configs = SCONFIG_LIST([
748+
configs = [
780749
(Ioctl_ID.DATA_RATE.value, self.baudrate),
781750
(Ioctl_ID.LOOPBACK.value, 0),
782-
(Ioctl_ID.ISO15765_BS.value, 0x20),
783-
(Ioctl_ID.ISO15765_STMIN.value, 0),
784-
])
785-
self.result = self.interface.PassThruIoctl(self.channelID, Ioctl_ID.SET_CONFIG, configs)
751+
]
752+
if self.protocol in [Protocol_ID.ISO9141, Protocol_ID.ISO14230]:
753+
configs += [
754+
(Ioctl_ID.P1_MAX.value, 40),
755+
(Ioctl_ID.P3_MIN.value, 110),
756+
(Ioctl_ID.P4_MIN.value, 10),
757+
(Ioctl_ID.TIDLE.value, 300),
758+
(Ioctl_ID.TWUP.value, 50),
759+
(Ioctl_ID.TINL.value, 25),
760+
]
761+
elif self.protocol in [Protocol_ID.ISO15765]:
762+
configs += [
763+
(Ioctl_ID.ISO15765_BS.value, 0x20),
764+
(Ioctl_ID.ISO15765_STMIN.value, 0),
765+
]
766+
767+
self.result = self.interface.PassThruIoctl(self.channelID, Ioctl_ID.SET_CONFIG, SCONFIG_LIST(configs))
786768
self.log_last_operation("PassThruIoctl SET_CONFIG")
787769

788770
self.result = self.interface.PassThruIoctl(self.channelID, Ioctl_ID.CLEAR_MSG_FILTERS)
@@ -804,7 +786,7 @@ def __init__(self,
804786

805787
def open(self) -> "J2534Connection":
806788
self.exit_requested = False
807-
self.sem = threading.Semaphore()
789+
self.interfaceSemaphore = threading.Semaphore()
808790
self.rxthread = threading.Thread(target=self.rxthread_task, daemon=True)
809791
self.rxthread.start()
810792
self.opened = True
@@ -822,15 +804,15 @@ def is_open(self) -> bool:
822804

823805
def rxthread_task(self) -> None:
824806
while not self.exit_requested:
825-
self.sem.acquire()
807+
self.interfaceSemaphore.acquire()
826808
try:
827-
result, data, numMessages = self.interface.PassThruReadMsgs(self.channelID, self.protocol.value, 1, 1)
809+
result, data, numMessages = self.interface.PassThruReadMsgs(self.channelID, self.protocol.value, pNumMsgs=1)
828810
if data is not None:
829811
self.rxqueue.put(data)
830812
except Exception:
831813
self.logger.critical("Exiting J2534 rx thread")
832814
self.exit_requested = True
833-
self.sem.release()
815+
self.interfaceSemaphore.release()
834816
time.sleep(0.001)
835817

836818
def log_last_operation(self, exec_method: str, with_raise = False) -> None:
@@ -860,27 +842,19 @@ def specific_send(self, payload: bytes, timeout: Optional[float] = None):
860842
timeout = 0 if timeout is None else timeout
861843

862844
# Fix for avoid ERR_CONCURRENT_API_CALL. Stop reading
863-
self.sem.acquire()
845+
self.interfaceSemaphore.acquire()
864846
self.result = self.interface.PassThruWriteMsgs(self.channelID, payload, self.protocol.value, Timeout=int(timeout * 1000))
865847
self.log_last_operation('PassThruWriteMsgs', with_raise=True)
866-
self.sem.release()
848+
self.interfaceSemaphore.release()
867849

868850
def specific_wait_frame(self, timeout: Optional[float] = None) -> Optional[bytes]:
869-
if not self.opened:
870-
raise RuntimeError("J2534 Connection is not open")
851+
self.check_connection_opened()
871852

872-
timedout = False
873-
frame = None
874853
try:
875-
frame = self.rxqueue.get(block=True, timeout=timeout)
854+
return self.rxqueue.get(block=True, timeout=timeout)
876855
except queue.Empty:
877-
timedout = True
878-
879-
if timedout:
880856
raise TimeoutException("Did not received response from J2534 RxQueue (timeout=%s sec)" % timeout)
881857

882-
return frame
883-
884858
def empty_rxqueue(self) -> None:
885859
while not self.rxqueue.empty():
886860
self.rxqueue.get()
@@ -942,21 +916,13 @@ def specific_send(self, payload: bytes, timeout: Optional[float] = None):
942916
self.rxqueue.put(self.ResponseData[payload])
943917

944918
def specific_wait_frame(self, timeout: Optional[float] = None) -> Optional[bytes]:
945-
if not self.opened:
946-
raise RuntimeError("Fake Connection is not open")
919+
self.check_connection_opened()
947920

948-
timedout = False
949-
frame = None
950921
try:
951-
frame = self.rxqueue.get(block=True, timeout=timeout)
922+
return self.rxqueue.get(block=True, timeout=timeout)
952923
except queue.Empty:
953-
timedout = True
954-
955-
if timedout:
956924
raise TimeoutException("Did not received response from J2534 RxQueue (timeout=%s sec)" % timeout)
957925

958-
return frame
959-
960926
def empty_rxqueue(self) -> None:
961927
while not self.rxqueue.empty():
962928
self.rxqueue.get()
@@ -1002,13 +968,14 @@ def __init__(self, rx_id: int, tx_id: int, name: Optional[str] = None, *args, **
1002968
self.opened = False
1003969

1004970
def specific_send(self, payload: bytes, timeout: Optional[float] = None) -> None:
1005-
if self.conn is None or not self.opened:
1006-
raise RuntimeError("Connection is not opened")
971+
self.check_connection_opened()
972+
assert self.conn is not None
973+
1007974
self.conn.send(payload)
1008975

1009976
def specific_wait_frame(self, timeout: Optional[float] = None) -> Optional[bytes]:
1010-
if not self.opened or self.conn is None:
1011-
raise RuntimeError("Connection is not open")
977+
self.check_connection_opened()
978+
assert self.conn is not None
1012979

1013980
frame = cast(Optional[bytes], self.conn.recv(timeout))
1014981

@@ -1034,7 +1001,7 @@ def empty_rxqueue(self) -> None:
10341001
self.conn.empty()
10351002

10361003
def is_open(self) -> bool:
1037-
return self.opened
1004+
return self.conn is not None and self.opened
10381005

10391006
def __enter__(self) -> "SyncAioIsotpConnection":
10401007
return self

0 commit comments

Comments
 (0)