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 First, create some shim functions to let this library use your lower level
17 // required, this must send a single CAN message with the given arbitration
18 // ID (i.e. the CAN message ID) and data. The size will never be more than 8
20 void send_can(const uint16_t arbitration_id, const uint8_t* data,
25 // optional, provide to receive debugging log messages
26 void debug(const char* format, ...) {
31 // not used in the current version
32 void set_timer(uint16_t time_ms, void (*callback)) {
36 With your shims in place, create a `DiagnosticShims` object to pass them around:
38 DiagnosticShims shims = diagnostic_init_shims(debug, send_can, set_timer);
40 With your shims in hand, send a simple PID request to the stadnard broadcast
43 // Optional: This is your callback that will be called the response to your
44 // diagnostic request is received.
45 void response_received_handler(const DiagnosticResponse* response) {
46 // You received a response! Do something with it.
49 DiagnosticRequestHandle handle = diagnostic_request_pid(&shims,
50 DIAGNOSTIC_STANDARD_PID, // this is a standard PID request, not an extended or enhanced one
51 0x7df, // the request is going out to the broadcast arbitration ID
52 0x2, // we want PID 0x2
53 response_received_handler); // our callback (optional, use NULL if you don't have one)
55 if(handle.completed) {
57 // something happened and it already failed - possibly we aren't
58 // able to send CAN messages
61 // this should never occur right away - you need to receive a fresh
66 // Continue to read from CAN, passing off each message to the handle.
67 // This will return a 'completed' DiagnosticResponse when the when
68 // the request is completely sent and the response is received
69 // (which may take more than 1 CAN frames)
70 DiagnosticResponse response = diagnostic_receive_can_frame(&shims,
71 &handle, can_message_id, can_data, sizeof(can_data));
73 if(response.completed && handle.completed) {
75 if(response.success) {
76 // The request was sent successfully, the response was
77 // received successfully, and it was a positive response - we
78 // got back some data!
80 // The request was sent successfully, the response was
81 // received successfully, BUT it was a negative response
82 // from the other node.
83 printf("This is the error code: %d", response.negative_response_code);
86 // Some other fatal error ocurred - we weren't able to send
87 // the request or receive the response. The CAN connection
94 ## Requests for other modes
96 If you want to do more besides PID requests on mode 0x1 and 0x22, there's a
97 lower level API you can use. Here's how to make a mode 3 request to get DTCs.
99 DiagnosticRequest request = {
100 arbitration_id: 0x7df,
101 mode: OBD2_MODE_EMISSIONS_DTC_REQUEST
103 DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request, NULL);
105 if(handle.completed) {
106 if(!handle.success) {
107 // something happened and it already failed - possibly we aren't
108 // able to send CAN messages
111 // this should never occur right away - you need to receive a fresh
116 // Continue to read from CAN, passing off each message to the handle.
117 // This will return a 'completed' DiagnosticResponse when the when
118 // the request is completely sent and the response is received
119 // (which may take more than 1 CAN frames)
120 DiagnosticResponse response = diagnostic_receive_can_frame(&shims,
121 &handle, can_message_id, can_data, sizeof(can_data));
123 if(response.completed && handle.completed) {
125 if(response.success) {
126 // The request was sent successfully, the response was
127 // received successfully, and it was a positive response - we
128 // got back some data!
129 printf("The DTCs are: ");
130 for(int i = 0; i < response.payload_length; i++) {
131 printf("0x%x ", response.payload[i]);
134 // The request was sent successfully, the response was
135 // received successfully, BUT it was a negative response
136 // from the other node.
137 printf("This is the error code: %d", response.negative_response_code);
140 // Some other fatal error ocurred - we weren't able to send
141 // the request or receive the response. The CAN connection
150 The library includes a test suite that uses the `check` C unit test library.
154 You can also see the test coverage if you have `lcov` installed and the
155 `BROWSER` environment variable set to your choice of web browsers:
157 $ BROWSER=google-chrome-stable make coverage
161 TODO diagram out a request, response and error response
163 * store the request arb id, mode, pid, and payload locally
165 * get all new can messages passed to it
166 * Check the incoming can message to see if it matches one of the standard ECU
167 response IDs, or our arb ID + 0x8
168 * if it matches, parse the diagnostic response and call the callback
173 you're going to request a few PIDs over and over again at some frequency
174 you're going to request DTCs once and read the response
175 you're going to clear DTCs once
177 we need another layer on top of that to handle the repeated requests.
181 Chris Peplin cpeplin@ford.com
185 Copyright (c) 2013 Ford Motor Company
187 Licensed under the BSD license.