BOROSOFTWAREAll work →
scantool/scantool_diag.c 508 lines
1 finding in this fileB14L185
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 *
24 * Mostly ODBII Compliant Scan Tool (as defined in SAE J1978)
25 *
26 * CLI routines - diag subcommand
27 *
28 * This is extended stuff for playing with ECUs, allowing you to
29 * start a L2 connection to an ECU, add a L3 connection etc
30 *
31 */
32
33#include <stdint.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38#include "diag.h"
39#include "diag_l0.h"
40#include "diag_l1.h"
41#include "diag_l2.h"
42#include "diag_l3.h"
43#include "diag_err.h"
44
45#include "libcli.h"
46
47#include "scantool.h"
48#include "scantool_cli.h"
49
50
51static enum cli_retval cmd_diag_help(int argc, char **argv);
52
53enum cli_retval cmd_diag_disconnect(int argc, char **argv);
54static enum cli_retval cmd_diag_connect(int argc, char **argv);
55static enum cli_retval cmd_diag_sendreq(int argc, char **argv);
56static enum cli_retval cmd_diag_read(int argc, char **argv);
57
58static enum cli_retval cmd_diag_addl3(int argc, char **argv);
59static enum cli_retval cmd_diag_reml3(UNUSED(int argc), UNUSED(char **argv));
60
61static enum cli_retval cmd_diag_probe(int argc, char **argv);
62static enum cli_retval cmd_diag_fastprobe(int argc, char **argv);
63
64const struct cmd_tbl_entry diag_cmd_table[] = {
65 { "help", "help [command]", "Gives help for a command",
66 cmd_diag_help, 0, NULL},
67 { "?", "? [command]", "Gives help for a command",
68 cmd_diag_help, CLI_CMD_HIDDEN, NULL},
69
70 { "connect", "connect", "Connect to ECU", cmd_diag_connect, 0, NULL},
71
72 { "disconnect", "disconnect", "Disconnect from ECU", cmd_diag_disconnect,
73 0, NULL},
74
75 { "sendreq", "sendreq [byte0 [byte1 [...]]]", "Send raw data to the ECU and print response",
76 cmd_diag_sendreq, 0, NULL},
77 { "sr", "sendreq [byte0 [byte1 [...]]]", "Send a command to the ECU and print response",
78 cmd_diag_sendreq, CLI_CMD_HIDDEN, NULL},
79 { "read", "read [waittime]",
80 "Receive some data from the ECU waiting waittime seconds",
81 cmd_diag_read, 0, NULL},
82 { "rx", "read [waittime]", "Receive some data from the ECU",
83 cmd_diag_read, CLI_CMD_HIDDEN, NULL},
84
85 { "addl3", "addl3 [protocol]", "Add (start) a L3 protocol",
86 cmd_diag_addl3, 0, NULL},
87 { "reml3", "reml3", "Remove (stop) an L3 protocol",
88 cmd_diag_reml3, 0, NULL},
89
90 { "probe", "probe start_addr [stop_addr]", "Scan bus using ISO9141 5 baud init [slow!]", cmd_diag_probe, 0, NULL},
91 { "fastprobe", "fastprobe start_addr [stop_addr [func]]", "Scan bus using ISO14230 fast init with physical or functional addressing", cmd_diag_fastprobe, 0, NULL},
92 CLI_TBL_BUILTINS,
93 CLI_TBL_END
94};
95
96static enum cli_retval cmd_diag_help(int argc, char **argv) {
97 return cli_help_basic(argc, argv, diag_cmd_table);
98}
99
100static enum cli_retval cmd_diag_addl3(int argc, char **argv) {
101 int i;
102 const char *proto;
103
104 if (argc != 2) {
105 return CMD_USAGE;
106 }
107
108 if (strcmp(argv[1], "?") == 0) {
109 printf("Valid protocols are: ");
110 for (i=0; diag_l3_protocols[i] != NULL; i++) {
111 printf("%s ", diag_l3_protocols[i]->proto_name);
112 }
113 printf("\n");
114 return CMD_USAGE;
115 }
116
117 /* Add a L3 stack above the open L2 */
118 if (global_state < STATE_CONNECTED) {
119 printf("Not connected to ECU\n");
120 return CMD_FAILED;
121 }
122
123 if (global_state >= STATE_L3ADDED) {
124 printf("L3 protocol already connected\n");
125 return CMD_OK;
126 }
127
128 if (global_l3_conn != NULL) {
129 fprintf(stderr, FLFMT "Oops : there's a global L3 conn with an invalid global_state ! Report this !\n", FL);
130 return CMD_FAILED;
131 }
132
133 //match specified L3proto with available protos
134 for (i=0, proto = NULL; diag_l3_protocols[i] != NULL; i++) {
135 if (strcasecmp(diag_l3_protocols[i]->proto_name, argv[1]) == 0) {
136 proto = diag_l3_protocols[i]->proto_name;
137 break;
138 }
139 }
140
141 if (proto == NULL) {
142 printf("No such protocol, use %s ? for list of protocols\n",
143 argv[0]);
144 return CMD_OK;
145 }
146
147 //use the global L2 connection to start an L3 connection.
148 global_l3_conn = diag_l3_start(proto, global_l2_conn);
149
150 if (global_l3_conn !=NULL) {
151 global_state = STATE_L3ADDED;
152 printf("Done\n");
153 } else {
154 printf("Failed to add L3 protocol\n");
155 }
156
157
158 return CMD_OK;
159}
160
161// cmd_diag_reml3 : undoes what diag_addl3 did.
162static enum cli_retval cmd_diag_reml3(UNUSED(int argc), UNUSED(char **argv)) {
163 int rv;
164 struct diag_l3_conn *old_dl3c = global_l3_conn;
165
166 if (global_l3_conn == NULL) {
167 printf("No active global L3 connection.\n");
168 return CMD_OK;
169 }
170
171 if (global_state < STATE_L3ADDED) {
172 printf("Global state wasn't set properly ? Report this !\n");
173 return CMD_FAILED;
174 }
175
176 global_l3_conn = global_l3_conn->next; //in case there was more than 1
177
178 rv=diag_l3_stop(old_dl3c);
179
180 if (global_l3_conn == NULL) {
181 global_state = STATE_CONNECTED; // we probably still have an L2
182 // hanging there
183 }
184
185 return rv? diag_ifwderr(rv):0;
186}
187
188
189//cmd_diag_prob_common [startaddr] [stopaddr]
190//This should stop searching at the first succesful init
191//and update the global connection
192static enum cli_retval cmd_diag_probe_common(int argc, char **argv, int fastflag) {
193 unsigned int start, end, i;
194 int rv;
195 struct diag_l0_device *dl0d = global_dl0d;
196 struct diag_l2_conn *d_conn;
197 uint32_t funcmode = 0;
198
199 if (argc < 2) {
200 return CMD_USAGE;
201 }
202 if (strcmp(argv[1], "?") == 0) {
203 return CMD_USAGE;
204 }
205
206 if (global_state != STATE_IDLE) {
207 printf("Cannot probe while there is an active global connection.\n");
208 return CMD_FAILED;
209 }
210
211 if (!dl0d) {
212 printf("No global L0. Please select + configure L0 first\n");
213 return CMD_FAILED;
214 }
215
216 start = htoi(argv[1]);
217
218 if (argc == 2) {
219 end = start;
220 } else {
221 end = htoi(argv[2]);
222 }
223
224
225 if (fastflag && argc>=4) {
226 if (strcasecmp(argv[3], "func") == 0) {
227 funcmode = DIAG_L2_TYPE_FUNCADDR;
228 }
229 }
230
231 if ((start > 255) || (end > 255)) {
232 printf("Values must be between 0 and 255\n");
233 return CMD_OK;
234 }
235 if (end < start) {
236 printf("Start must not be greater than End address\n");
237 return CMD_OK;
238 }
239
240 /* Open interface using hardware type ISO9141 */
241 rv = diag_l2_open(dl0d, DIAG_L1_ISO9141);
242 if (rv) {
243 printf("Failed to open hardware interface, error 0x%X",rv);
244 if (rv == DIAG_ERR_PROTO_NOTSUPP) {
245 printf(", does not support requested L1 protocol\n");
246 } else if (rv == DIAG_ERR_BADIFADAPTER) {
247 printf(", adapter probably not connected\n");
248 } else {
249 printf("\n");
250 }
251 return CMD_FAILED;
252 }
253
254 printf("Scanning:\n");
255 for (i=start; i<=end; i++) {
256 printf("\t0x%X ", i);
257 fflush(stdout);
258
259 if (fastflag) {
260 d_conn = diag_l2_StartCommunications(dl0d,
261 DIAG_L2_PROT_ISO14230,
262 DIAG_L2_TYPE_FASTINIT | funcmode,
263 global_cfg.speed, (target_type) i, global_cfg.src);
264 } else {
265 d_conn = diag_l2_StartCommunications(
266 dl0d, DIAG_L2_PROT_ISO9141,
267 DIAG_L2_TYPE_SLOWINIT, global_cfg.speed,
268 (target_type)i, global_cfg.src);
269 }
270
271 if (d_conn == NULL) {
272 continue;
273 }
274
275 int gotsome;
276 struct diag_l2_data d;
277
278 printf(" connected !!\n");
279 fflush(stdout);
280
281 global_state = STATE_CONNECTED;
282 global_l2_conn = d_conn;
283
284 /* Get the keybytes */
285 diag_l2_ioctl(d_conn, DIAG_IOCTL_GET_L2_DATA, &d);
286 if (fastflag) {
287 printf("Keybytes: 0x%X 0x%X\n", d.kb1, d.kb2);
288 } else {
289 printf("received: 0x%X 0x%X\n", d.kb1, d.kb2);
290 }
291
292 /* Now read some data */
293
294 rv = 0; gotsome = 0;
295 while (rv >= 0) {
296 rv = diag_l2_recv(d_conn, 100, l2raw_data_rcv, NULL);
297 if (rv > 0) {
298 gotsome = 1;
299 }
300 }
301 if (gotsome) {
302 printf("\n");
303 } else if (rv != DIAG_ERR_TIMEOUT) {
304 printf("- read failed %d\n", rv);
305 }
306
307 return CMD_OK;
308 } //for addresses
309 //Failed => clean up
310 diag_l2_close(dl0d);
311 printf("\n");
312 return CMD_OK;
313}
314
315static enum cli_retval cmd_diag_probe(int argc, char **argv) {
316 return cmd_diag_probe_common(argc, argv, 0);
317}
318
319static enum cli_retval cmd_diag_fastprobe(int argc, char **argv) {
320 return cmd_diag_probe_common(argc, argv, 1);
321}
322
323
324/*
325 * Generic init, using parameters set by user.
326 * Currently only called from cmd_diag_connect;
327 */
328static int do_l2_generic_start(void) {
329 struct diag_l2_conn *d_conn;
330 struct diag_l0_device *dl0d = global_dl0d;
331 int rv;
332 flag_type flags = 0;
333
334 if (!dl0d) {
335 printf("No global L0. Please select + configure L0 first\n");
336 return diag_iseterr(DIAG_ERR_GENERAL);
337 }
338
339 /* Open interface using current L1 proto and hardware */
340 rv = diag_l2_open(dl0d, global_cfg.L1proto);
341 if (rv) {
342 fprintf(stderr, "l2_generic_start: open failed for protocol %d on %s\n",
343 global_cfg.L1proto, dl0d->dl0->shortname);
344 return diag_ifwderr(rv);
345 }
346
347 if (global_cfg.addrtype) {
348 flags = DIAG_L2_TYPE_FUNCADDR;
349 } else {
350 flags = 0;
351 }
352
353 flags |= (global_cfg.initmode & DIAG_L2_TYPE_INITMASK);
354
355 d_conn = diag_l2_StartCommunications(dl0d, global_cfg.L2proto,
356 flags, global_cfg.speed, global_cfg.tgt, global_cfg.src);
357
358 if (d_conn == NULL) {
359 rv=diag_geterr();
360 diag_l2_close(dl0d);
361 return diag_iseterr(rv);
362 }
363
364 /* Connected ! */
365
366 global_l2_conn = d_conn;
367
368 return 0;
369}
370
371
372
373//cmd_diag_connect : attempt to connect to ECU
374//using the current global l2proto, l1proto, etc.
375static enum cli_retval cmd_diag_connect(UNUSED(int argc), UNUSED(char **argv)) {
376 int rv;
377
378 if (argc > 1) {
379 return CMD_USAGE;
380 }
381
382 if (global_state >= STATE_CONNECTED) {
383 printf("Already connected !\n");
384 return CMD_OK;
385 }
386
387 rv = do_l2_generic_start();
388 if (rv==0) {
389 printf("Connection to ECU established!\n");
390 global_state = STATE_CONNECTED;
391 } else {
392 printf("\nConnection to ECU failed\n");
393 printf("Please check :\n");
394 printf("\tAdapter is connected to PC\n");
395 printf("\tCable is connected to Vehicle\n");
396 printf("\tVehicle is switched on\n");
397 }
398 return CMD_OK;
399}
400
401
402//Currently, this stops + removes the current global L3 conn.
403//If there are no more L3 conns, also stop + close the global L2 conn.
404enum cli_retval cmd_diag_disconnect(UNUSED(int argc), UNUSED(char **argv)) {
405 if (argc > 1) {
406 return CMD_USAGE;
407 }
408
409 if (global_state < STATE_CONNECTED) {
410 return CMD_OK;
411 }
412
413 if (global_state >= STATE_L3ADDED) {
414 /* Close L3 protocol */
415 cmd_diag_reml3(0,NULL);
416 }
417
418 if (global_l3_conn == NULL) {
419 // no other l3 conns, so stop the global L2 conn
420 diag_l2_StopCommunications(global_l2_conn);
421 diag_l2_close(global_dl0d);
422
423 global_l2_conn = NULL;
424 global_state = STATE_IDLE;
425 } else {
426 printf("There is another active L3 connection : %p\n : %s",
427 (void *) global_l3_conn, global_l3_conn->d_l3_proto->proto_name);
428 printf("Run disconnect again to close it.\n");
429 return CMD_OK;
430 }
431
432 return CMD_OK;
433}
434
435
436static enum cli_retval cmd_diag_read(int argc, char **argv) {
437 unsigned int timeout = 0;
438
439 if (global_state < STATE_CONNECTED) {
440 printf("Not connected to ECU\n");
441 return CMD_OK;
442 }
443
444 if (argc > 1) {
445 timeout = (unsigned int)atoi(argv[1]) * 1000;
446 }
447
448 if (global_state < STATE_L3ADDED) {
449 /* No L3 protocol, do L2 stuff */
450 (void)diag_l2_recv(global_l2_conn, timeout, l2raw_data_rcv,
451 NULL);
452
453 } else {
454 (void)diag_l3_recv(global_l3_conn, timeout, j1979_data_rcv,
455 (void *)&_RQST_HANDLE_WATCH);
456 }
457 return CMD_OK;
458}
459
460/*
461 * Send some data, and wait for a response
462 */
463static enum cli_retval cmd_diag_sendreq(int argc, char **argv) {
464 uint8_t data[MAXRBUF];
465 unsigned int i,j,len;
466 int rv;
467
468 if (argc < 2) {
469 printf("Too few arguments\n");
470 return CMD_USAGE;
471 }
472
473 if (strcmp(argv[1], "?") == 0) {
474 return CMD_USAGE;
475 }
476
477 if (global_state < STATE_CONNECTED) {
478 printf("Not connected to ECU\n");
479 return CMD_OK;
480 }
481
482 memset(data, 0, sizeof(data));
483
484 for (i=1, j=0; (i < (unsigned int) argc) && (i < sizeof(data)); i++, j++) {
485 data[j] = (uint8_t) htoi(argv[i]);
486 }
487 len = j;
488
489
490 if (global_state < STATE_L3ADDED) {
491 rv = l2_do_send( global_l2_conn, data, len,
492 (void *)&_RQST_HANDLE_DECODE);
493 } else {
494 /* Send data with handle to tell callback to print results */
495 rv = l3_do_send( global_l3_conn, data, len,
496 (void *)&_RQST_HANDLE_DECODE);
497 }
498
499 if (rv != 0) {
500 if (rv == DIAG_ERR_TIMEOUT) {
501 printf("No data received\n");
502 } else {
503 printf("sendreq: failed error %d\n", rv);
504 }
505 }
506 return CMD_OK;
507}
508