6
6
import sys
7
7
from abc import ABC , abstractmethod
8
8
import time
9
- from typing import Union , Any , Dict
9
+ from typing import Union , Dict
10
10
import ctypes
11
11
import selectors
12
12
@@ -83,7 +83,7 @@ def wait_frame(self, timeout: Optional[float] = None, exception: bool = False) -
83
83
"""Waits for the reception of a frame of data from the underlying transport protocol
84
84
85
85
:param timeout: The maximum amount of time to wait before giving up in seconds
86
- :type timeout: int
86
+ :type timeout: float
87
87
:param exception: Boolean value indicating if this function may return exceptions.
88
88
When ``True``, all exceptions may be raised, including ``TimeoutException``
89
89
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
128
128
"""The implementation of the ``wait_frame`` method.
129
129
130
130
:param timeout: The maximum amount of time to wait before giving up
131
- :type timeout: int
131
+ :type timeout: float
132
132
133
133
:returns: Received data
134
134
:rtype: bytes or None
@@ -728,22 +728,28 @@ class J2534Connection(BaseConnection):
728
728
opened : bool
729
729
730
730
def __init__ (self , windll : str , rxid : int , txid : int , name : Optional [str ] = None , debug : bool = False , * args , ** kwargs ):
731
-
732
731
BaseConnection .__init__ (self , name )
733
732
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
-
737
733
# 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' )
739
738
740
739
# Set the protocol to ISO15765, Baud rate to 500000
741
740
self .protocol = Protocol_ID .ISO15765
742
741
self .baudrate = 500000
743
742
self .debug = debug
744
743
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 )
747
753
748
754
if debug :
749
755
self .result = self .interface .PassThruIoctl (0 ,
@@ -759,7 +765,7 @@ def __init__(self, windll: str, rxid: int, txid: int, name: Optional[str] = None
759
765
760
766
# get the channel ID of the interface (used for subsequent communication)
761
767
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 )
763
769
764
770
configs = SCONFIG_LIST ([
765
771
(Ioctl_ID .DATA_RATE .value , 500000 ),
@@ -805,7 +811,6 @@ def is_open(self) -> bool:
805
811
return self .opened
806
812
807
813
def rxthread_task (self ) -> None :
808
-
809
814
while not self .exit_requested :
810
815
try :
811
816
result , data , numMessages = self .interface .PassThruReadMsgs (self .channelID , self .protocol .value , 1 , 1 )
@@ -815,20 +820,28 @@ def rxthread_task(self) -> None:
815
820
self .logger .critical ("Exiting J2534 rx thread" )
816
821
self .exit_requested = True
817
822
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 :
820
824
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
822
831
823
832
elif self .debug :
824
833
self .logger .debug ("J2534 %s: OK" % (exec_method ))
825
834
826
835
def close (self ) -> None :
836
+ self .opened = False
827
837
self .exit_requested = True
828
838
self .rxthread .join ()
839
+
829
840
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' )
832
845
833
846
def specific_send (self , payload : bytes , timeout : Optional [float ] = None ):
834
847
if timeout is None :
@@ -855,6 +868,16 @@ def empty_rxqueue(self) -> None:
855
868
while not self .rxqueue .empty ():
856
869
self .rxqueue .get ()
857
870
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
+
858
881
859
882
class FakeConnection (BaseConnection ):
860
883
"""
0 commit comments