aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.mkd66
m---------deps/isotp-c10
-rw-r--r--src/obd2/obd2.c47
-rw-r--r--src/obd2/obd2.h173
-rw-r--r--tests/common.c0
-rw-r--r--tests/test_core.c (renamed from tests/tests.c)3
6 files changed, 292 insertions, 7 deletions
diff --git a/README.mkd b/README.mkd
index 485f2cc5..96b969ee 100644
--- a/README.mkd
+++ b/README.mkd
@@ -1,8 +1,74 @@
OBD-II Support Library in C
=============================
+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
+
+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
+
+but that does complicate the memory management because it'll need to create
+some internal data structures.
+
+at the simplest, what does this handler have to do?
+
+* store the request arb id, mode, pid, and payload locally
+* send a can message
+* get all new can messages passed to it
+* Check the incoming can message to see if it matches one of the standard ECU
+ 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
+
+what we need is another layer on top of that to handle the repeated requests.
+
## API
+ void my_callback(const DiagnosticResponse* response) {
+ }
+
+ DiagnosticRequestHandler handler = diagnostic_init(my_callback);
+ DiagnosticRequest request = {
+ arbitratin_id: 0x7df,
+ mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST,
+ pid: 3
+ };
+
+ diagnostic_send(&handler, &request);
+ while(true) {
+ diagnostic_handle_can_frame(&handler, 42, data, 8);
+ }
+
+ diagnostic_request_pid(&handler, DIAGNOSTIC_STANDARD_PID, 42
+
+ diagnostic_destroy(&handler);
+
## Testing
The library includes a test suite that uses the `check` C unit test library.
diff --git a/deps/isotp-c b/deps/isotp-c
-Subproject 368d36cc15b69882e9d21803f3b8aa7a1c97736
+Subproject bc7c0205d8dd7550060f6f0bbe8e2064d28ace8
diff --git a/src/obd2/obd2.c b/src/obd2/obd2.c
new file mode 100644
index 00000000..9b4ea92d
--- /dev/null
+++ b/src/obd2/obd2.c
@@ -0,0 +1,47 @@
+#include <obd2/obd2.h>
+
+DiagnosticShims diagnostic_init_shims(LogShim log,
+ SendCanMessageShim send_can_message,
+ SetTimerShim set_timer) {
+}
+
+DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims,
+ DiagnosticRequest* request, DiagnosticResponseReceived callback) {
+}
+
+// decide mode 0x1 / 0x22 based on pid type
+DiagnosticRequestHandle diagnostic_request_pid(DiagnosticShims* shims,
+ DiagnosticPidRequestType pid_request_type, uint16_t pid,
+ DiagnosticResponseReceived callback) {
+}
+
+// TODO request malfunction indicator light (MIL) status - request mode 1 pid 1,
+// parse first bit
+DiagnosticRequestHandle diagnostic_request_malfunction_indicator_status(
+ DiagnosticShims* shims,
+ DiagnosticMilStatusReceived callback) {
+}
+
+DiagnosticRequestHandle diagnostic_request_vin(DiagnosticShims* shims,
+ DiagnosticVinReceived callback) {
+}
+
+DiagnosticRequestHandle diagnostic_request_dtc(DiagnosticShims* shims,
+ DiagnosticTroubleCodeType dtc_type,
+ DiagnosticTroubleCodesReceived callback) {
+}
+
+bool diagnostic_clear_dtc(DiagnosticShims* shims) {
+}
+
+// before calling the callback, split up the received bytes into 1 or 2 byte
+// chunks depending on the mode so the final pid list is actual 1 or 2 byte PIDs
+// TODO request supported PIDs - request PID 0 and parse 4 bytes in response
+DiagnosticRequestHandle diagnostic_enumerate_pids(DiagnosticShims* shims,
+ DiagnosticRequest* request, DiagnosticPidEnumerationReceived callback) {
+}
+
+void diagnostic_receive_can_frame(DiagnosticRequestHandle* handler,
+ const uint16_t arbitration_id, const uint8_t data[],
+ const uint8_t size) {
+}
diff --git a/src/obd2/obd2.h b/src/obd2/obd2.h
new file mode 100644
index 00000000..e6b5bc96
--- /dev/null
+++ b/src/obd2/obd2.h
@@ -0,0 +1,173 @@
+#ifndef __OBD2_H__
+#define __OBD2_H__
+
+#include <isotp/isotp.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_OBD2_PAYLOAD_LENGTH 7
+#define VIN_LENGTH 17
+
+typedef void (*LogShim)(const char* message);
+typedef bool (*SendCanMessageShim)(const uint16_t arbitration_id,
+ const uint8_t* data, const uint8_t size);
+typedef bool (*SetTimerShim)(uint16_t time_ms, void (*callback));
+
+typedef struct {
+ uint16_t arbitration_id;
+ uint8_t mode;
+ uint16_t pid;
+ uint8_t payload[MAX_OBD2_PAYLOAD_LENGTH];
+ uint8_t payload_length;
+} DiagnosticRequest;
+
+// Thanks to
+// http://www.canbushack.com/blog/index.php?title=scanning-for-diagnostic-data&more=1&c=1&tb=1&pb=1
+// for the list of NRCs
+typedef enum {
+ NRC_SERVICE_NOT_SUPPORTED = 0x11,
+ NRC_SUB_FUNCTION_NOT_SUPPORTED = 0x12,
+ NRC_CONDITIONS_NOT_CORRECT = 0x22,
+ NRC_REQUEST_OUT_OF_RANGE = 0x31,
+ NRC_SECURITY_ACCESS_DENIED = 0x33,
+ NRC_INVALID_KEY = 0x35,
+ NRC_TOO_MANY_ATTEMPS = 0x36,
+ NRC_TIME_DELAY_NOT_EXPIRED = 0x37,
+ NRC_RESPONSE_PENDING = 0x78
+} DiagnosticNegativeResponseCode;
+
+typedef enum {
+ OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST = 0x1,
+ OBD2_MODE_POWERTRAIN_FREEZE_FRAME_REQUEST = 0x2,
+ OBD2_MODE_EMISSIONS_DTC_REQUEST = 0x3,
+ OBD2_MODE_EMISSIONS_DTC_CLEAR = 0x4,
+ // 0x5 is for non-CAN only
+ // OBD2_MODE_OXYGEN_SENSOR_TEST = 0x5,
+ OBD2_MODE_TEST_RESULTS = 0x6,
+ OBD2_MODE_DRIVE_CYCLE_DTC_REQUEST = 0x7,
+ OBD2_MODE_CONTROL = 0x8,
+ OBD2_MODE_VEHICLE_INFORMATION = 0x9,
+ OBD2_MODE_PERMANENT_DTC_REQUEST = 0xa,
+ // this one isn't technically in OBD2, but both of the enhanced standards
+ // have their PID requests at 0x22
+ OBD2_MODE_ENHANCED_DIAGNOSTIC_REQUEST = 0x22
+} DiagnosticMode;
+
+typedef enum {
+ DTC_EMISSIONS,
+ DTC_DRIVE_CYCLE,
+ DTC_PERMANENT
+} DiagnosticTroubleCodeType;
+
+typedef struct {
+ uint16_t arbitration_id;
+ uint8_t mode;
+ bool success;
+ // if mode is one with a PID, read the correct numbers of PID bytes (1 or 2)
+ // into this field, then store the remainder of the payload in the payload
+ // field
+ uint16_t pid;
+ DiagnosticNegativeResponseCode negative_response_code;
+ // if response mode is a negative response, read first byte of payload into
+ // NRC and store remainder of payload in payload field
+ uint8_t payload[MAX_OBD2_PAYLOAD_LENGTH];
+ uint8_t payload_length;
+} DiagnosticResponse;
+
+typedef enum {
+ POWERTRAIN = 0x0,
+ CHASSIS = 0x1,
+ BODY = 0x2,
+ NETWORK = 0x3
+} DiagnosticTroubleCodeGroup;
+
+typedef struct {
+ DiagnosticTroubleCodeGroup group;
+ uint8_t group_num;
+ uint8_t code;
+} DiagnosticTroubleCode;
+
+typedef void (*DiagnosticResponseReceived)(const DiagnosticResponse* response);
+typedef void (*DiagnosticMilStatusReceived)(bool malfunction_indicator_status);
+typedef void (*DiagnosticVinReceived)(uint8_t vin[]);
+typedef void (*DiagnosticTroubleCodesReceived)(
+ DiagnosticMode mode, DiagnosticTroubleCode* codes);
+typedef void (*DiagnosticPidEnumerationReceived)(
+ const DiagnosticResponse* response, uint16_t* pids);
+
+// TODO should we enumerate every OBD-II PID? need conversion formulas, too
+typedef struct {
+ uint16_t pid;
+ uint8_t bytes_returned;
+ float min_value;
+ float max_value;
+} DiagnosticParameter;
+
+typedef enum {
+ DIAGNOSTIC_REQUEST_TYPE_PID,
+ DIAGNOSTIC_REQUEST_TYPE_DTC,
+ DIAGNOSTIC_REQUEST_TYPE_MIL_STATUS,
+ DIAGNOSTIC_REQUEST_TYPE_VIN
+} DiagnosticRequestType;
+
+typedef struct {
+ IsoTpHandler isotp_handler;
+ DiagnosticRequestType type;
+ DiagnosticResponseReceived callback;
+ DiagnosticMilStatusReceived mil_status_callback;
+ DiagnosticVinReceived vin_callback;
+ bool status;
+} DiagnosticRequestHandle;
+
+typedef enum {
+ DIAGNOSTIC_STANDARD_PID,
+ DIAGNOSTIC_ENHANCED_PID
+} DiagnosticPidRequestType;
+
+typedef struct {
+ IsoTpShims isotp_shims;
+ LogShim log;
+ SendCanMessageShim send_can_message;
+} DiagnosticShims;
+
+DiagnosticShims diagnostic_init_shims(LogShim log,
+ SendCanMessageShim send_can_message,
+ SetTimerShim set_timer);
+
+DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims,
+ DiagnosticRequest* request, DiagnosticResponseReceived callback);
+
+// decide mode 0x1 / 0x22 based on pid type
+DiagnosticRequestHandle diagnostic_request_pid(DiagnosticShims* shims,
+ DiagnosticPidRequestType pid_request_type, uint16_t pid,
+ DiagnosticResponseReceived callback);
+
+DiagnosticRequestHandle diagnostic_request_malfunction_indicator_status(
+ DiagnosticShims* shims,
+ DiagnosticMilStatusReceived callback);
+
+DiagnosticRequestHandle diagnostic_request_vin(DiagnosticShims* shims,
+ DiagnosticVinReceived callback);
+
+DiagnosticRequestHandle diagnostic_request_dtc(DiagnosticShims* shims,
+ DiagnosticTroubleCodeType dtc_type,
+ DiagnosticTroubleCodesReceived callback);
+
+bool diagnostic_clear_dtc(DiagnosticShims* shims);
+
+DiagnosticRequestHandle diagnostic_enumerate_pids(DiagnosticShims* shims,
+ DiagnosticRequest* request, DiagnosticPidEnumerationReceived callback);
+
+void diagnostic_receive_can_frame(DiagnosticRequestHandle* handler,
+ const uint16_t arbitration_id, const uint8_t data[],
+ const uint8_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __OBD2_H__
diff --git a/tests/common.c b/tests/common.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/common.c
diff --git a/tests/tests.c b/tests/test_core.c
index 68745652..65af8580 100644
--- a/tests/tests.c
+++ b/tests/test_core.c
@@ -1,8 +1,7 @@
#include <check.h>
#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
+#include <stdbool.h>
void setup() {