Preserve compatibility with C89 mode.
[apps/low-level-can-service.git] / README.mkd
1 OBD-II Support Library in C
2 =============================
3
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.
7
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.
11
12 ## Usage
13
14 First, create some shim functions to let this library use your lower level
15 system:
16
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
19     // bytes.
20     bool send_can(const uint16_t arbitration_id, const uint8_t* data,
21             const uint8_t size) {
22         ...
23     }
24
25     // optional, provide to receive debugging log messages
26     void debug(const char* format, ...) {
27         ...
28     }
29
30
31     // not used in the current version
32     void set_timer(uint16_t time_ms, void (*callback)) {
33         ...
34     }
35
36 With your shims in place, create a `DiagnosticShims` object to pass them around:
37
38     DiagnosticShims shims = diagnostic_init_shims(debug, send_can, set_timer);
39
40 With your shims in hand, send a simple PID request to the standard broadcast
41 address, `0x7df` (we use the constant `OBD2_FUNCTIONAL_BROADCAST_ID` here):
42
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.
47     }
48
49     DiagnosticRequestHandle handle = diagnostic_request_pid(&shims,
50             DIAGNOSTIC_STANDARD_PID, // this is a standard PID request, not an extended or enhanced one
51             OBD2_FUNCTIONAL_BROADCAST_ID, // 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)
54
55     if(handle.completed) {
56         if(!handle.success) {
57             // something happened and it already failed - possibly we aren't
58             // able to send CAN messages
59             return;
60         } else {
61             // this should never occur right away - you need to receive a fresh
62             // CAN message first
63         }
64     } else {
65         while(true) {
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));
72
73             if(response.completed && handle.completed) {
74                 if(handle.success) {
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!
79                   } else {
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);
84                   }
85                 } else {
86                     // Some other fatal error ocurred - we weren't able to send
87                     // the request or receive the response. The CAN connection
88                     // may be down.
89                 }
90             }
91         }
92     }
93
94 ### Requests for other modes
95
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.
98
99     DiagnosticRequest request = {
100         arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
101         mode: OBD2_MODE_EMISSIONS_DTC_REQUEST
102     };
103     DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request, NULL);
104
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
109             return;
110         } else {
111             // this should never occur right away - you need to receive a fresh
112             // CAN message first
113         }
114     } else {
115         while(true) {
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));
122
123             if(response.completed && handle.completed) {
124                 if(handle.success) {
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]);
132                       }
133                   } else {
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);
138                   }
139                 } else {
140                     // Some other fatal error ocurred - we weren't able to send
141                     // the request or receive the response. The CAN connection
142                     // may be down.
143                 }
144             }
145         }
146     }
147
148 ## Dependencies
149
150 This library requires 2 dependencies:
151
152 * [isotp-c](https://github.com/openxc/isotp-c)
153 * [bitfield-c](https://github.com/openxc/bitfield-c)
154
155 ## Testing
156
157 The library includes a test suite that uses the `check` C unit test library.
158
159     $ make test
160
161 You can also see the test coverage if you have `lcov` installed and the
162 `BROWSER` environment variable set to your choice of web browsers:
163
164     $ BROWSER=google-chrome-stable make coverage
165
166 ## OBD-II Basics
167
168 TODO diagram out a request, response and error response
169
170 * store the request arb id, mode, pid, and payload locally
171 * send a can message
172 * get all new can messages passed to it
173 * Check the incoming can message to see if it matches one of the standard ECU
174   response IDs, or our arb ID + 0x8
175 * if it matches, parse the diagnostic response and call the callback
176
177
178 ## Future Notes
179
180 you're going to request a few PIDs over and over again at some frequency
181 you're going to request DTCs once and read the response
182 you're going to clear DTCs once
183
184 we need another layer on top of that to handle the repeated requests.
185
186 ## Authors
187
188 Chris Peplin cpeplin@ford.com
189
190 ## License
191
192 Copyright (c) 2013 Ford Motor Company
193
194 Licensed under the BSD license.