Document all remaining methods and data structures.
[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 ## OBD-II Basics
13
14 TODO diagram out a request, response and error response
15
16 * store the request arb id, mode, pid, and payload locally
17 * send a can message
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
22
23 ## Usage
24
25 First, create some shim functions to let this library use your lower level
26 system:
27
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
30     // bytes.
31     void send_can(const uint16_t arbitration_id, const uint8_t* data,
32             const uint8_t size) {
33         ...
34     }
35
36     // optional, provide to receive debugging log messages
37     void debug(const char* format, ...) {
38         ...
39     }
40
41
42     // not used in the current version
43     void set_timer(uint16_t time_ms, void (*callback)) {
44         ...
45     }
46
47 With your shims in place, create a `DiagnosticShims` object to pass them around:
48
49     DiagnosticShims shims = diagnostic_init_shims(debug, send_can, set_timer);
50
51 With your shims in hand, send a simple PID request to the stadnard broadcast
52 address, `0x7df`:
53
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.
58     }
59
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)
65
66     if(handle.completed) {
67         if(!handle.success) {
68             // something happened and it already failed - possibly we aren't
69             // able to send CAN messages
70             return;
71         } else {
72             // this should never occur right away - you need to receive a fresh
73             // CAN message first
74         }
75     } else {
76         while(true) {
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));
83
84             if(response.completed && handle.completed) {
85                 if(handle.success) {
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!
90                   } else {
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);
95                   }
96                 } else {
97                     // Some other fatal error ocurred - we weren't able to send
98                     // the request or receive the response. The CAN connection
99                     // may be down.
100                 }
101             }
102         }
103     }
104
105 ## Requests for other modes
106
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.
109
110     DiagnosticRequest request = {
111         arbitration_id: 0x7df,
112         mode: OBD2_MODE_EMISSIONS_DTC_REQUEST
113     };
114     DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request, NULL);
115
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
120             return;
121         } else {
122             // this should never occur right away - you need to receive a fresh
123             // CAN message first
124         }
125     } else {
126         while(true) {
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));
133
134             if(response.completed && handle.completed) {
135                 if(handle.success) {
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]);
143                       }
144                   } else {
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);
149                   }
150                 } else {
151                     // Some other fatal error ocurred - we weren't able to send
152                     // the request or receive the response. The CAN connection
153                     // may be down.
154                 }
155             }
156         }
157     }
158
159 ## Testing
160
161 The library includes a test suite that uses the `check` C unit test library.
162
163     $ make test
164
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:
167
168     $ BROWSER=google-chrome-stable make coverage
169
170 ## Future Notes
171
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
175
176 we need another layer on top of that to handle the repeated requests.
177
178 ## Authors
179
180 Chris Peplin cpeplin@ford.com
181
182 ## License
183
184 Copyright (c) 2013 Ford Motor Company
185
186 Licensed under the BSD license.