1 OBD-II Support Library in C
2 =============================
4 This is a platform agnostic C library that implements the standard On Board
5 Diagnostics system for vehicles. It currently supports OBD-II running over CAN
6 (ISO 15765-4), which uses the ISO-TP (ISO 15765-2) protocol underneath.
8 This library doesn't assume anything about the source of your diagnostic message
9 requests or underlying interface to the CAN bus. It uses dependency injection to
10 give you complete control.
14 TODO diagram out a request, response and error response
16 * store the request arb id, mode, pid, and payload locally
18 * get all new can messages passed to it
19 * Check the incoming can message to see if it matches one of the standard ECU
20 response IDs, or our arb ID + 0x8
21 * if it matches, parse the diagnostic response and call the callback
25 First, create some shim functions to let this library use your lower level
28 // required, this must send a single CAN message with the given arbitration
29 // ID (i.e. the CAN message ID) and data. The size will never be more than 8
31 void send_can(const uint16_t arbitration_id, const uint8_t* data,
36 // optional, provide to receive debugging log messages
37 void debug(const char* format, ...) {
42 // not used in the current version
43 void set_timer(uint16_t time_ms, void (*callback)) {
47 With your shims in place, create a `DiagnosticShims` object to pass them around:
49 DiagnosticShims shims = diagnostic_init_shims(debug, send_can, set_timer);
51 With your shims in hand, send a simple PID request to the stadnard broadcast
54 // Optional: This is your callback that will be called the response to your
55 // diagnostic request is received.
56 void response_received_handler(const DiagnosticResponse* response) {
57 // You received a response! Do something with it.
60 DiagnosticRequestHandle handle = diagnostic_request_pid(&shims,
61 DIAGNOSTIC_STANDARD_PID, // this is a standard PID request, not an extended or enhanced one
62 0x7df, // the request is going out to the broadcast arbitration ID
63 0x2, // we want PID 0x2
64 response_received_handler); // our callback (optional, use NULL if you don't have one)
66 if(handle.completed) {
68 // something happened and it already failed - possibly we aren't
69 // able to send CAN messages
72 // this should never occur right away - you need to receive a fresh
77 // Continue to read from CAN, passing off each message to the handle.
78 // This will return a 'completed' DiagnosticResponse when the when
79 // the request is completely sent and the response is received
80 // (which may take more than 1 CAN frames)
81 DiagnosticResponse response = diagnostic_receive_can_frame(&shims,
82 &handle, can_message_id, can_data, sizeof(can_data));
84 if(response.completed && handle.completed) {
86 if(response.success) {
87 // The request was sent successfully, the response was
88 // received successfully, and it was a positive response - we
89 // got back some data!
91 // The request was sent successfully, the response was
92 // received successfully, BUT it was a negative response
93 // from the other node.
94 printf("This is the error code: %d", response.negative_response_code);
97 // Some other fatal error ocurred - we weren't able to send
98 // the request or receive the response. The CAN connection
105 ## Requests for other modes
107 If you want to do more besides PID requests on mode 0x1 and 0x22, there's a
108 lower level API you can use. Here's how to make a mode 3 request to get DTCs.
110 DiagnosticRequest request = {
111 arbitration_id: 0x7df,
112 mode: OBD2_MODE_EMISSIONS_DTC_REQUEST
114 DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request, NULL);
116 if(handle.completed) {
117 if(!handle.success) {
118 // something happened and it already failed - possibly we aren't
119 // able to send CAN messages
122 // this should never occur right away - you need to receive a fresh
127 // Continue to read from CAN, passing off each message to the handle.
128 // This will return a 'completed' DiagnosticResponse when the when
129 // the request is completely sent and the response is received
130 // (which may take more than 1 CAN frames)
131 DiagnosticResponse response = diagnostic_receive_can_frame(&shims,
132 &handle, can_message_id, can_data, sizeof(can_data));
134 if(response.completed && handle.completed) {
136 if(response.success) {
137 // The request was sent successfully, the response was
138 // received successfully, and it was a positive response - we
139 // got back some data!
140 printf("The DTCs are: ");
141 for(int i = 0; i < response.payload_length; i++) {
142 printf("0x%x ", response.payload[i]);
145 // The request was sent successfully, the response was
146 // received successfully, BUT it was a negative response
147 // from the other node.
148 printf("This is the error code: %d", response.negative_response_code);
151 // Some other fatal error ocurred - we weren't able to send
152 // the request or receive the response. The CAN connection
161 The library includes a test suite that uses the `check` C unit test library.
165 You can also see the test coverage if you have `lcov` installed and the
166 `BROWSER` environment variable set to your choice of web browsers:
168 $ BROWSER=google-chrome-stable make coverage
172 you're going to request a few PIDs over and over again at some frequency
173 you're going to request DTCs once and read the response
174 you're going to clear DTCs once
176 we need another layer on top of that to handle the repeated requests.
180 Chris Peplin cpeplin@ford.com
184 Copyright (c) 2013 Ford Motor Company
186 Licensed under the BSD license.