-
-
Notifications
You must be signed in to change notification settings - Fork 30
Description
Background
According to Wikipedia (sorry I don't have access to the actual OBD-II specification):
The PID query and response occurs on the vehicle's CAN bus. Standard OBD requests and responses use functional addresses. The diagnostic reader initiates a query using CAN ID 7DFh, which acts as a broadcast address, and accepts responses from any ID in the range 7E8h to 7EFh. ECUs that can respond to OBD queries listen both to the functional broadcast ID of 7DFh and one assigned ID in the range 7E0h to 7E7h. Their response has an ID of their assigned ID plus 8 e.g. 7E8h through 7EFh.
This approach allows up to eight ECUs, each independently responding to OBD queries. The diagnostic reader can use the ID in the ECU response frame to continue communication with a specific ECU. In particular, multi-frame communication requires a response to the specific ECU ID rather than to ID 7DFh.
This library's current code has you specify a sid/did (tx_id, rx_id) for OBD messages, and uses a single socket (socketCAN ISO-TP kernel interface) to handle sending/receiving messages on just those addresses. However, this causes problems when running against vehicles that follow the spec.
Observed Behavior
On a 2020 Toyota Camry, I tested Service_09::get_vin(), but it causes a timeout error. The reason is that if I set the tx_id to 0x7df, I get the first frame back from the ECU (with CAN ID 0x7e8), but the ECU pauses and waits for a FlowControl frame to be sent with CAN ID 0x7e0 (8 less than the ECU's transmit ID). The ISO-TP kernel sends flow control using the original broadcast address, 0x7df, which the ECU ignores. If I set the tx_id to 0x7e0 and request the VIN, the ECU completely ignores the request.
Other Implementations
I have a scan tool that sends the OBD messages properly, and I looked at the example code for Comma.ai's Panda, and they also send the request to 0x7df and listen on 0x7e8 (which sends the FC frame using ID 0x7e0). Their handling of UDS protocol does similar filtering to ensure the tx addr is changed from 0x7df to something in the range 0x7e0-0x7e7 (based on the first response received).
Proposed Design
The OBD code should have a single transmit socket with tx_id = 0x7df, and eight listening sockets with rx_id in the range 0x7e8 - 0x7ef (and tx_id for FC frames set to a value that is 8 less than the rx_id). This would follow the specification, allowing 8 ECUs to respond to OBD queries simultaneously. If it is a simple request, like to get the VIN, then that function can just take the first response and return it. In order for this to be possible, you will first have to implement the suggestion in Issue #11 to have a software-based ISO-TP channel. The socketcan-isotp crate definitely supports this, as demonstrated in their examples.