Add skeleton of the API and data structures.
[apps/agl-service-can-low-level.git] / src / obd2 / obd2.h
1 #ifndef __OBD2_H__
2 #define __OBD2_H__
3
4 #include <isotp/isotp.h>
5 #include <stdint.h>
6 #include <stdbool.h>
7
8 #ifdef __cplusplus
9 extern "C" {
10 #endif
11
12 #define MAX_OBD2_PAYLOAD_LENGTH 7
13 #define VIN_LENGTH 17
14
15 typedef void (*LogShim)(const char* message);
16 typedef bool (*SendCanMessageShim)(const uint16_t arbitration_id,
17         const uint8_t* data, const uint8_t size);
18 typedef bool (*SetTimerShim)(uint16_t time_ms, void (*callback));
19
20 typedef struct {
21     uint16_t arbitration_id;
22     uint8_t mode;
23     uint16_t pid;
24     uint8_t payload[MAX_OBD2_PAYLOAD_LENGTH];
25     uint8_t payload_length;
26 } DiagnosticRequest;
27
28 // Thanks to
29 // http://www.canbushack.com/blog/index.php?title=scanning-for-diagnostic-data&more=1&c=1&tb=1&pb=1
30 // for the list of NRCs
31 typedef enum {
32     NRC_SERVICE_NOT_SUPPORTED = 0x11,
33     NRC_SUB_FUNCTION_NOT_SUPPORTED = 0x12,
34     NRC_CONDITIONS_NOT_CORRECT = 0x22,
35     NRC_REQUEST_OUT_OF_RANGE = 0x31,
36     NRC_SECURITY_ACCESS_DENIED = 0x33,
37     NRC_INVALID_KEY = 0x35,
38     NRC_TOO_MANY_ATTEMPS = 0x36,
39     NRC_TIME_DELAY_NOT_EXPIRED = 0x37,
40     NRC_RESPONSE_PENDING = 0x78
41 } DiagnosticNegativeResponseCode;
42
43 typedef enum {
44     OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST = 0x1,
45     OBD2_MODE_POWERTRAIN_FREEZE_FRAME_REQUEST = 0x2,
46     OBD2_MODE_EMISSIONS_DTC_REQUEST = 0x3,
47     OBD2_MODE_EMISSIONS_DTC_CLEAR = 0x4,
48     // 0x5 is for non-CAN only
49     // OBD2_MODE_OXYGEN_SENSOR_TEST = 0x5,
50     OBD2_MODE_TEST_RESULTS = 0x6,
51     OBD2_MODE_DRIVE_CYCLE_DTC_REQUEST = 0x7,
52     OBD2_MODE_CONTROL = 0x8,
53     OBD2_MODE_VEHICLE_INFORMATION = 0x9,
54     OBD2_MODE_PERMANENT_DTC_REQUEST = 0xa,
55     // this one isn't technically in OBD2, but both of the enhanced standards
56     // have their PID requests at 0x22
57     OBD2_MODE_ENHANCED_DIAGNOSTIC_REQUEST = 0x22
58 } DiagnosticMode;
59
60 typedef enum {
61     DTC_EMISSIONS,
62     DTC_DRIVE_CYCLE,
63     DTC_PERMANENT
64 } DiagnosticTroubleCodeType;
65
66 typedef struct {
67     uint16_t arbitration_id;
68     uint8_t mode;
69     bool success;
70     // if mode is one with a PID, read the correct numbers of PID bytes (1 or 2)
71     // into this field, then store the remainder of the payload in the payload
72     // field
73     uint16_t pid;
74     DiagnosticNegativeResponseCode negative_response_code;
75     // if response mode is a negative response, read first byte of payload into
76     // NRC and store remainder of payload in payload field
77     uint8_t payload[MAX_OBD2_PAYLOAD_LENGTH];
78     uint8_t payload_length;
79 } DiagnosticResponse;
80
81 typedef enum {
82     POWERTRAIN = 0x0,
83     CHASSIS = 0x1,
84     BODY = 0x2,
85     NETWORK = 0x3
86 } DiagnosticTroubleCodeGroup;
87
88 typedef struct {
89     DiagnosticTroubleCodeGroup group;
90     uint8_t group_num;
91     uint8_t code;
92 } DiagnosticTroubleCode;
93
94 typedef void (*DiagnosticResponseReceived)(const DiagnosticResponse* response);
95 typedef void (*DiagnosticMilStatusReceived)(bool malfunction_indicator_status);
96 typedef void (*DiagnosticVinReceived)(uint8_t vin[]);
97 typedef void (*DiagnosticTroubleCodesReceived)(
98         DiagnosticMode mode, DiagnosticTroubleCode* codes);
99 typedef void (*DiagnosticPidEnumerationReceived)(
100         const DiagnosticResponse* response, uint16_t* pids);
101
102 // TODO should we enumerate every OBD-II PID? need conversion formulas, too
103 typedef struct {
104     uint16_t pid;
105     uint8_t bytes_returned;
106     float min_value;
107     float max_value;
108 } DiagnosticParameter;
109
110 typedef enum {
111     DIAGNOSTIC_REQUEST_TYPE_PID,
112     DIAGNOSTIC_REQUEST_TYPE_DTC,
113     DIAGNOSTIC_REQUEST_TYPE_MIL_STATUS,
114     DIAGNOSTIC_REQUEST_TYPE_VIN
115 } DiagnosticRequestType;
116
117 typedef struct {
118     IsoTpHandler isotp_handler;
119     DiagnosticRequestType type;
120     DiagnosticResponseReceived callback;
121     DiagnosticMilStatusReceived mil_status_callback;
122     DiagnosticVinReceived vin_callback;
123     bool status;
124 } DiagnosticRequestHandle;
125
126 typedef enum {
127     DIAGNOSTIC_STANDARD_PID,
128     DIAGNOSTIC_ENHANCED_PID
129 } DiagnosticPidRequestType;
130
131 typedef struct {
132     IsoTpShims isotp_shims;
133     LogShim log;
134     SendCanMessageShim send_can_message;
135 } DiagnosticShims;
136
137 DiagnosticShims diagnostic_init_shims(LogShim log,
138         SendCanMessageShim send_can_message,
139         SetTimerShim set_timer);
140
141 DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims,
142         DiagnosticRequest* request, DiagnosticResponseReceived callback);
143
144 // decide mode 0x1 / 0x22 based on pid type
145 DiagnosticRequestHandle diagnostic_request_pid(DiagnosticShims* shims,
146         DiagnosticPidRequestType pid_request_type, uint16_t pid,
147         DiagnosticResponseReceived callback);
148
149 DiagnosticRequestHandle diagnostic_request_malfunction_indicator_status(
150         DiagnosticShims* shims,
151         DiagnosticMilStatusReceived callback);
152
153 DiagnosticRequestHandle diagnostic_request_vin(DiagnosticShims* shims,
154         DiagnosticVinReceived callback);
155
156 DiagnosticRequestHandle diagnostic_request_dtc(DiagnosticShims* shims,
157         DiagnosticTroubleCodeType dtc_type,
158         DiagnosticTroubleCodesReceived callback);
159
160 bool diagnostic_clear_dtc(DiagnosticShims* shims);
161
162 DiagnosticRequestHandle diagnostic_enumerate_pids(DiagnosticShims* shims,
163         DiagnosticRequest* request, DiagnosticPidEnumerationReceived callback);
164
165 void diagnostic_receive_can_frame(DiagnosticRequestHandle* handler,
166         const uint16_t arbitration_id, const uint8_t data[],
167         const uint8_t size);
168
169 #ifdef __cplusplus
170 }
171 #endif
172
173 #endif // __OBD2_H__