BOROSOFTWAREAll work →
scantool/diag_l3_iso14230.c 351 lines
1/*
2 * freediag - Vehicle Diagnostic Utility
3 *
4 *
5 * Copyright (C) 2001 Richard Almeida & Ibex Ltd ([email protected])
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 *************************************************************************
22 *
23 * L7, ISO14230-3 KeyWord 2000 protocol
24 * routines
25 * This doesn't duplicate what is provided by the L3 J1979 handler.
26 * It provides iso14230 SID + response code string decoding,
27 */
28
29#include <stdint.h>
30#include <stdio.h>
31
32#include "diag.h"
33#include "diag_err.h"
34#include "diag_iso14230.h"
35#include "diag_l2.h"
36#include "diag_l3.h"
37#include "diag_l3_iso14230.h"
38
39
40
41static const char *l3_iso14230_sidlookup(const int id);
42static const char *l3_iso14230_neglookup(const int id);
43
44#define RESP_MAXLEN 80 //max length for response code strings.
45
46/*
47 * We'll use a big switch statement here, and rely on the compiler
48 * to make it efficient
49 * it assumes the packet in *buf has no more headers ! i.e. buf[0]
50 * is the service ID byte.
51 */
52char *diag_l3_iso14230_decode_response(struct diag_msg *msg,
53 char *buf, const size_t bufsize) {
54 char buf2[RESP_MAXLEN];
55
56 switch (msg->data[0]) {
57 //for these 3 SID's,
58 case DIAG_KW2K_RC_SCRPR:
59 snprintf(buf, bufsize, "StartCommunications_OK");
60 break;
61 case DIAG_KW2K_RC_SPRPR:
62 snprintf(buf, bufsize, "StopCommunications_OK");
63 break;
64 case DIAG_KW2K_RC_ATPPR:
65 snprintf(buf, bufsize, "AccessTimingParameters_OK");
66 break;
67
68 case DIAG_KW2K_RC_NR:
69 if (msg->len < 3) {
70 snprintf(buf, bufsize, "General_Error, no response code");
71 } else {
72
73 snprintf(buf, bufsize, "General_Error, Requested_SID_%s ",
74 l3_iso14230_sidlookup(msg->data[1]));
75
76 snprintf(buf2, sizeof(buf2), "Error_%s",
77 l3_iso14230_neglookup(msg->data[2]));
78
79 /* Don't overflow our buffers. */
80
81 smartcat(buf, bufsize, buf2 );
82 }
83 break;
84 default:
85 //data[0] is either a "positive response service identifier (SNPR)"
86 //or a NACK (0x7F); which we already checked... bit 6 is set on all
87 // positive responses (14230-3 table 1)
88 if (msg->data[0] & 0x40) {
89 snprintf(buf, bufsize, "Positive response, %s ",
90 l3_iso14230_sidlookup(msg->data[0] & ~0x40));
91 switch (msg->data[0] & ~0x40) {
92 case DIAG_KW2K_SI_REID:
93 snprintf(buf2, sizeof(buf2), "identOption 0x%02X", msg->data[1]);
94 smartcat(buf, bufsize, buf2);
95 break;
96 case DIAG_KW2K_SI_RDDBLI:
97 snprintf(buf2, sizeof(buf2), "RLOCID 0x%02X", msg->data[1]);
98 smartcat(buf, bufsize, buf2);
99 break;
100 default:
101 break;
102 }
103 //TODO : add "custom" printout for every SID that has a local ID ?
104 //or maybe expand the SID tables to include a field that indicates how many
105 //extra bytes are meaningful. For example, SID 27 SecurityAccess
106
107 } else {
108 snprintf(buf, bufsize, "Unknown_response_code 0x%02X",
109 msg->data[0]);
110 }
111 break;
112 }
113
114 return buf;
115}
116
117
118//return 0 if ok.
119//the data in *msg should have no headers and no checksum, obviously.
120//address information should be already set as well; this function just
121//forwards the request to l2_send (presumably the user is using this L3
122//proto over an iso14230 L2 proto. Running an iso14230 L3 over anything other
123//than iso14230 is meaningless.
124static int diag_l3_iso14230_send(struct diag_l3_conn *d_l3_conn, struct diag_msg *msg) {
125 int rv;
126 struct diag_l2_conn *d_conn;
127
128 /* Get l2 connection info */
129 d_conn = d_l3_conn->d_l3l2_conn;
130
131 DIAG_DBGMDATA(diag_l3_debug, DIAG_DEBUG_WRITE, DIAG_DBGLEVEL_V,
132 msg->data, (size_t)msg->len,
133 FLFMT "_send %u bytes, l2 flags 0x%X\n",
134 FL, msg->len, d_l3_conn->d_l3l2_flags);
135
136 // L2 does framing, adds addressing and CRC, so do nothing special
137
138 rv = diag_l2_send(d_conn, msg);
139 return rv? diag_ifwderr(rv):0;
140}
141
142
143/*
144 * RX callback, called as data received from L2 (from l3_recv). If we get a full message,
145 * call L3 callback routine
146 */
147static void diag_l3_14230_rxcallback(void *handle, struct diag_msg *msg) {
148 /*
149 * Got some data from L2, build it into a L3 message, if
150 * message is complete call next layer callback routine
151 */
152 struct diag_l3_conn *d_l3_conn = (struct diag_l3_conn *)handle;
153 char buffer[200];
154
155 DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V,
156 FLFMT "rcv_callback for %u bytes fmt 0x%X conn\n",
157 FL, msg->len, msg->fmt);
158
159 if (diag_l3_iso14230_decode_response(msg, buffer, sizeof(buffer))) {
160 fprintf(stderr, "DECODED: %s\n",buffer);
161 }
162
163 if (msg->fmt & DIAG_FMT_FRAMED) {
164 /* Send data upward if needed */
165 if (d_l3_conn->callback) {
166 d_l3_conn->callback(d_l3_conn->handle, msg);
167 }
168 } else {
169 fprintf(stderr, FLFMT "problem: got an unframed message!\n"
170 "Report this !\n", FL);
171 }
172}
173
174
175//This just forwards the request to the L2 recv function. I can't see how we could use an
176// iso14230 L3 over anything else than an iso14230 L2, so there's no reason to do anything else
177// in here.
178static int diag_l3_iso14230_recv(struct diag_l3_conn *d_l3_conn, unsigned int timeout,
179 void (* rcv_call_back)(void *handle,struct diag_msg *), void *handle) {
180
181 int rv;
182
183 if (d_l3_conn->d_l3l2_flags & DIAG_L2_FLAG_FRAMED) {
184 /*
185 * L2 does framing stuff , which means we get one message
186 * with nicely formed frames
187 */
188 /* Store the callback routine for use if needed */
189 d_l3_conn->callback = rcv_call_back;
190 d_l3_conn->handle = handle;
191
192 /*
193 * Call L2 receive, L2 will build up the datapacket and
194 * call the callback routine if needed
195 */
196
197 rv = diag_l2_recv(d_l3_conn->d_l3l2_conn, timeout,
198 diag_l3_14230_rxcallback, (void *)d_l3_conn);
199
200 DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V,
201 FLFMT "_recv returns %d\n", FL, rv);
202
203 } else {
204 //problem : the only time DIAG_L2_FLAG_FRAMED is not set is if
205 //L2 is raw. Who uses a raw L2 instead of 14230 L2 ???
206 //so we'll complain loudly
207 fprintf(stderr, FLFMT "*** Error : using iso14230 L3 code on a non-iso14230\n", FL);
208 fprintf(stderr, FLFMT "*** L2 interface !! Please report this.\n", FL);
209 return diag_iseterr(DIAG_ERR_PROTO_NOTSUPP);
210 }
211
212
213 return rv;
214}
215
216
217
218void diag_l3_iso14230_decode(UNUSED(struct diag_l3_conn *d_l3_conn),
219 struct diag_msg *msg, char *buf, size_t bufsize) {
220 if (msg->data[0] & 0x40) {
221 snprintf(buf, bufsize, "ISO14230 response ");
222 } else {
223 snprintf(buf, bufsize, "ISO14230 request ");
224 }
225
226 return;
227}
228
229
230/*
231 * Table of english descriptions of the ISO14230 SIDs
232 */
233static const struct {
234 const int id;
235 const char *service;
236} sids[] = {
237 {DIAG_KW2K_SI_STADS, "startDiagnosticSession"},
238 {DIAG_KW2K_SI_ER, "ecuReset"},
239 {DIAG_KW2K_SI_RDFFD, "readFreezeFrameData"},
240 {DIAG_KW2K_SI_RDTC, "readDiagnosticTroubleCodes"},
241 {DIAG_KW2K_SI_CDI, "clearDiagnosticInformation"},
242 {DIAG_KW2K_SI_RDSODTC, "readStatusOfDiagnosticTroubleCodes"},
243 {DIAG_KW2K_SI_RDTCBS, "readDiagnosticTroubleCodesByStatus"},
244 {DIAG_KW2K_SI_REID, "readEcuId"},
245 {DIAG_KW2K_SI_STODS, "stopDiagnosticSession"},
246 {DIAG_KW2K_SI_RDDBLI, "readDataByLocalId"},
247 {DIAG_KW2K_SI_RDDBCI, "readDataByCommonId"},
248 {DIAG_KW2K_SI_RDMBA, "readMemoryByAddress"},
249 {DIAG_KW2K_SI_SRDT, "stopRepeatedDataTransmission"},
250 {DIAG_KW2K_SI_SDR, "setDataRates"},
251 {DIAG_KW2K_SI_SA, "securityAccess"},
252 {DIAG_KW2K_SI_DDLI, "dynamicallyDefineLocalId"},
253 {DIAG_KW2K_SI_WRDBCI, "writeDataByCommonId"},
254 {DIAG_KW2K_SI_IOCBCI, "inputOutputControlByCommonId"},
255 {DIAG_KW2K_SI_IOCBLI, "inputOutputControlByLocalId"},
256 {DIAG_KW2K_SI_STARBLI, "startRoutineByLocalID"},
257 {DIAG_KW2K_SI_STORBLI, "stopRoutineByLocalID"},
258 {DIAG_KW2K_SI_RRRBLI, "requestRoutineResultsByLocalId"},
259 {DIAG_KW2K_SI_RD, "requestDownload"},
260 {DIAG_KW2K_SI_RU, "requestUpload"},
261 {DIAG_KW2K_SI_TD, "transfer data"},
262 {DIAG_KW2K_SI_RTE, "request transfer exit"},
263 {DIAG_KW2K_SI_STARBA, "startRoutineByAddress"},
264 {DIAG_KW2K_SI_STORBA, "stopRoutineByAddress"},
265 {DIAG_KW2K_SI_RRRBA, "requestRoutineResultsByAddress"},
266 {DIAG_KW2K_SI_WRDBLI, "writeDataByLocalId"},
267 {DIAG_KW2K_SI_WRMBA, "writeMemoryByAddress"},
268 {DIAG_KW2K_SI_TP, "testerPresent"},
269 {DIAG_KW2K_SI_ESC, "EscCode"},
270 {DIAG_KW2K_SI_SCR, "startCommunication"},
271 {DIAG_KW2K_SI_SPR, "stopCommunication"},
272 {DIAG_KW2K_SI_ATP, "accessTimingParameters"},
273};
274
275static const char *l3_iso14230_sidlookup(const int id) {
276 unsigned i;
277 for (i = 0; i < ARRAY_SIZE(sids); i++) {
278 if (sids[i].id == id) {
279 return sids[i].service;
280 }
281 }
282
283 return "Unknown SID";
284}
285
286
287/*
288 * Table of english descriptions of the ISO14230 NegResponse codes
289 */
290static const struct {
291 const int id;
292 const char *response;
293} negresps[] = {
294 {DIAG_KW2K_RC_GR, "generalReject"},
295 {DIAG_KW2K_RC_SNS, "serviceNotSupported"},
296 {DIAG_KW2K_RC_SFNS_IF, "subFunctionNotSupported-Invalid Format"},
297 {DIAG_KW2K_RC_B_RR, "busy-repeatRequest"},
298 {DIAG_KW2K_RC_CNCORSE, "conditionsNoteCorrectOrRequestSequenceError"},
299 {DIAG_KW2K_RC_RNC, "routineNotCompleteOrServiceInProgress"},
300 {DIAG_KW2K_RC_ROOT, "requestOutOfRange"},
301 {DIAG_KW2K_RC_SAD_SAR, "securityAccessDenied-securityAccessRequested"},
302 {DIAG_KW2K_RC_IK, "invalidKey"},
303 {DIAG_KW2K_RC_ENOA, "exceedNumberOfAttempts"},
304 {DIAG_KW2K_RC_RTDNE, "requiredTimeDelayNotExpired"},
305 {DIAG_KW2K_RC_DNA, "downloadNotAccepted"},
306 {DIAG_KW2K_RC_IDT, "improperDownloadType"},
307 {DIAG_KW2K_RC_CNDTSA, "canNotDownloadToSpecifiedAddress"},
308 {DIAG_KW2K_RC_CNDNOBR, "canNotDownloadNumberOfBytesRequested"},
309 {DIAG_KW2K_RC_UNA, "uploadNotAccepted"},
310 {DIAG_KW2K_RC_IUT, "improperUploadType"},
311 {DIAG_KW2K_RC_CNUFSA, "canNotUploadFromSpecifiedAddress"},
312 {DIAG_KW2K_RC_CNUNOBR, "canNotUploadNumberOfBytesRequested"},
313 {DIAG_KW2K_RC_TS, "transferSuspended"},
314 {DIAG_KW2K_RC_TA, "transferAborted"},
315 {DIAG_KW2K_RC_IAIBT, "illegalAddressInBlockTransfer"},
316 {DIAG_KW2K_RC_IBCIBT, "illegalByteCountInBlockTransfer"},
317 {DIAG_KW2K_RC_IBTT, "illegalBlockTrasnferType"},
318 {DIAG_KW2K_RC_BTCDE, "blockTransferDataChecksumError"},
319 {DIAG_KW2K_RC_RCR_RP, "requestCorrectyRcvd-RspPending"},
320 {DIAG_KW2K_RC_IBCDBT, "incorrectByteCountDuringBlockTransfer"},
321 {DIAG_KW2K_RC_SNSIADS, "serviceNotSupportedInActiveDiagnosticMode//Mfg-Specific"},
322 {0, NULL},
323};
324
325static const char *l3_iso14230_neglookup(const int id) {
326 unsigned i;
327 static char unk_resp[RESP_MAXLEN];
328 for (i = 0; i < ARRAY_SIZE(negresps); i++) {
329 if (negresps[i].id == id) {
330 return negresps[i].response;
331 }
332 }
333
334 snprintf(unk_resp, sizeof(unk_resp) - 1, "Unknown Response code 0x%02X", id & 0xFF);
335 unk_resp[RESP_MAXLEN - 1] = 0;
336 return unk_resp;
337}
338
339
340const struct diag_l3_proto diag_l3_iso14230 = {
341 "ISO14230",
342 diag_l3_base_start,
343 diag_l3_base_stop,
344 diag_l3_iso14230_send,
345 diag_l3_iso14230_recv,
346 NULL, //ioctl
347 diag_l3_base_request,
348 diag_l3_iso14230_decode,
349 NULL //timer
350};
351