Skip to content

Commit a4b66db

Browse files
authored
Improvement with processing J2534 Connection (#248)
1 parent 05e7d52 commit a4b66db

File tree

2 files changed

+55
-31
lines changed

2 files changed

+55
-31
lines changed

udsoncan/connections.py

+40-17
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import sys
77
from abc import ABC, abstractmethod
88
import time
9-
from typing import Union, Any, Dict
9+
from typing import Union, Dict
1010
import ctypes
1111
import selectors
1212

@@ -83,7 +83,7 @@ def wait_frame(self, timeout: Optional[float] = None, exception: bool = False) -
8383
"""Waits for the reception of a frame of data from the underlying transport protocol
8484
8585
:param timeout: The maximum amount of time to wait before giving up in seconds
86-
:type timeout: int
86+
:type timeout: float
8787
:param exception: Boolean value indicating if this function may return exceptions.
8888
When ``True``, all exceptions may be raised, including ``TimeoutException``
8989
When ``False``, all exceptions will be logged as ``DEBUG`` and ``None`` will be returned.
@@ -128,7 +128,7 @@ def specific_wait_frame(self, timeout: Optional[float] = None) -> Optional[bytes
128128
"""The implementation of the ``wait_frame`` method.
129129
130130
:param timeout: The maximum amount of time to wait before giving up
131-
:type timeout: int
131+
:type timeout: float
132132
133133
:returns: Received data
134134
:rtype: bytes or None
@@ -728,22 +728,28 @@ class J2534Connection(BaseConnection):
728728
opened: bool
729729

730730
def __init__(self, windll: str, rxid: int, txid: int, name: Optional[str] = None, debug: bool = False, *args, **kwargs):
731-
732731
BaseConnection.__init__(self, name)
733732

734-
# Determine mode ID29 or ID11
735-
txFlags = TxStatusFlag.ISO15765_CAN_ID_29.value if txid >> 11 else TxStatusFlag.ISO15765_CAN_ID_11.value
736-
737733
# Set up a J2534 interface using the DLL provided
738-
self.interface = J2534(windll=windll, rxid=rxid, txid=txid, txFlags=txFlags)
734+
try:
735+
self.interface = J2534(windll=windll, rxid=rxid, txid=txid)
736+
except FileNotFoundError:
737+
raise RuntimeError('DLL not found')
739738

740739
# Set the protocol to ISO15765, Baud rate to 500000
741740
self.protocol = Protocol_ID.ISO15765
742741
self.baudrate = 500000
743742
self.debug = debug
744743

745-
# Open the interface (connect to the DLL)
746-
result, self.devID = self.interface.PassThruOpen()
744+
try:
745+
# Open the interface (connect to the DLL)
746+
self.result, self.devID = self.interface.PassThruOpen()
747+
except OSError as e:
748+
if e.errno in [0x16, 0xe06d7363]:
749+
raise RuntimeError('J2534 Device busy')
750+
raise RuntimeError('%s, %X' % (type(e).__name__, e.errno))
751+
752+
self.log_last_operation("PassThruOpen", with_raise=True)
747753

748754
if debug:
749755
self.result = self.interface.PassThruIoctl(0,
@@ -759,7 +765,7 @@ def __init__(self, windll: str, rxid: int, txid: int, name: Optional[str] = None
759765

760766
# get the channel ID of the interface (used for subsequent communication)
761767
self.result, self.channelID = self.interface.PassThruConnect(self.devID, self.protocol.value, self.baudrate)
762-
self.log_last_operation("PassThruConnect")
768+
self.log_last_operation("PassThruConnect", with_raise=True)
763769

764770
configs = SCONFIG_LIST([
765771
(Ioctl_ID.DATA_RATE.value, 500000),
@@ -805,7 +811,6 @@ def is_open(self) -> bool:
805811
return self.opened
806812

807813
def rxthread_task(self) -> None:
808-
809814
while not self.exit_requested:
810815
try:
811816
result, data, numMessages = self.interface.PassThruReadMsgs(self.channelID, self.protocol.value, 1, 1)
@@ -815,20 +820,28 @@ def rxthread_task(self) -> None:
815820
self.logger.critical("Exiting J2534 rx thread")
816821
self.exit_requested = True
817822

818-
def log_last_operation(self, exec_method: str) -> None:
819-
res, pErrDescr = self.interface.PassThruGetLastError()
823+
def log_last_operation(self, exec_method: str, with_raise = False) -> None:
820824
if self.result != Error_ID.ERR_SUCCESS:
821-
self.logger.error("J2534 %s: %s %s" % (exec_method, self.result, pErrDescr))
825+
res, pErrDescr = self.interface.PassThruGetLastError()
826+
err = "J2534 %s: %s (%s)" % (exec_method, pErrDescr, self.result)
827+
self.logger.error(err)
828+
if with_raise:
829+
raise RuntimeError(err)
830+
return
822831

823832
elif self.debug:
824833
self.logger.debug("J2534 %s: OK" % (exec_method))
825834

826835
def close(self) -> None:
836+
self.opened = False
827837
self.exit_requested = True
828838
self.rxthread.join()
839+
829840
self.result = self.interface.PassThruDisconnect(self.channelID)
830-
self.opened = False
831-
self.log_last_operation("Connection closed")
841+
self.log_last_operation('PassThruDisconnect')
842+
843+
self.interface.PassThruClose(self.devID)
844+
self.log_last_operation('PassThruClose')
832845

833846
def specific_send(self, payload: bytes, timeout: Optional[float] = None):
834847
if timeout is None:
@@ -855,6 +868,16 @@ def empty_rxqueue(self) -> None:
855868
while not self.rxqueue.empty():
856869
self.rxqueue.get()
857870

871+
def read_vbatt(self, digits=1) -> float:
872+
vbatt = ctypes.POINTER(ctypes.c_int32)()
873+
874+
self.result = self.interface.PassThruIoctl(self.channelID, Ioctl_ID.READ_VBATT, None, vbatt)
875+
self.log_last_operation("PassThruIoctl READ_VBATT")
876+
877+
value = ctypes.cast(vbatt, ctypes.c_void_p).value
878+
879+
return round(value / 1000, digits) if value else 0
880+
858881

859882
class FakeConnection(BaseConnection):
860883
"""

udsoncan/j2534.py

+15-14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class PASSTHRU_MSG(Structure):
1212
("TxFlags", c_ulong),
1313
("Timestamp", c_ulong),
1414
("DataSize", c_ulong),
15-
("ExtraDataindex", c_ulong),
15+
("ExtraDataIndex", c_ulong),
1616
("Data", ctypes.c_ubyte * 4128)]
1717

1818

@@ -44,7 +44,7 @@ class J2534():
4444
dllPassThruStartMsgFilter = None
4545
dllPassThruIoctl = None
4646

47-
def __init__(self, windll, rxid, txid, txFlags=0):
47+
def __init__(self, windll, rxid, txid):
4848
global dllPassThruOpen
4949
global dllPassThruClose
5050
global dllPassThruConnect
@@ -61,7 +61,9 @@ def __init__(self, windll, rxid, txid, txFlags=0):
6161
self.hDLL = ctypes.cdll.LoadLibrary(windll)
6262
self.rxid = rxid.to_bytes(4, 'big')
6363
self.txid = txid.to_bytes(4, 'big')
64-
self.txFlags = txFlags
64+
# Determine mode ID29 or ID11
65+
self.txConnectFlags = TxStatusFlag.ISO15765_CAN_ID_29.value if txid >> 11 else TxStatusFlag.ISO15765_CAN_ID_11.value
66+
self.txFlags = self.txConnectFlags | TxStatusFlag.ISO15765_FRAME_PAD.value
6567

6668
self.logger = logging.getLogger()
6769

@@ -190,7 +192,7 @@ def PassThruConnect(self, deviceID, protocol, baudrate, pChannelID=None):
190192
if not pChannelID:
191193
pChannelID = c_ulong()
192194

193-
result = dllPassThruConnect(deviceID, protocol, self.txFlags, baudrate, byref(pChannelID))
195+
result = dllPassThruConnect(deviceID, protocol, self.txConnectFlags, baudrate, byref(pChannelID))
194196
return Error_ID(hex(result)), pChannelID
195197

196198
def PassThruClose(self, DeviceID):
@@ -259,18 +261,13 @@ def PassThruGetLastError(self):
259261
pErrorDescription = (ctypes.c_char * 80)()
260262
result = dllPassThruGetLastError(pErrorDescription)
261263

262-
return Error_ID(hex(result)), str(pErrorDescription.value)
264+
return Error_ID(hex(result)), pErrorDescription.value.decode()
263265

264266
def PassThruIoctl(self, Handle, IoctlID, ioctlInput=None, ioctlOutput=None):
265-
if ioctlInput is None:
266-
pInput = POINTER(c_ulong)()
267-
else:
268-
pInput = ioctlInput
267+
pInput = None if ioctlInput is None else byref(ioctlInput)
268+
pOutput = None if ioctlOutput is None else byref(ioctlOutput)
269269

270-
if ioctlOutput is None:
271-
pOutput = POINTER(c_ulong)()
272-
273-
result = dllPassThruIoctl(Handle, c_ulong(IoctlID.value), byref(pInput), byref(pOutput))
270+
result = dllPassThruIoctl(Handle, c_ulong(IoctlID.value), pInput, pOutput)
274271

275272
return Error_ID(hex(result))
276273

@@ -279,20 +276,23 @@ def PassThruStartMsgFilter(self, ChannelID, protocol):
279276
msgMask.ProtocolID = protocol
280277
msgMask.TxFlags = self.txFlags
281278
msgMask.DataSize = 4
279+
msgMask.RxStatus = msgMask.ExtraDataIndex = 0xCCCC_CCCC
282280
for i in range(0, 4):
283281
msgMask.Data[i] = 0xFF
284282

285283
msgPattern = PASSTHRU_MSG()
286284
msgPattern.ProtocolID = protocol
287285
msgPattern.TxFlags = self.txFlags
288286
msgPattern.DataSize = 4
287+
msgPattern.RxStatus = msgPattern.ExtraDataIndex = 0xCCCC_CCCC
289288
for i in range(0, len(self.rxid)):
290289
msgPattern.Data[i] = self.rxid[i]
291290

292291
msgFlow = PASSTHRU_MSG()
293292
msgFlow.ProtocolID = protocol;
294293
msgFlow.TxFlags = self.txFlags
295294
msgFlow.DataSize = 4
295+
msgFlow.RxStatus = msgFlow.ExtraDataIndex = 0xCCCC_CCCC
296296
for i in range(0, len(self.txid)):
297297
msgFlow.Data[i] = self.txid[i]
298298

@@ -355,7 +355,8 @@ class Filter(Enum):
355355

356356

357357
class TxStatusFlag(Enum):
358-
ISO15765_CAN_ID_29 = 0x00000140
358+
ISO15765_CAN_ID_BOTH = 0x00000800
359+
ISO15765_CAN_ID_29 = 0x00000100
359360
ISO15765_CAN_ID_11 = 0x00000040
360361
ISO15765_FRAME_PAD = 0x00000040
361362
WAIT_P3_MIN_ONLY = 0x00000200

0 commit comments

Comments
 (0)