📄 scantool_cli.c
字号:
/* * freediag - Vehicle Diagnostic Utility * * * Copyright (C) 2001 Richard Almeida & Ibex Ltd (rpa@ibex.co.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ************************************************************************* * * * Mostly ODBII Compliant Scan Tool (as defined in SAE J1978) * * CLI routines * */#include <config.h>#include "diag_os.h" /* operating specific includes */#include "scantool.h"#include <time.h>#include <sys/stat.h>#include "scantool_cli.h"static char *cvsid = "$Id: scantool_cli.c,v 1.24 2002/09/11 19:59:02 rpalmeida Exp $";char *progname;FILE *global_logfp; /* Monitor log output file pointer */#define LOG_FORMAT "FREEDIAG log format 0.2"FILE *instream;/* ROOT main menu *//* Sub menus */extern struct cmd_tbl_entry set_cmd_table[];extern struct cmd_tbl_entry debug_cmd_table[];extern struct cmd_tbl_entry test_cmd_table[];extern struct cmd_tbl_entry diag_cmd_table[];extern struct cmd_tbl_entry vag_cmd_table[];/* Main menu commands */int cmd_help(int argc, char **argv);int cmd_exit(int argc, char **argv);int cmd_monitor(int argc, char **argv);int cmd_watch(int argc, char **argv);int cmd_cleardtc(int argc, char **argv);int cmd_ecus(int argc, char **argv);int cmd_log(int argc, char **argv);int cmd_stoplog(int argc, char **argv);int cmd_play(int argc, char **argv);int cmd_dumpdata(int argc, char **argv);int cmd_scan(int argc, char **argv);int cmd_date(int argc, char **argv);int cmd_rem(int argc, char **argv);int cmd_source(int argc, char **argv);struct cmd_tbl_entry root_cmd_table[] ={ { "scan", "scan", "Start SCAN process", cmd_scan, 0, NULL}, { "monitor", "monitor [english/metric]", "Continuously monitor rpm etc", cmd_monitor, 0, NULL}, { "log", "log <filename>", "Log monitor data to <filename>", cmd_log, 0, NULL}, { "stoplog", "stoplog", "Stop logging", cmd_stoplog, 0, NULL},#if notdef { "play", "play filename", "Play back data from <filename>", cmd_play, FLAG_HIDDEN, NULL},#endif { "cleardtc", "cleardtc", "Clear DTCs from ECU", cmd_cleardtc, 0, NULL}, { "ecus", "ecus", "Show ECU information", cmd_ecus, 0, NULL}, { "watch", "watch [raw/nodecode/nol3]", "Watch the diagnostic bus and, if not in raw/nol3 mode, decode data", cmd_watch, 0, NULL}, { "set", "set <parameter value>", "Sets/displays parameters, \"set help\" for more info", NULL, 0, set_cmd_table}, { "test", "test <command [params]>", "Perform various tests, \"test help\" for more info", NULL, 0, test_cmd_table}, { "diag", "diag <command [params]>", "Extended diagnostic functions, \"diag help\" for more info", NULL, 0, diag_cmd_table}, { "vw", "vw <command [params]", "VW diagnostic protocol functions, \"vw help\" for more info", NULL, 0, vag_cmd_table}, { "debug", "debug [parameter = value]", "Sets/displays debug stuff, \"debug help\" for more info", NULL, 0, debug_cmd_table}, { "date", "date", "Prints date & time", cmd_date, FLAG_HIDDEN, NULL}, { "#", "#", "Does nothing", cmd_rem, FLAG_HIDDEN, NULL}, { "source", "source <file>", "Read commands from a file", cmd_source, 0, NULL}, { "help", "help [command]", "Gives help for a command", cmd_help, 0, NULL }, { "quit", "quit", "Exits program", cmd_exit, 0, NULL}, { "exit", "exit", "Exits program", cmd_exit, FLAG_HIDDEN, NULL}, { NULL, NULL, NULL, NULL, 0, NULL}};#define INPUT_MAX 1024/* * Caller must free returned buffer. Used if we don't * have readline, and when reading init or command files. * No line editing or history. */static char *basic_get_input(char *prompt){ char *input; input = malloc(INPUT_MAX); if (!input) return NULL; while (1) { if (prompt) { printf("%s", prompt); fflush(stdout); } if (fgets(input, INPUT_MAX, instream)) break; else { if (feof(instream)) { free(input); return NULL; } else /* Ignore error and try again */ clearerr(instream); } } input[strlen(input)-1] = '\0'; /* Remove trailing CR */ return input;}#if HAVE_LIBREADLINE#include <readline/readline.h>#include <readline/history.h>/* Caller must free returned buffer */static char *get_input(char *prompt){ char *input; input = readline(prompt); if (input && *input) add_history(input); return input;}static voidreadline_init(void){ /* * Could do fancy command completion someday, but for * now, at least disable the default filename completion. */ rl_bind_key('\t', rl_insert);}#elsestatic char *get_input(char *prompt){ return basic_get_input(prompt);}static void readline_init(void) {}#endifstatic char *command_line_input(char *prompt){ if (instream == stdin) return get_input(prompt); /* Reading from init or command file; no prompting or history */ return basic_get_input(NULL);}intcmd_exit(int argc, char **argv){ return (CMD_EXIT);}int help_common(int argc, char **argv, struct cmd_tbl_entry *cmd_table){/* int i;*/ struct cmd_tbl_entry *ctp; if (argc > 1) { /* Single command help */ int found = 0; ctp = cmd_table; while (ctp->command) { if (strcasecmp(ctp->command, argv[1]) == 0) { printf("%s: %s\n", ctp->command, ctp->help); printf("Usage: %s\n", ctp->usage); found++; break; } ctp++; } if (!found) { printf("help: %s: no such command\n", argv[1]); } } else { /* Print help */ printf("Available commands are :-\n"); ctp = cmd_table; while (ctp->command) { if ((ctp->flags & FLAG_HIDDEN) == 0) printf(" %s\n", ctp->usage); ctp++; } printf("\nTry \"help <command>\" for further help\n"); } return (CMD_OK);}intcmd_help(int argc, char **argv){ help_common(argc, argv, root_cmd_table); return (CMD_OK);}intcmd_date(int argc, char **argv){ struct tm *tm; time_t now; now = time(NULL); tm = localtime(&now); printf("%s", asctime(tm)); return (CMD_OK);}intcmd_rem(int argc, char **argv){ return (CMD_OK);}struct timeval log_start;static voidlog_timestamp(char *prefix){ struct timeval tv; long sec, usec; gettimeofday(&tv, NULL); if (tv.tv_usec < log_start.tv_usec) { tv.tv_usec += 1000*1000; tv.tv_sec--; } sec = tv.tv_sec - log_start.tv_sec; usec = tv.tv_usec - log_start.tv_usec; fprintf(global_logfp, "%s %04d.%03d ", prefix, sec, usec / 1000);}static voidlog_command(int argc, char **argv){ int i; if (!global_logfp) return; log_timestamp(">"); for (i = 0; i < argc; i++) fprintf(global_logfp, " %s", argv[i]); fprintf(global_logfp, "\n");}intcmd_log(int argc, char **argv){ char *file; struct stat buf; time_t now; int i; if (global_logfp != NULL) { printf("Already logging\n"); return(CMD_FAILED); } /* Turn on logging */ if (argc > 1) file = argv[1]; else { file = malloc(20); if (!file) { printf("Can't allocate space for filename\n"); return(CMD_FAILED); } for (i = 0; i < 99; i++) { sprintf(file, "log.%02d", i); if (stat(file, &buf) == -1 && errno == ENOENT) break; } if (i > 99) { printf("Can't create log.<nn>\n"); free(file); return(CMD_FAILED); } } global_logfp = fopen(file, "w"); if (global_logfp == NULL) { printf("Failed to create log file %s\n", file); free(file); return(CMD_FAILED); } now = time(NULL); gettimeofday(&log_start, NULL); fprintf(global_logfp, "%s\n", LOG_FORMAT); log_timestamp("#"); fprintf(global_logfp, "logging started at %s", asctime(localtime(&now))); printf("Logging to file %s\n", file); free(file); return (CMD_OK);}intcmd_stoplog(int argc, char **argv){ /* Turn off logging */ if (global_logfp == NULL) { printf("Logging was not on\n"); return(CMD_FAILED); } fclose(global_logfp); global_logfp = NULL; return (CMD_OK);}intcmd_play(int argc, char **argv){ FILE *fp; int linenr; /* Turn on logging for monitor mode */ if (argc < 2) return(CMD_USAGE); fp = fopen(argv[1], "r"); if (fp == NULL) { printf("Failed to open log file %s\n", argv[1]); return(CMD_FAILED); } linenr = 0; /* Read data file in */ /* XXX logging */ /* Loop and call display routines */ while (1) { int ch; printf("DATE: +/- to step, S/E to goto start or end, Q to quit\n"); ch = getc(stdin); switch (ch) { case '-': case '+': case 'E': case 'e': case 'S': case 's': case 'Q': case 'q': break; } } fclose(fp); return (CMD_OK);}intcmd_watch(int argc, char **argv){ int rv; diag_l2_conn_t *d_l2_conn; diag_l3_conn_t *d_l3_conn; int fd; int rawmode = 0; int nodecode = 0; int nol3 = 0; if (argc > 1) { if (strcasecmp(argv[1], "raw") == 0) rawmode = 1; else if (strcasecmp(argv[1], "nodecode") == 0) nodecode = 1; else if (strcasecmp(argv[1], "nol3") == 0) nol3 = 1; else { printf("Don't understand \"%s\"\n", argv[1]); return(CMD_USAGE); } } rv = diag_init(); if (rv != 0) { fprintf(stderr, "diag_init failed\n"); return(-1); } fd = diag_l2_open(set_interface, set_subinterface, set_L1protocol); if (fd < 0) { printf("Failed to open hardware interface "); if (fd == DIAG_ERR_PROTO_NOTSUPP) printf(", does not support requested L1 protocol\n"); else if (fd == DIAG_ERR_BADIFADAPTER) printf(", adapter probably not connected\n"); else printf("\n"); return(CMD_FAILED); } if (rawmode) d_l2_conn = diag_l2_StartCommunications(fd, DIAG_L2_PROT_RAW, 0, set_speed, set_destaddr, set_testerid); else d_l2_conn = diag_l2_StartCommunications(fd, set_L2protocol, DIAG_L2_TYPE_MONINIT, set_speed, set_destaddr, set_testerid); if (d_l2_conn == 0) { printf("Failed to connect to hardware in monitor mode\n"); return(CMD_FAILED); } if (rawmode == 0) { /* Put the SAE J1979 stack on top of the ISO device */ if (nol3 == 0) { d_l3_conn = diag_l3_start("SAEJ1979", d_l2_conn); if (d_l3_conn == NULL) { printf("Failed to enable SAEJ1979 mode\n"); return(CMD_FAILED); } } else d_l3_conn = NULL; printf("Waiting for data to be received\n"); while (1) { if (d_l3_conn) rv = diag_l3_recv(d_l3_conn, 10000, j1979_watch_rcv, (nodecode) ? NULL:(void *)d_l3_conn); else rv = diag_l2_recv(d_l2_conn, 10000, j1979_watch_rcv, NULL); if (rv == 0) continue; if (rv == DIAG_ERR_TIMEOUT) continue; } } else { /* * And just read stuff, callback routine will print out the data */ printf("Waiting for data to be received\n"); while (1) { rv = diag_l2_recv(d_l2_conn, 10000, j1979_data_rcv, (void *)RQST_HANDLE_WATCH); if (rv == 0) continue; if (rv == DIAG_ERR_TIMEOUT) continue; printf("recv returns %d\n", rv); break; } } return(CMD_OK);}struct pid;typedef void (formatter)(char *, int, struct pid *, response_t *, int);#define DATA_VALID(p, d) (d[p->pid].type == TYPE_GOOD)#define DATA_1(p, n, d) (d[p->pid].data[n])#define DATA_2(p, n, d) (DATA_1(p, n, d) * 256 + DATA_1(p, n+1, d))#define DATA_RAW(p, n, d) (p->bytes == 1 ? DATA_1(p, n, d) : \ DATA_2(p, n, d))#define DATA_SCALED(p, v) (v * p->scale1 + p->offset1)#define DATA_ENGLISH(p, v) (v * p->scale2 + p->offset2)struct pid { int pid; char *desc; formatter *sprintf; int bytes; char *fmt1; // SI double scale1; double offset1; char *fmt2; // English (typically) double scale2; double offset2;};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -