// diag_tty_break #1 : use Set / ClearCommBreak // and return as soon as break is cleared. // ret 0 if ok int diag_tty_break(struct diag_l0_device *dl0d, const unsigned int ms) { LARGE_INTEGER qpc1, qpc2; //for timing verification long real_t; //"real" duration struct tty_int *wti = (struct tty_int *)dl0d->tty_int; int errval=0; if (wti->fd == INVALID_HANDLE_VALUE) { fprintf(stderr, FLFMT "Error. Is the port open ?\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } if (ms <= 1) return diag_iseterr(DIAG_ERR_GENERAL); QueryPerformanceCounter(&qpc1); errval = !SetCommBreak(wti->fd); QueryPerformanceCounter(&qpc2); //that call can take quite a while (6ms !!) on some setups (win7 + CH340 USB-Serial). //It's still impossible to know (from here) when exactly TXD goes low (beginning or end of the call) real_t=(long) (pf_conv * (qpc2.QuadPart-qpc1.QuadPart)) / 1000L; real_t = (long) ms - real_t; //time remaining if (real_t <= 0) real_t = 0; diag_os_millisleep((unsigned int ) real_t); errval |= !ClearCommBreak(wti->fd); if (errval) { //if either of the calls failed fprintf(stderr, FLFMT "tty_break could not set/clear break!\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } return 0; }
/* * Routine to read a whole BR1 message * length of which depends on the first value received. * This also handles "error" messages (top bit of first value set) * * Returns length of received message, or TIMEOUT error, or BUSERROR * if the BR interface tells us theres a congested bus */ static int br_getmsg(struct diag_l0_device *dl0d, uint8_t *dp, unsigned int timeout) { uint8_t firstbyte; size_t readlen; int rv; struct br_device *dev = dl0d->l0_int; DIAG_DBGM(diag_l0_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V, FLFMT "link %p getmsg timeout %u\n", FL, (void *)dl0d, timeout); /* * First read the 1st byte, using the supplied timeout */ rv = diag_tty_read(dev->tty_int, &firstbyte, 1, timeout); if (rv != 1) { DIAG_DBGM(diag_l0_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V, FLFMT "link %p getmsg 1st byte timed out\n", FL, (void *)dl0d); return diag_ifwderr(rv); } /* * Now read data. Maximum is 15 bytes. */ readlen = firstbyte & 0x0f; /* * Reasonable timeout here as the interface told us how * much data to expect, so it should arrive */ rv = diag_tty_read(dev->tty_int, dp, readlen, 100); if (rv != (int)readlen) { fprintf(stderr, FLFMT "br_getmsg error\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } DIAG_DBGMDATA(diag_l0_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V, dp, readlen, FLFMT "link %p getmsg read ctl 0x%X data:", FL, (void *)dl0d, firstbyte & 0xff); /* * Message read complete, check error flag * Top bit set means error, Bit 6 = VPW/PWM bus * congestion (i.e retry). */ if (firstbyte & 0x80) { /* Error indicator */ return diag_iseterr(DIAG_ERR_TIMEOUT); } if (firstbyte & 0x40) { /* VPW/PWM bus conflict, need to retry */ return diag_iseterr(DIAG_ERR_BUSERROR); } if (readlen == 0) { /* Should never happen */ return diag_iseterr(DIAG_ERR_TIMEOUT); } return (int) readlen; }
/* * Safe write routine; return 0 on success */ static int diag_l0_muleng_write(struct diag_l0_device *dl0d, const void *dp, size_t txlen) { if (txlen <=0) return diag_iseterr(DIAG_ERR_BADLEN); if ( (diag_l0_debug & (DIAG_DEBUG_WRITE|DIAG_DEBUG_DATA)) == (DIAG_DEBUG_WRITE|DIAG_DEBUG_DATA) ) { fprintf(stderr, FLFMT "device link %p sending to ME device: ", FL, (void *)dl0d); diag_data_dump(stderr, dp, txlen); fprintf(stderr, "\n"); } /* * And send it to the interface */ if (diag_tty_write(dl0d, dp, txlen) != (int) txlen) { fprintf(stderr, FLFMT "muleng_write error!!\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } return 0; }
/* * Set/Clear DTR and RTS lines, as specified * on Win32 this can easily be done by calling EscapeCommFunction twice. * This takes around ~15-20us to do; probably with ~10 us skew between setting RTS and DTR. * If it proves to be a problem, it's possible to change both RTS and DTR at once by updating * the DCB and calling SetCommState. That call would take around 30-40us. * Note : passing 1 in dtr or rts means "set DTR/RTS", i.e. positive voltage. * ret 0 if ok */ int diag_tty_control(struct diag_l0_device *dl0d, unsigned int dtr, unsigned int rts) { unsigned int escapefunc; struct tty_int *wti = (struct tty_int *)dl0d->tty_int; if (wti->fd == INVALID_HANDLE_VALUE) { fprintf(stderr, FLFMT "Error. Is the port open ?\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } if (dtr) escapefunc=SETDTR; else escapefunc=CLRDTR; if (! EscapeCommFunction(wti->fd,escapefunc)) { fprintf(stderr, FLFMT "Could not change DTR: %s\n", FL, diag_os_geterr(0)); return diag_iseterr(DIAG_ERR_GENERAL); } if (rts) escapefunc=SETRTS; else escapefunc=CLRRTS; if (! EscapeCommFunction(wti->fd,escapefunc)) { fprintf(stderr, FLFMT "Could not change RTS: %s\n", FL, diag_os_geterr(0)); return diag_iseterr(DIAG_ERR_GENERAL); } return 0; } //diag_tty_control
/* * Insert the L3 layer on top of the layer 2 connection * */ static int diag_l3_vag_start(struct diag_l3_conn *d_l3_conn) { struct diag_l2_data l2data; struct diag_l2_conn *d_l2_conn; /* 5 baud init has been done, make sure we got the correct keybytes */ d_l2_conn = d_l3_conn->d_l3l2_conn; (void)diag_l2_ioctl(d_l2_conn, DIAG_IOCTL_GET_L2_DATA, (void *)&l2data); DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_INIT, DIAG_DBGLEVEL_V, FLFMT "start L3 KB 0x%X 0x%X need 0x01 0x8A\n", FL, l2data.kb1, l2data.kb2); if (l2data.kb1 != 0x01) { return diag_iseterr(DIAG_ERR_WRONGKB); } if (l2data.kb2 != 0x8A) { return diag_iseterr(DIAG_ERR_WRONGKB); } /* OK, ISO 9141 keybytes are correct ! */ /* Get the initial stuff the ECU tells us */ return 0; }
static int diag_l0_br_write(struct diag_l0_device *dl0d, const void *dp, size_t txlen) { if (txlen <=0) return diag_iseterr(DIAG_ERR_BADLEN); if (diag_tty_write(dl0d, dp, txlen) != (int) txlen) { fprintf(stderr, FLFMT "br_write error\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } return 0; }
int diag_l2_proto_raw_startcomms( struct diag_l2_conn *d_l2_conn, UNUSED(flag_type flags), unsigned int bitrate, target_type target, source_type source) { int rv; struct diag_serial_settings set; set.speed = bitrate; set.databits = diag_databits_8; set.stopbits = diag_stopbits_1; set.parflag = diag_par_n; /* Set the speed as shown */ rv=diag_l2_ioctl(d_l2_conn, DIAG_IOCTL_SETSPEED, &set); if (!rv) return diag_iseterr(DIAG_ERR_GENERAL); //set tgt and src address in d_l2_conn d_l2_conn->diag_l2_destaddr=target; d_l2_conn->diag_l2_srcaddr=source; return 0; }
static int diag_l0_br_write(struct diag_l0_device *dl0d, const void *dp, size_t txlen) { ssize_t xferd; while ((size_t)(xferd = diag_tty_write(dl0d, dp, txlen)) != txlen) { if (xferd < 0) { /* error */ if (errno != EINTR) { fprintf(stderr, FLFMT "write returned error %s.\n", FL, strerror(errno)); return diag_iseterr(DIAG_ERR_GENERAL); } xferd = 0; /* Interrupted read, nothing transferred. */ errno = 0; } /* * Successfully wrote xferd bytes (or 0 bytes if EINTR), * so increment the pointers and continue */ txlen -= (size_t) xferd; dp = (const void *)((const char *)dp + xferd); } return 0; }
/* * Send the data * * - with VAG protocol this will sleep as the message is sent as each byte * is ack'ed by the far end * * - after each byte reset the send timer or the timeout routine may try * and send something * * 1st byte of message is command, followed by data */ static int diag_l2_proto_vag_send(struct diag_l2_conn *d_l2_conn, struct diag_msg *msg) { int rv = 0; /* int i;*/ /* int csum;*/ /* int len;*/ /* uint8_t buf[MAXRBUF];*/ /* int offset;*/ //struct diag_l2_vag *dp; if (diag_l2_debug & DIAG_DEBUG_WRITE) fprintf(stderr, FLFMT "diag_l2_vag_send %p msg %p len %d called\n", FL, (void *)d_l2_conn, (void *)msg, msg->len); //dp = (struct diag_l2_vag *)d_l2_conn->diag_l2_proto_data; //not used ? #if xx rv = diag_l1_send (d_l2_conn->diag_link->diag_l2_dl0d, 0, buf, len, d_l2_conn->diag_l2_p4min); #endif return rv? diag_iseterr(rv):0 ; }
/* * Do wakeup on the bus * * We do this by noting a wakeup needs to be done for the next packet for * fastinit, and doing slowinit now */ static int diag_l0_muleng_initbus(struct diag_l0_device *dl0d, struct diag_l1_initbus_args *in) { int rv = 0; struct diag_l0_muleng_device *dev; dev = (struct diag_l0_muleng_device *)dl0d->l0_int; if (!dev) return diag_iseterr(DIAG_ERR_GENERAL); if (diag_l0_debug & DIAG_DEBUG_IOCTL) fprintf(stderr, FLFMT "device link %p info %p initbus type %d proto %d\n", FL, (void *)dl0d, (void *)dev, in->type, dev->protocol); diag_tty_iflush(dl0d); /* Empty the receive buffer, wait for idle bus */ if (in->type == DIAG_L1_INITBUS_5BAUD) rv = diag_l0_muleng_slowinit(dl0d, in, dev); else { /* Do wakeup on first TX */ dev->dev_wakeup = in->type; dev->dev_state = MULENG_STATE_FASTSTART; } return rv; }
/* * Get data (blocking, unless timeout is 0) * returns # of bytes read, or <0 if error. * XXX currently nothing handles the case of L0 returning 0 bytes read. Logically that could * only happen when requesting n bytes with a timeout of 0; otherwise DIAG_ERR_TIMEOUT will * generated. */ int diag_l1_recv(struct diag_l0_device *dl0d, const char *subinterface, void *data, size_t len, unsigned int timeout) { int rv; if (!len) { return diag_iseterr(DIAG_ERR_BADLEN); } DIAG_DBGM(diag_l1_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V, FLFMT "_recv request len=%d, timeout=%u;", FL, (int)len, timeout); if (timeout == 0) { fprintf(stderr, FLFMT "Interesting : L1 read with timeout=0. Report this !\n", FL); } rv=diag_l0_recv(dl0d, subinterface, data, len, timeout); if (!rv) { fprintf(stderr, FLFMT "L0 returns with 0 bytes; returning TIMEOUT instead. Report this !\n", FL); return DIAG_ERR_TIMEOUT; } if (rv>0) { DIAG_DBGMDATA(diag_l1_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V, data, (size_t) rv, "got %d bytes; ",rv); } return rv; }
/* * XXX All commands should probably have optional "init" hooks. */ int set_init(void) { /* Reset parameters to defaults. */ set_speed = 10400; /* Comms speed; ECUs will probably send at 10416 bps (96us per bit) */ set_testerid = 0xf1; /* Our tester ID */ set_addrtype = 1; /* Use virtual addressing */ set_destaddr = 0x33; /* Dest ECU address */ store_set_destaddr = set_destaddr; set_L1protocol = DIAG_L1_ISO9141; /* L1 protocol type */ set_L2protocol = DIAG_L2_PROT_ISO9141; /* Protocol type */ set_initmode = DIAG_L2_TYPE_FASTINIT ; set_display = 0; /* English (1), or Metric (0) */ set_vehicle = "ODBII"; /* Vehicle */ set_ecu = "ODBII"; /* ECU name */ set_interface_idx= DEFAULT_INTERFACE; set_interface = l0_names[DEFAULT_INTERFACE].code; /* Default H/w interface to use */ strncpy(set_subinterface,"/dev/null",sizeof(set_subinterface)); printf( "%s: Interface set to default: %s on %s\n", progname, l0_names[set_interface_idx].longname, set_subinterface); if (diag_calloc(&set_simfile, strlen(DB_FILE)+1)) return diag_iseterr(DIAG_ERR_GENERAL); strcpy(set_simfile, DB_FILE); //default simfile for use with CARSIM diag_l0_sim_setfile(set_simfile); return 0; }
int diag_l1_add_l0dev(const struct diag_l0 *l0dev) { int rv; struct diag_l0_node *last_node, *new_node; if (l0dev_list == NULL) { /* * No devices yet, create the root. */ if ( (rv = diag_calloc(&l0dev_list, 1)) ) return rv; l0dev_list->l0dev = l0dev; return 0; } for (last_node = l0dev_list; last_node != NULL; last_node = last_node->next) if (last_node->l0dev == l0dev) return diag_iseterr(DIAG_ERR_GENERAL); /* Already there. */ if ( (rv = diag_calloc(&new_node, 1)) ) return rv; for (last_node = l0dev_list; last_node->next != NULL; last_node = last_node->next) /* Search for the next-to-last node */; new_node->l0dev = l0dev; last_node->next = new_node; return 0; }
int diag_tty_break(struct diag_l0_device *dl0d, const int ms) { HANDLE hd; long h; /* * I'm going through this convoluted two-step conversion * to avoid compiler warnings: */ h = get_osfhandle(dl0d->fd); hd = (HANDLE)h; if (tcdrain(dl0d->fd)) { fprintf(stderr, FLFMT "tcdrain returned %s.\n", FL, strerror(errno)); return diag_iseterr(DIAG_ERR_GENERAL); } SetCommBreak(hd); diag_os_millisleep(ms); ClearCommBreak(hd); return 0; }
/* * Send a load of data * * Returns 0 on success, -1 on failure * * This routine will do a fastinit if needed, but all 5 baud inits * will have been done by the slowinit() code */ static int br_send(struct diag_l0_device *dl0d, UNUSED(const char *subinterface), const void *data, size_t len) { int rv = 0; struct br_device *dev; dev = (struct br_device *)dl0d->l0_int; if (len <= 0) { return diag_iseterr(DIAG_ERR_BADLEN); } DIAG_DBGMDATA(diag_l0_debug, DIAG_DEBUG_WRITE, DIAG_DBGLEVEL_V, data, len, FLFMT "device link %p send %ld bytes protocol %d state %d: ", FL, (void *)dl0d, (long)len, dev->protocol, dev->dev_state); /* * Special handling for fastinit, we need to collect up the * bytes of the StartComms message sent by the upper layer * when we have a whole message we can then send the request * as part of a special initialisation type */ if (dev->dev_state == BR_STATE_KWP_FASTINIT) { uint8_t outbuf[6]; if (dev->dev_txlen < 5) { memcpy(&dev->dev_txbuf[dev->dev_txlen], data, len); dev->dev_txlen += len; rv = 0; } if (dev->dev_txlen >= 5) { /* * Startcomms request is 5 bytes long - we have * 5 bytes, so now we should send the initialisation */ outbuf[0] = 0x03; memcpy(&outbuf[1], dev->dev_txbuf, 5); rv = br_writemsg(dl0d, BR_WRTYPE_INIT, outbuf, 6); /* Stays in FASTINIT state until first read */ } } else { /* * Now, keep a copy of the data, and set the framenr to 1 * This means the receive code will resend the request if it * wants to get a frame number 2 or 3 or whatever */ memcpy(dev->dev_rxbuf, data, len); dev->dev_txlen = len; dev->dev_framenr = 1; /* And now encapsulate and send the data */ rv = br_writemsg(dl0d, BR_WRTYPE_DATA, data, len); } return rv; }
//elm_bogusinit : send a 01 00 request to force ELM to init bus. //Only used to force clones to establish a connection... hack-grade because it assumes all ECUs support this. // non-OBD ECUs may not work with this. ELM clones suck... // TODO : add argument to allow either a 01 00 request (SID1 PID0, J1979) or 3E (iso14230 TesterPresent) request to force init. static int elm_bogusinit(struct diag_l0_device *dl0d, unsigned int timeout) { int rv; uint8_t buf[MAXRBUF]; uint8_t data[]={0x01,0x00}; const char *err_str; rv = diag_l0_elm_send(dl0d, NULL, data, 2); if (rv) return diag_iseterr(rv); // receive everything; we're hoping for a prompt at the end and no error message. rv=diag_tty_read(dl0d, buf, MAXRBUF-5, timeout); //rv=# bytes read if (diag_l0_debug & (DIAG_DEBUG_WRITE | DIAG_DEBUG_READ)) { fprintf(stderr, FLFMT "received %d bytes\n", FL, rv); if (diag_l0_debug & DIAG_DEBUG_DATA) { elm_parse_cr(buf, rv); fprintf(stderr, FLFMT "(got %.*s)\n", FL, rv, buf); } } if (rv<1) { //no data or error if (diag_l0_debug & DIAG_DEBUG_WRITE) { fprintf(stderr, FLFMT "ELM did not respond\n", FL); } return diag_iseterr(DIAG_ERR_GENERAL); } buf[rv]=0; //terminate string if (buf[rv-1] != '>') { //if last character isn't the input prompt, there is a problem fprintf(stderr, FLFMT "ELM not ready (no prompt received): %s\n", FL, buf); return diag_iseterr(DIAG_ERR_GENERAL); } err_str = elm_parse_errors(dl0d, buf); if (err_str != NULL) { fprintf(stderr, FLFMT "got error while forcing init: %s\n", FL, err_str); return diag_iseterr(DIAG_ERR_GENERAL); } return 0; }
// diag_tty_break #1 : use Set / ClearCommBreak // and return as soon as break is cleared. // ret 0 if ok int diag_tty_break(struct diag_l0_device *dl0d, const unsigned int ms) { LARGE_INTEGER qpc1, qpc2; //for timing verification static long correction=0; //running average offset (us) to add to the timeout long real_t; //"real" duration measured in us struct tty_int *wti = (struct tty_int *)dl0d->tty_int; int errval=0; if (wti->fd == INVALID_HANDLE_VALUE) { fprintf(stderr, FLFMT "Error. Is the port open ?\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } if ( (ms + correction/1000)<1) return diag_iseterr(DIAG_ERR_GENERAL); QueryPerformanceCounter(&qpc1); errval=!SetCommBreak(wti->fd); diag_os_millisleep(ms + correction/1000); QueryPerformanceCounter(&qpc2); errval += !ClearCommBreak(wti->fd); if (errval) { //if either of the calls failed fprintf(stderr, FLFMT "tty_break could not set/clear break!\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } real_t=(long) (pf_conv * (qpc2.QuadPart-qpc1.QuadPart)); //now verify if it's within 1ms of the requested delay. real_t = real_t - (ms*1000); if (real_t < -3000) { diag_os_millisleep((unsigned int)(real_t / -1000)); } else if ((real_t > -1000) && (real_t < 1000)) { //good enough: return 0; } //we're here if we were off by more than -3ms or +1ms. //correct by a fraction of the error. //diag_os_millisleep also does some self-correcting; we don't want to overdo it. correction = correction - (real_t / 3); //fprintf(stderr, FLFMT "tty_break off by %ldus, new correction=%ldus.\n", // FL, real_t, correction); return 0; }
/* * Do wakeup on the bus * * We do this by noting a wakeup needs to be done for the next packet for * fastinit, and doing slowinit now */ static int diag_l0_br_initbus(struct diag_l0_device *dl0d, struct diag_l1_initbus_args *in) { int rv = 0; struct diag_l0_br_device *dev; dev = (struct diag_l0_br_device *)dl0d->l0_int; if (diag_l0_debug & DIAG_DEBUG_IOCTL) fprintf(stderr, FLFMT "device link %p info %p initbus type %d proto %d\n", FL, (void *)dl0d, (void *)dev, in->type, dev ? dev->protocol : -1); if (!dev) return diag_iseterr(DIAG_ERR_GENERAL); diag_tty_iflush(dl0d); /* Flush unread input */ switch (in->type) { case DIAG_L1_INITBUS_5BAUD: rv = diag_l0_br_slowinit(dl0d, in); break; case DIAG_L1_INITBUS_FAST: if ((dev->dev_features & BR_FEATURE_FASTINIT) == 0) { /* Fast init Not supported */ rv = DIAG_ERR_INIT_NOTSUPP; } else { /* Fastinit done on 1st TX */ dev->dev_state = BR_STATE_KWP_FASTINIT; rv = 0; } break; default: rv = DIAG_ERR_INIT_NOTSUPP; break; } return rv? diag_iseterr(rv):0 ; }
/* * POSIX serial I/O input flush: */ int diag_tty_iflush(struct diag_l0_device *dl0d) { errno = 0; if (tcflush(dl0d->fd, TCIFLUSH) < 0) { fprintf(stderr, FLFMT "TCIFLUSH on fd %d returned %s.\n", FL, dl0d->fd, strerror(errno)); return diag_iseterr(DIAG_ERR_GENERAL); } return 0; }
ssize_t diag_tty_read(struct diag_l0_device *dl0d, void *buf, size_t count, unsigned int timeout) { DWORD bytesread; ssize_t rv=DIAG_ERR_TIMEOUT; OVERLAPPED *pOverlap; struct tty_int *wti = (struct tty_int *)dl0d->tty_int; pOverlap=NULL; COMMTIMEOUTS devtimeouts; if ((count <= 0) || (timeout <= 0)) return DIAG_ERR_BADLEN; if (diag_l0_debug & DIAG_DEBUG_READ) { fprintf(stderr, FLFMT "tty_read: ttyh=%p, fd=%p, len=%u, t=%u\n", FL, (void *)wti, (void *)wti->fd, count, timeout); } if (wti->fd == INVALID_HANDLE_VALUE) { fprintf(stderr, FLFMT "Error. Is the port open ?\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } // GetCommTimeouts(dl0d->fd, &devtimeouts); //get current timeouts //and modify them devtimeouts.ReadIntervalTimeout= timeout ? 0:MAXDWORD; //disabled unless timeout was 0. devtimeouts.ReadTotalTimeoutMultiplier=0; //timeout per requested byte devtimeouts.ReadTotalTimeoutConstant=timeout; // (tconst + mult*numbytes) = total timeout on read devtimeouts.WriteTotalTimeoutMultiplier=0; //probably useless as all flow control will be disabled ?? devtimeouts.WriteTotalTimeoutConstant=0; if (! SetCommTimeouts(wti->fd, &devtimeouts)) { fprintf(stderr, FLFMT "Could not set comm timeouts: %s\n",FL, diag_os_geterr(0)); return diag_iseterr(DIAG_ERR_GENERAL); } if (! ReadFile(wti->fd, buf, count, &bytesread, pOverlap)) { fprintf(stderr, FLFMT "ReadFile error: %s\n",FL, diag_os_geterr(0)); return diag_iseterr(DIAG_ERR_GENERAL); } if (bytesread > 0) rv=bytesread; return rv; }
static int diag_l0_elm_send(struct diag_l0_device *dl0d, UNUSED(const char *subinterface), const void *data, size_t len) { uint8_t buf[ELM_BUFSIZE]; //ssize_t xferd; int rv; unsigned int i; if (len <= 0) return diag_iseterr(DIAG_ERR_BADLEN); if ((2*len)>(ELM_BUFSIZE-1)) { //too much data for buffer size fprintf(stderr, FLFMT "ELM: too much data for buffer (report this bug please!)\n", FL); return diag_iseterr(DIAG_ERR_BADLEN); } if (diag_l0_debug & DIAG_DEBUG_WRITE) { fprintf(stderr, FLFMT "ELM: sending %d bytes\n", FL, (int) len); } for (i=0; i<len; i++) { //fill buffer with ascii-fied hex data snprintf((char *) &buf[2*i], 3, "%02X", (unsigned int)((uint8_t *)data)[i] ); } i=2*len; buf[i]=0x0D; buf[i+1]=0x00; //terminate string if ((diag_l0_debug & DIAG_DEBUG_WRITE) && (diag_l0_debug & DIAG_DEBUG_DATA)) { fprintf(stderr, FLFMT "ELM: (sending string %s)\n", FL, (char *) buf); } rv=diag_tty_write(dl0d, buf, i+1); if (rv != (int) (i+1)) { //XXX danger ! evil cast ! fprintf(stderr, FLFMT "elm_send:write error\n",FL); return diag_iseterr(DIAG_ERR_GENERAL); } return 0; }
int diag_l3_send(struct diag_l3_conn *d_l3_conn, struct diag_msg *msg) { int rv; const struct diag_l3_proto *dp = d_l3_conn->d_l3_proto; rv = dp->diag_l3_proto_send(d_l3_conn, msg); if (!rv) d_l3_conn->timer=diag_os_getms(); return rv? diag_iseterr(rv):0; }
/* * Set/Clear DTR and RTS lines, as specified */ int diag_tty_control(struct diag_l0_device *dl0d, unsigned int dtr, unsigned int rts) { int flags; /* Current flag values. */ struct unix_tty_int *uti = (struct unix_tty_int *)dl0d->tty_int; int setflags = 0, clearflags = 0; if (dtr) setflags = TIOCM_DTR; else clearflags = TIOCM_DTR; if (rts) setflags = TIOCM_RTS; else clearflags = TIOCM_RTS; errno = 0; if (ioctl(uti->fd, TIOCMGET, &flags) < 0) { fprintf(stderr, FLFMT "open: Ioctl TIOCMGET failed %s\n", FL, strerror(errno)); return diag_iseterr(DIAG_ERR_GENERAL); } flags |= setflags; flags &= ~clearflags; if (ioctl(uti->fd, TIOCMSET, &flags) < 0) { fprintf(stderr, FLFMT "open: Ioctl TIOCMSET failed %s\n", FL, strerror(errno)); return diag_iseterr(DIAG_ERR_GENERAL); } if (diag_l0_debug & DIAG_DEBUG_TIMER) { unsigned long tc=diag_os_chronoms(0); fprintf(stderr, FLFMT "%lu : DTR/RTS changed\n", FL, tc); } return 0; }
/* * Set/Clear DTR and RTS lines, as specified */ int diag_tty_control(struct diag_l0_device *dl0d, int dtr, int rts) { int flags; /* Current flag values. */ struct timeval tv; //for getting timestamps int setflags = 0, clearflags = 0; if (dtr) setflags = TIOCM_DTR; else clearflags = TIOCM_DTR; if (rts) setflags = TIOCM_RTS; else clearflags = TIOCM_RTS; errno = 0; if (ioctl(dl0d->fd, TIOCMGET, &flags) < 0) { fprintf(stderr, FLFMT "open: Ioctl TIOCMGET failed %s\n", FL, strerror(errno)); return diag_iseterr(DIAG_ERR_GENERAL); } flags |= setflags; flags &= ~clearflags; if (ioctl(dl0d->fd, TIOCMSET, &flags) < 0) { fprintf(stderr, FLFMT "open: Ioctl TIOCMSET failed %s\n", FL, strerror(errno)); return diag_iseterr(DIAG_ERR_GENERAL); } gettimeofday(&tv, NULL); if (diag_l0_debug & DIAG_DEBUG_TIMER) { fprintf(stderr, FLFMT "%04ld.%03ld : DTR/RTS changed\n", FL, tv.tv_sec, tv.tv_usec); } return 0; }
// Simulates the send of a request. // Returns 0 on success, -1 on failure. // Should be called with the full message to send, because // CARSIM behaves like a smart interface (does P4). // Gets the list of responses from the DB file for the given request. static int diag_l0_sim_send(struct diag_l0_device *dl0d, UNUSED(const char *subinterface), const void *data, const size_t len) { struct diag_l0_sim_device * dev = dl0d->dl0_handle; if (len <= 0) return diag_iseterr(DIAG_ERR_BADLEN); if (len > 255) { fprintf(stderr, FLFMT "Error : calling diag_l0_sim_send with len >255 bytes! (%u)\n", FL, (unsigned int) len); return diag_iseterr(DIAG_ERR_GENERAL); } if (sim_last_ecu_responses != NULL) { fprintf(stderr, FLFMT "AAAHHH!!! You're sending a new request before reading all previous responses!!! \n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } if (diag_l0_debug & DIAG_DEBUG_WRITE) { fprintf(stderr, FLFMT "dl0d=%p sending %u bytes\n", FL, (void *)dl0d, (unsigned int)len); if (diag_l0_debug & DIAG_DEBUG_DATA) { fprintf(stderr, FLFMT "L0 sim sending: ", FL); diag_data_dump(stderr, data, len); fprintf(stderr, "\n"); } } // Build the list of responses for this request. sim_find_responses(&sim_last_ecu_responses, dev->fp, data, (uint8_t) len); if (diag_l0_debug & DIAG_DEBUG_DATA) sim_dump_ecu_responses(sim_last_ecu_responses); return 0; }
// Simulates the bus initialization. static int diag_l0_sim_initbus(struct diag_l0_device *dl0d, struct diag_l1_initbus_args *in) { struct diag_l0_sim_device *dev; uint8_t synch_patt[1]; const uint8_t sim_break = 0x00; sim_free_ecu_responses(&sim_last_ecu_responses); dev = (struct diag_l0_sim_device *)dl0d->dl0_handle; if (diag_l0_debug & DIAG_DEBUG_IOCTL) fprintf(stderr, FLFMT "device link %p info %p initbus type %d\n", FL, (void *)dl0d, (void *)dev, in->type); if (!dev) return diag_iseterr(DIAG_ERR_INIT_NOTSUPP); switch (in->type) { case DIAG_L1_INITBUS_FAST: // Send break. // We simulate a break with a single "0x00" char. if (diag_l0_debug & DIAG_DEBUG_DATA) fprintf(stderr, FLFMT "Sending: BREAK!\n", FL); diag_l0_sim_send(dl0d, 0, &sim_break, 1); break; case DIAG_L1_INITBUS_5BAUD: // Send Service Address (as if it was at 5baud). diag_l0_sim_send(dl0d, 0, &in->addr, 1); // Receive Synch Pattern (as if it was at 10.4kbaud). diag_l0_sim_recv(dl0d, 0 , synch_patt, 1, 0); break; default: return diag_iseterr(DIAG_ERR_INIT_NOTSUPP); break; } return 0; }
//return <0 on error, number of bytes on success static int diag_l1_saferead(struct diag_l0_device *dl0d, char *buf, size_t bufsiz, int timeout) { int xferd; /* And read back the single byte echo, which shows TX completes */ while ( (xferd = diag_tty_read(dl0d, buf, bufsiz, timeout)) < 0) { if (errno != EINTR) return diag_iseterr(DIAG_ERR_BUSERROR); xferd = 0; /* Interrupted read, nothing transferred. */ } return xferd; }
int diag_l3_recv(struct diag_l3_conn *d_l3_conn, unsigned int timeout, void (* rcv_call_back)(void *handle ,struct diag_msg *) , void *handle) { const struct diag_l3_proto *dp = d_l3_conn->d_l3_proto; int rv; rv=dp->diag_l3_proto_recv(d_l3_conn, timeout, rcv_call_back, handle); if (rv==0) d_l3_conn->timer=diag_os_getms(); return rv? diag_iseterr(rv):0; }
/* * Open the L0 device with L1 proto. * */ int diag_l1_open(struct diag_l0_device *dl0d, int l1protocol) { DIAG_DBGM(diag_l1_debug, DIAG_DEBUG_OPEN, DIAG_DBGLEVEL_V, FLFMT "diag_l1_open(0x%p, l1 proto=%d\n", FL, (void *)dl0d, l1protocol); /* Check h/w supports this l1 protocol */ if ((dl0d->dl0->l1proto_mask & l1protocol) == 0) { return diag_iseterr(DIAG_ERR_PROTO_NOTSUPP); } /* Call the open routine with the requested L1 protocol */ return diag_l0_open(dl0d, l1protocol); }
ssize_t diag_tty_write(struct diag_l0_device *dl0d, const void *buf, const size_t count) { DWORD byteswritten; OVERLAPPED *pOverlap; struct tty_int *wti = (struct tty_int *)dl0d->tty_int; pOverlap=NULL; //note : if overlap is eventually enabled, the CreateFile flags should be adjusted if (wti->fd == INVALID_HANDLE_VALUE) { fprintf(stderr, FLFMT "Error. Is the port open ?\n", FL); return diag_iseterr(DIAG_ERR_GENERAL); } if (count <= 0) return diag_iseterr(DIAG_ERR_BADLEN); if (! WriteFile(wti->fd, buf, count, &byteswritten, pOverlap)) { fprintf(stderr, FLFMT "WriteFile error:%s. %u bytes written, %u requested\n", FL, diag_os_geterr(0), (unsigned int) byteswritten, count); return diag_iseterr(DIAG_ERR_GENERAL); } if (!FlushFileBuffers(wti->fd)) { fprintf(stderr, FLFMT "tty_write : could not flush buffers, %s\n", FL, diag_os_geterr(0)); return diag_iseterr(DIAG_ERR_GENERAL); } return byteswritten; } //diag_tty_write