summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.mkd196
m---------deps/isotp-c6
-rw-r--r--src/obd2/obd2.h2
-rw-r--r--tests/test_core.c2
4 files changed, 155 insertions, 51 deletions
diff --git a/README.mkd b/README.mkd
index bd074e99..5e962f04 100644
--- a/README.mkd
+++ b/README.mkd
@@ -1,42 +1,17 @@
OBD-II Support Library in C
=============================
-TODO diagram out a request, response and error response
-
-TODO isotp needs to accept responses on an ID other that the request's arb id -
-or maybe we have 2 isotp instances, for rx and tx.
-
-* Response's arb id is assigned ID plus 0x8
-* Functional daignostic request (Broadcast), 0x7df arb id
-* Standard ECU requests to 0x7e0 - 0x7e7
-
-* Some requests don't need PIDs - e.g. mode 3
- * some responses don't have PIDs, just payload - e.g. mode 3
-
-* Service ID + 0x40 == positive response
-* Response includes PID echo - use this to match up request/response
-* Response ID, ISO-TP PCI, ISO-TP length, service response ID, PID echo, data
-
-I send the request and give a callback
-when the response arrives for the matchin service and PID - on any arb id, since
-this may be a broadcast - call my callback.
-
-
-TODO do you want to provide the callback to the Handler, or to each
-individual send?o
-ok, what are the use cases here.
-
-you're going to request a few PIDs over and over again at some frequency
-you're going to request DTCs once and read the response
-you're going to clear DTCs once
+This is a platform agnostic C library that implements the standard On Board
+Diagnostics system for vehicles. It currently supports OBD-II running over CAN
+(ISO 15765-4), which uses the ISO-TP (ISO 15765-2) protocol underneath.
-i'd rather use the same diagnostic handler to send all of the differet messages
-rather than create one for each use. that way ai can
+This library doesn't assume anything about the source of your diagnostic message
+requests or underlying interface to the CAN bus. It uses dependency injection to
+give you complete control.
-but that does complicate the memory management because it'll need to create
-some internal data structures.
+## OBD-II Basics
-at the simplest, what does this handler have to do?
+TODO diagram out a request, response and error response
* store the request arb id, mode, pid, and payload locally
* send a can message
@@ -45,31 +20,141 @@ at the simplest, what does this handler have to do?
response IDs, or our arb ID + 0x8
* if it matches, parse the diagnostic response and call the callback
-that seems pretty simple and not worth greatly increasing the internal state to
-handle multiple requests
+## Usage
-what we need is another layer on top of that to handle the repeated requests.
+First, create some shim functions to let this library use your lower level
+system:
-## API
+ // required, this must send a single CAN message with the given arbitration
+ // ID (i.e. the CAN message ID) and data. The size will never be more than 8
+ // bytes.
+ void send_can(const uint16_t arbitration_id, const uint8_t* data,
+ const uint8_t size) {
+ ...
+ }
- void my_callback(const DiagnosticResponse* response) {
+ // optional, provide to receive debugging log messages
+ void debug(const char* format, ...) {
+ ...
}
- DiagnosticRequestHandle handle = diagnostic_init(my_callback);
- DiagnosticRequest request = {
- arbitratin_id: 0x7df,
- mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST,
- pid: 3
- };
- diagnostic_send(&handle, &request);
- while(true) {
- diagnostic_handle_can_frame(&handle, 42, data, 8);
+ // not used in the current version
+ void set_timer(uint16_t time_ms, void (*callback)) {
+ ...
}
- diagnostic_request_pid(&handle, DIAGNOSTIC_STANDARD_PID, 42
+With your shims in place, create a `DiagnosticShims` object to pass them around:
- diagnostic_destroy(&handle);
+ DiagnosticShims shims = diagnostic_init_shims(debug, send_can, set_timer);
+
+With your shims in hand, send a simple PID request to the stadnard broadcast
+address, `0x7df`:
+
+ // Optional: This is your callback that will be called the response to your
+ // diagnostic request is received.
+ void response_received_handler(const DiagnosticResponse* response) {
+ // You received a response! Do something with it.
+ }
+
+ DiagnosticRequestHandle handle = diagnostic_request_pid(&shims,
+ DIAGNOSTIC_STANDARD_PID, // this is a standard PID request, not an extended or enhanced one
+ 0x7df, // the request is going out to the broadcast arbitration ID
+ 0x2, // we want PID 0x2
+ response_received_handler); // our callback (optional, use NULL if you don't have one)
+
+ if(handle.completed) {
+ if(!handle.success) {
+ // something happened and it already failed - possibly we aren't
+ // able to send CAN messages
+ return;
+ } else {
+ // this should never occur right away - you need to receive a fresh
+ // CAN message first
+ }
+ } else {
+ while(true) {
+ // Continue to read from CAN, passing off each message to the handle.
+ // This will return a 'completed' DiagnosticResponse when the when
+ // the request is completely sent and the response is received
+ // (which may take more than 1 CAN frames)
+ DiagnosticResponse response = diagnostic_receive_can_frame(&shims,
+ &handle, can_message_id, can_data, sizeof(can_data));
+
+ if(response.completed && handle.completed) {
+ if(handle.success) {
+ if(response.success) {
+ // The request was sent successfully, the response was
+ // received successfully, and it was a positive response - we
+ // got back some data!
+ } else {
+ // The request was sent successfully, the response was
+ // received successfully, BUT it was a negative response
+ // from the other node.
+ printf("This is the error code: %d", response.negative_response_code);
+ }
+ } else {
+ // Some other fatal error ocurred - we weren't able to send
+ // the request or receive the response. The CAN connection
+ // may be down.
+ }
+ }
+ }
+ }
+
+## Requests for other modes
+
+If you want to do more besides PID requests on mode 0x1 and 0x22, there's a
+lower level API you can use. Here's how to make a mode 3 request to get DTCs.
+
+ DiagnosticRequest request = {
+ arbitration_id: 0x7df,
+ mode: OBD2_MODE_EMISSIONS_DTC_REQUEST
+ };
+ DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request, NULL);
+
+ if(handle.completed) {
+ if(!handle.success) {
+ // something happened and it already failed - possibly we aren't
+ // able to send CAN messages
+ return;
+ } else {
+ // this should never occur right away - you need to receive a fresh
+ // CAN message first
+ }
+ } else {
+ while(true) {
+ // Continue to read from CAN, passing off each message to the handle.
+ // This will return a 'completed' DiagnosticResponse when the when
+ // the request is completely sent and the response is received
+ // (which may take more than 1 CAN frames)
+ DiagnosticResponse response = diagnostic_receive_can_frame(&shims,
+ &handle, can_message_id, can_data, sizeof(can_data));
+
+ if(response.completed && handle.completed) {
+ if(handle.success) {
+ if(response.success) {
+ // The request was sent successfully, the response was
+ // received successfully, and it was a positive response - we
+ // got back some data!
+ printf("The DTCs are: ");
+ for(int i = 0; i < response.payload_length; i++) {
+ printf("0x%x ", response.payload[i]);
+ }
+ } else {
+ // The request was sent successfully, the response was
+ // received successfully, BUT it was a negative response
+ // from the other node.
+ printf("This is the error code: %d", response.negative_response_code);
+ }
+ } else {
+ // Some other fatal error ocurred - we weren't able to send
+ // the request or receive the response. The CAN connection
+ // may be down.
+ }
+ }
+ }
+ }
## Testing
@@ -77,6 +162,19 @@ The library includes a test suite that uses the `check` C unit test library.
$ make test
+You can also see the test coverage if you have `lcov` installed and the
+`BROWSER` environment variable set to your choice of web browsers:
+
+ $ BROWSER=google-chrome-stable make coverage
+
+## Future Notes
+
+you're going to request a few PIDs over and over again at some frequency
+you're going to request DTCs once and read the response
+you're going to clear DTCs once
+
+we need another layer on top of that to handle the repeated requests.
+
## Authors
Chris Peplin cpeplin@ford.com
diff --git a/deps/isotp-c b/deps/isotp-c
-Subproject 101d36e65bc7cb2b1fc8e4dbae4eacf749c98b0
+Subproject 8922abb7ff8c30e1fa5af078284eb6aebf0052e
diff --git a/src/obd2/obd2.h b/src/obd2/obd2.h
index a2ea033c..8cdd4a1b 100644
--- a/src/obd2/obd2.h
+++ b/src/obd2/obd2.h
@@ -73,8 +73,8 @@ typedef enum {
typedef struct {
uint16_t arbitration_id;
uint8_t mode;
- bool success;
bool completed;
+ bool success;
uint16_t pid;
DiagnosticNegativeResponseCode negative_response_code;
uint8_t payload[MAX_OBD2_PAYLOAD_LENGTH];
diff --git a/tests/test_core.c b/tests/test_core.c
index 16863a97..cf8673ae 100644
--- a/tests/test_core.c
+++ b/tests/test_core.c
@@ -60,7 +60,7 @@ START_TEST (test_send_diag_request)
{
DiagnosticRequest request = {
arbitration_id: 0x7df,
- mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST
+ mode: OBD2_MODE_EMISSIONS_DTC_REQUEST
};
DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
response_received_handler);