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