Move notes lower down in README.
[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     void 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 stadnard broadcast
41 address, `0x7df`:
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             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)
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: 0x7df,
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 ## Testing
149
150 The library includes a test suite that uses the `check` C unit test library.
151
152     $ make test
153
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:
156
157     $ BROWSER=google-chrome-stable make coverage
158
159 ## OBD-II Basics
160
161 TODO diagram out a request, response and error response
162
163 * store the request arb id, mode, pid, and payload locally
164 * send a can message
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
169
170
171 ## Future Notes
172
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
176
177 we need another layer on top of that to handle the repeated requests.
178
179 ## Authors
180
181 Chris Peplin cpeplin@ford.com
182
183 ## License
184
185 Copyright (c) 2013 Ford Motor Company
186
187 Licensed under the BSD license.