pylessard / python-udsoncan

Python implementation of UDS (ISO-14229) standard.
MIT License
564 stars 195 forks source link

No data received: [TimeoutException] Problem #212

Closed ichbinbork closed 5 months ago

ichbinbork commented 5 months ago

Hi,

I'm trying to use multiple UDS services with real ECU. Then I'm sending UDS services like this

def flash_update(conn,our_software):       
    with Client(conn,request_timeout=100,config=config) as client:
        try:
            '''client.change_session(2)'''    
            '''client.change_session(2)
            sleep(5)'''
            client.tester_present()
            client.routine_control(0xFF01,1)   ## Start Routine ## 0x0201 Routine id 1 Start Routine
            client.routine_control(0XFF01,2)   ## Stop Routine
            client.routine_control(0XFF01,3)   ## Request Routine Results       #### End of line Configuration
                                                                                                                                ### routine_id (int) – The routine ID. Value should be between 0 and 0xFFFF
                                                                                                                                ### control_type (int) – Service subfunction. Allowed values are from 0 to 0x7F
                                                                                                                                #data (bytes) – Optional additional data to provide to the server
            memloc1 = MemoryLocation(address=0x00011410, memorysize=0x0016EBF0, address_format=32)
            client.request_download(memloc1)

            client.transfer_data(0x3B,our_software)
            client.request_transfer_exit()
            client.routine_control(0xFF02,1)
            client.routine_control(0xFF02,2)
            client.routine_control(0xFF02,3)
            client.ecu_reset(1)
            #client.authentication(0)
        except Exception as e:
            print(e)
            print("xxxxxxxxxxxxxxxxxxxx")
            uds_exception_signal.stop_uds()

Also I'm getting response for tester present like shown in the CAN log

image

But programs get exception due to no data received.

Here is the DEBUG log:

2024-02-15 13:32:19 [INFO] UdsClient: TesterPresent<0x3e> - Sending TesterPresent request
2024-02-15 13:32:19 [DEBUG] Connection: Sending 2 bytes : [3e00]
2024-02-15 13:32:29 [DEBUG] Connection: No data received: [TimeoutException] - Did not receive IsoTP frame from the Transport layer in time (timeout=10 sec)
2024-02-15 13:32:29 [ERROR] UdsClient: [TimeoutException] : Did not receive response in time. P2 timeout time has expired (timeout=10.000 sec)
Did not receive response in time. P2 timeout time has expired (timeout=10.000 sec)
xxxxxxxxxxxxxxxxxxxx
2024-02-15 13:32:29 [INFO] Connection: Connection closed
2024-02-15 13:32:29 [INFO] Connection: Connection closed
2024-02-15 13:32:29 [INFO] Connection: Connection opened
2024-02-15 13:32:29 [INFO] UdsClient: TesterPresent<0x3e> - Sending TesterPresent request
2024-02-15 13:32:29 [DEBUG] Connection: Sending 2 bytes : [3e00]
2024-02-15 13:32:40 [DEBUG] Connection: No data received: [TimeoutException] - Did not receive IsoTP frame from the Transport layer in time (timeout=10 sec)
2024-02-15 13:32:40 [ERROR] UdsClient: [TimeoutException] : Did not receive response in time. P2 timeout time has expired (timeout=10.000 sec)
Did not receive response in time. P2 timeout time has expired (timeout=10.000 sec)

Should I send services one by one each threat?

Here is my library version : (1.22.1) for udsoncan (2.0.4) for iso-tp

pylessard commented 5 months ago

Can you share how you configured the communication stack? Parameters, connection, link layer.

Thanks

ichbinbork commented 5 months ago

Ofc Here is

def start_can(self): # DTC :5      ### 0x0407
        try:
            self.con_label.resize(25,12)
            self.con_label.setPixmap(self.con_on)
            self.con_stat.setText("ONLINE")
            bitrate = {"250kb/s" :"250000",
                       "500kb/s": "500000"}
            bitt = bitrate[str(self.comboBox_3.currentText())]

            self.bus = can.interface.Bus(bustype=self.comboBox.currentText(), channel=self.comboBox_2.currentText(),bitrate=int(bitt))
            self.tp_addr = isotp.Address(isotp.AddressingMode.Normal_29bits,txid=0x1234,rxid=0x123124)
            self.stack = isotp.CanStack(bus=self.bus,address=self.tp_addr,params=isotp_params.isotp_params)
            self.stack.set_sleep_timing(0,0)
            self.conn = PythonIsoTpConnection(self.stack)

I created stack dynamically according to user input in interface lets say this is a main.py. Then I created another python module for creating object and calling services here is the other module that I created

def flash_update(conn,our_software):       
    with Client(conn,request_timeout=None,config=config) as client:
        try:
            client.change_session(2)
            client.change_session(2)
            sleep(5)
            client.tester_present()
            client.routine_control(0xFF01,1)   ## Start Routine ## 0x0201 Routine id 1 Start Routine
            client.routine_control(0XFF01,2)   ## Stop Routine
            client.routine_control(0XFF01,3)   ## Request Routine Results       #### End of line Configuration
                                                                                                                                ### routine_id (int) – The routine ID. Value should be between 0 and 0xFFFF
                                                                                                                                ### control_type (int) – Service subfunction. Allowed values are from 0 to 0x7F
                                                                                                                                #data (bytes) – Optional additional data to provide to the server
            memloc1 = MemoryLocation(address=0x00011410, memorysize=0x0016EBF0, address_format=32)
            client.request_download(memloc1)

            client.transfer_data(0x3B,our_software)
            client.request_transfer_exit()
            client.routine_control(0xFF02,1)
            client.routine_control(0xFF02,2)
            client.routine_control(0xFF02,3)
            client.ecu_reset(1)
            #client.authentication(0)
        except Exception as e:
            print(e)
            print("xxxxxxxxxxxxxxxxxxxx")
            uds_exception_signal.stop_uds()

If you think this is the cause of the problem creating separate modules I don't think like that. Because I tested on the basic services that you created in the documents and got the same result, I used these services couple weeks ago and I successfully send&recieve uds messages. I suspect about your last update but as I said not sure. Interesting.

I forgot to add my istotp params:

isotp_params = {
 'stmin': 32,                            # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9
 'blocksize': 8,                         # Request the sender to send 8 consecutives frames before sending a new flow control message
 'wftmax': 0,                            # Number of wait frame allowed before triggering an error
 'tx_data_length': 8,                    # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
 # Minimum length of CAN messages. When different from None, messages are padded to meet this length. Works with CAN 2.0 and CAN FD.
 'tx_data_min_length': None,
 'tx_padding': 0,                        # Will pad all transmitted CAN messages with byte 0x00.
 'rx_flowcontrol_timeout': 1000,         # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds
 'rx_consecutive_frame_timeout': 1000,   # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds   # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
 'max_frame_size': 4095,                 # Limit the size of receive frame.
 'can_fd': False,                        # Does not set the can_fd flag on the output CAN messages
 'bitrate_switch': False,                # Does not set the bitrate_switch flag on the output CAN messages
 'rate_limit_enable': False,             # Disable the rate limiter
 'rate_limit_max_bitrate': 1000000,      # Ignored when rate_limit_enable=False. Sets the max bitrate when rate_limit_enable=True
 'rate_limit_window_size': 0.2,          # Ignored when rate_limit_enable=False. Sets the averaging window size for bitrate calculation when rate_limit_enable=True
 'listen_mode': False,                   # Does not use the listen_mode which prevent transmission.
}
pylessard commented 5 months ago

I'd like to see how you create the stack. Can bus, isotp layer, connection, client, etc

ichbinbork commented 5 months ago

Okay first of all I have already response your question in my previous answer. I don't get where you missed.

self.bus = can.interface.Bus(bustype=self.comboBox.currentText(), channel=self.comboBox_2.currentText(),bitrate=int(bitt))
            self.tp_addr = isotp.Address(isotp.AddressingMode.Normal_29bits,txid=0x1234,rxid=0x123124)
            self.stack = isotp.CanStack(bus=self.bus,address=self.tp_addr,params=isotp_params.isotp_params)
            self.stack.set_sleep_timing(0,0)
            self.conn = PythonIsoTpConnection(self.stack)

In this snippet I dynamically getting controller(vector or pcan), baudrate, channel. If you need yo understand whats going on the creating bus line bus = VectorBus(channel=0, bitrate=500000) this will help you .Also I have uploaded the isotp_params file.

Lastly I'm creating the client with this line with Client(conn,request_timeout=None,config=config) as client:

But be warned, the python module that I created the client object is different from the python modules that I created the can stack, isotp stack and conn.

pylessard commented 5 months ago

Yeah, I did miss it. I'm on holidays helping out on my phone. Do you read the can bus somewhere else? With isotp v2.x you can use a Listener/Notifier pattern that duplicates the message for each reader.

I see that the addresses you used are 0x1234 and 0x123123. Does not match the can log.

Will check more in details tonight

pylessard commented 5 months ago

Are you running multiple clients in different threads? If so, you absolutely need to use the new NotifierBasedCanStack. See the examples.

Is still don't understand why the addresses don't match though

ichbinbork commented 5 months ago

Can you link doc for that "Listener/Notifier". About addresses it's not a big deal I don't want to share real CAN IDs in github. As for your second comment. No, I have just one thread responsible for whole UDS communication and I'm creating more than one client in the same module but in different function. But I didn't call them in my main application. Here is a snippet about my uds functions python module.

def flash_update(conn,our_software):       
    with Client(conn,request_timeout=None,config=config) as client:
        try:
            '''client.change_session(2)
            client.change_session(2)
            sleep(5)'''
            client.tester_present()
            client.routine_control(0xFF01,1)   ## Start Routine ## 0x0201 Routine id 1 Start Routine
            client.routine_control(0XFF01,2)   ## Stop Routine
            client.routine_control(0XFF01,3)   ## Request Routine Results       #### End of line Configuration
                                                                                                                                ### routine_id (int) – The routine ID. Value should be between 0 and 0xFFFF
                                                                                                                                ### control_type (int) – Service subfunction. Allowed values are from 0 to 0x7F
                                                                                                                                #data (bytes) – Optional additional data to provide to the server
            memloc1 = MemoryLocation(address=0x00011410, memorysize=0x0016EBF0, address_format=32)
            client.request_download(memloc1)

            client.transfer_data(0x3B,our_software)
            client.request_transfer_exit()
            client.routine_control(0xFF02,1)
            client.routine_control(0xFF02,2)
            client.routine_control(0xFF02,3)
            client.ecu_reset(1)
            #client.authentication(0)
        except Exception as e:
            print(e)
            print("xxxxxxxxxxxxxxxxxxxx")
            uds_exception_signal.stop_uds()

            #client.close()

def changing_can_lines(conn):
    with Client(conn) as client:
        try:
            client.change_session(3)
            client.communication_control(0, 0x01)  # Enable Rx and Tx
            client.communication_control(1, 0x02)  # Enable Rx and Disable Tx
            client.communication_control(2, 0x03)  # Disable Rx and Enable Tx
            client.communication_control(3, 0x04)  # Disable Rx and Tx

I mean this situation little bit awkward cuz as I said couple days ago I successfully run the multiple services. So the problem might be happen due to last update on isotp and udsoncan. Its just a claim.

Cheers

pylessard commented 5 months ago

Pretty sure you run into a common issue if having 2 threads fighting to read the python-can queue. This issue existed prior to v2.x and have a bit of randomness into it because it is a race condition. Even if you have a single thread, there are threads created in the connection.

Listener/notifier is the solution https://udsoncan.readthedocs.io/en/latest/udsoncan/examples.html#using-uds-over-python-can

ichbinbork commented 5 months ago

Thanks for your answer. I applied your suggestions. At first, it was solved but later I got the same problems. I mean I don't say "it's not working" It worked a couple of times but its not stable. So I'm still not sure it's gonna a problem someday. Is there anything to do additional to fix that issue on my side? (Like managing threads on my side little bit regular.)

Interesting part of it it catches positive response of Tester present but can't catch the nrc of RoutineContro

2024-02-16 14:47:34 [INFO] Connection: Connection opened
2024-02-16 14:47:34 [INFO] UdsClient: TesterPresent<0x3e> - Sending TesterPresent request
2024-02-16 14:47:34 [DEBUG] Connection: Sending 2 bytes : [3e00]
2024-02-16 14:47:34 [DEBUG] Connection: Received 2 bytes : [7e00]
2024-02-16 14:47:34 [INFO] UdsClient: Received positive response for service TesterPresent (0x3e) from server.
2024-02-16 14:47:34 [INFO] UdsClient: RoutineControl<0x31> - ControlType=0x01 - Starting routine ID 0xff00 (EraseMemory) with a payload of 0 bytes
2024-02-16 14:47:34 [DEBUG] Connection: Sending 4 bytes : [3101ff00]
2024-02-16 14:47:35 [DEBUG] Connection: No data received: [TimeoutException] - Did not receive IsoTP frame from the Transport layer in time (timeout=1 sec) 
2024-02-16 14:47:35 [ERROR] UdsClient: [TimeoutException] : Did not receive response in time. P2 timeout time has expired (timeout=1.000 sec)
2024-02-16 14:47:35 [INFO] Connection: Connection closed
2024-02-16 14:50:08 [INFO] Connection: Connection opened
2024-02-16 14:50:08 [INFO] UdsClient: TesterPresent<0x3e> - Sending TesterPresent request
2024-02-16 14:50:08 [DEBUG] Connection: Sending 2 bytes : [3e00]
2024-02-16 14:50:08 [DEBUG] Connection: Received 2 bytes : [7e00]
2024-02-16 14:50:08 [INFO] UdsClient: Received positive response for service TesterPresent (0x3e) from server.
2024-02-16 14:50:08 [INFO] UdsClient: RoutineControl<0x31> - ControlType=0x01 - Starting routine ID 0xff00 (EraseMemory) with a payload of 0 bytes
2024-02-16 14:50:08 [DEBUG] Connection: Sending 4 bytes : [3101ff00]
2024-02-16 14:50:09 [DEBUG] Connection: No data received: [TimeoutException] - Did not receive IsoTP frame from the Transport layer in time (timeout=1 sec) 
2024-02-16 14:50:09 [ERROR] UdsClient: [TimeoutException] : Did not receive response in time. P2 timeout time has expired (timeout=1.000 sec)
2024-02-16 14:50:09 [INFO] Connection: Connection closed

Here is the can log of above debug log.

image
pylessard commented 5 months ago

Are you able to enable debug logging for the isotp layer? The logger name should be "isotp".

I trust that you have double checked the CAN IDs, because they could be a cause here

ichbinbork commented 5 months ago

No worries about CAN IDs. I think I found the problem and it's not relative with your code. In a function in my application I'm reading arbitration IDs and making some calculations with them in short, this is the thread that fighter with your thread in the library. Then I commented the functionality tested it again then it worked. Now I'm handling the threads for example when I worked with uds I closed the whole interaction with CAN Bus. I think this is the best solution for it. For now I will close the issue.

Thank you!

Last thing could you show me how to debug logging with isotp. Should I edit the logging.conf ?

Best regards

pylessard commented 5 months ago

To avoid threads fightings, read your bus by adding a Listener to the already existing notifier

The can.BufferedReader is the listener that you want

Cheers