Open Power-6 opened 2 years ago
Do you have a PCAP? The DoIP layer is indifferent to the UDS interactions. The ECU responding with 0x7b is typical, it essentially just extends the UDS P2 timeout. udsoncan handles it properly. Normally the loop is 1) udsoncan sends something 2) doip packs it up and sends it 3) udsoncan asks doip client if there's anything back - there's not, so we send Timeout Error 4) udsoncan accepts this and keeps looping until either p2 timeout or something shows up 5) If it receives 7b it keeps extending the timer
The only time you should have issues with timeouts is if the ECU isn't responding with DoIP ack in a timely manner, or if your udsoncan client isn't properly configured.
I suppose it's possible the udsoncan client interface has changed in newer versions. Can you show which version you have installed as well?
I vaguely recall you might need to tweak use_server_timing, p2_timeout, and p2_star_timeout
Hi, thanks for getting back to me! I was able to do further testing and get past this. So as such this is not an issue, as it looks like the pending message and wait is being properly handled with udsoncan (1.15 latest version) and doipclient is working correctly there. The immediate cause of the issue was the car timing out the connection.
The root cause was a different issue, which would be more of an enhancement, to doipclient, I think, unless I am missing a limitation of the connection with udsoncan. I could open a new issue or if it's not feasible let me know your thoughts before you close this one and I won't bother if it's more of a udsoncan issue or I am missing how to properly use doipclient.
The issue stems from very modern cars with a gateway. In this case a 2019 Volvo with a "VCM" that acts as the DOIP gateway to the car via ethernet from the OBD port, for all diagnostics. As such a diag tool talks to multiple ECUs through the same TCP session, IP destination is always the same, but the logical address would change of course. The doipclient, only allows one "client" at a time since the logical address is defined on the DOIPClient connection. The effect is I need to close and open connections, to the gateway on connecting, then close and open new connection to broadcast address to ping "tester present" to all ECUs, then close that connection and open a new connection to program an ECU. The problem, it turns out, is i have to close the broadcast connection and stop the "tester present" ping in order to work on a specific ECU, and after a time with no "ping" all the ECUs, specifically the "VCM" gateway time out of their current mode, and drop the TCP connection. i was hoping that a programming session would keep things going but that timely "tester present", broadcast to all ECUs (logical address 0x1FFF on the Volvo) turned out to be critical.
Initially I tried opening a separate socket via TCP and send the raw packet. No dice the gateway responds negative and closes the session! So I needed to be in the same session as the doipclient. I did end up working around this, I figured out the handy "send_doip' feature and that I can control the logical addressing withing that. So I was able to incorporate timely "tester present" pings to the broadcast address in the same session where I am programming a specific ECU. That kept the gateway from timing out the session and the programming session was able to complete.
The downside of this way is that I can't leverage udsoncan for the communication, need to assemble the payload, and any response handling from scratch, as the doipclient is configured for only one logical address. For my current challenge it is not a big deal, as the broadcast "tester present" has suppress reply bit enabled, it's just a dumb ping. For the future, it could be more of a challenge, like cycling through ECUs reading DTC information. I will need to open and close a session for each ECU, there are 35 ECUs in the car. Again that may be worked around, but maybe not ideal.
Seems to me, ideally the TCP session is not tied to the ECU session (the logical address) as with a gateway, the paradigm of "one session, one ECU" is broken. New paradigm: the gateway is a router, open TCP session with it, and then communicate with any ECU behind it in that session via the logical address. I don't know what that looks like, if that's possible to integrate with udsoncan. Or if I am missing there is way to do that already...
Just skimming your response, I agree that in this day and age vendors have come up with some pretty crazy situations, usually because they only need to support their own custom tooling. The spec does describe how edge gateway routers should behave, but I think in practice most vendors have some trickery required that's not in the spec. Mercedes and Volvo are the only two I've seen that even expose it. Zero Emission vehicles aren't required to provide diagnostics, so there is often no edge gateway to talk to - just their custom API's. I assume most other vendors still just use CAN and friends on the OBD2 port instead of DoIP, leaving DoIP for internal use.
In the common use case, with UDS and DoIP you're only talking to one ECU at a time, mainly because historically the transports have been ISOTP or LINTP. As such, I think as you're finding the tooling udsoncan and my library set out to handle this use case - specifically I was originally interested in talking to ECU's directly over automotive Ethernet rather than through a gateway. The architectural issue is that udsoncan doesn't have the concept of "who" you want to talk to, and we need to be careful to avoid pulling the rug out from under it. The easiest way, as you discovered, is to simply enforce a one to one relationship.
I suspect it would be pretty easy for you to create a new custom DoIPClient that does what you want and is able to reuse a lot of the pieces. It just needs to be threaded like the ISOTP connector and pet the DoIP and UDS layer for various logical addresses periodically, rather than waiting for the udsoncan caller to do it. If you do come up with something we could merge it in as a Volvo specific implementation. For now, the design goal of this project was "short lived synchronous" and my intended solution to your problem would be multiple DoIPClients and close/reopen as needed
Thanks Jacob! You hit the nail on the head and it's helpful to me. I am in a relative bubble being new and only working on one specific use case. My assumption was this is the way DoIP is going but that's confined to a few mfrs as far as I know right now, I think BMW ENET is similar to Volvo and Benz but that's the limit of my knowledge. I understand the situation with automakers, moving slowly from historically highly proprietary diagnostics to more open standards based, yet still so much proprietary in the implementations.
I'd love to contribute to make a gateway firendly DoIP client, I am loving Python. I think I will finish my first project with DoIP so I get a good understanding of the what would be the ideal architecture for how this would work. I'm already hitting some other challenges, but able to work around them for now. Not sure I am qualified to figure out how to build a new client/module, not like that would stop me ;-) I may reach out though when I get to that if you don't mind!
Hi! I'm new at software development so go easy on me ;-) I am plenty technical though. I am using this client with udsoncan to implement flash programming and diag over Ethernet. I am hitting a problem that I think is contained in the way doipclient handles wait state frames. In this case when doing data transfer. ECU is unlocked, programming mode, 0x34 Request Download is sent and acknowledge so all is well. Then send 0x36 request to transfer data, ECU will always respond with a 0x3f error, "Code: Request correctly received, but response is pending (0x78)". I beleive udsoncan has been updated to handle this, i.e. keep waiting on pending message return (if timeout not expired). I am getting immediate timeout from doipclient though.
Relevant code:
The first transfer of the first block, the client.transfer_data times out almost immediately, via the doipclient.
errors in testing:
In trying to figure out where this goes wrong, I think it's in connectors.py, the specific_wait_frame, as that returns from the function? I could be wrong about that, but at any rate it appears as far as I can see, doipclient is handling the pending message as the result and returning it, not waiting for the result. I have tried playing with the timeout there and in the constants, A_PROCESSING_TIME, setting to 20 to check if there is an effect, but there is not, return is still immediate timeout on pending message. If I sniff the factory tool, the ECU issues the pending message within 0.3 sec, then 0.5 sec later sends the transfer confirmation, so that seems to be happening within the 2 sec timeout of doipclient.
I could be way off though, I'm a n00b but wanted to bring it up as it seems an issue with doipclient.