/* * Fastinit: ISO14230-2 sec 5.2.4.2.3 * Caller should have waited W5 (>300ms) before calling this (from _initbus only!) * we assume the L line was at the correct state (1) during that time. * returns 0 (success), 50ms after starting the wake-up pattern. * Exceptionally we dont diag_iseterr on return since _initbus() takes care of that. */ static int diag_l0_dumb_fastinit(struct diag_l0_device *dl0d) { int rv=0; uint8_t cbuf[MAXRBUF]; if (diag_l0_debug & DIAG_DEBUG_INIT) fprintf(stderr, FLFMT "dl0d=%p fastinit\n", FL, (void *)dl0d); //Tidle before break : W5 (>300ms) on poweron; P3 (>55ms) after a StopCommunication; or 0ms after a P3 timeout. // We assume the caller took care of this. /* Send 25/25 ms break as initialisation pattern (TiniL) */ //ISO14230-2 says we should send the same sync pattern on both L and K together. // we do it almost perfectly; the L \_/ pulse starts before and ends after the K \_/ pulse. if (dumb_flags & USE_LLINE) { // do K+L only if the user wants to do both if (dumb_flags & FAST_BREAK) { //but we can't use diag_tty_fastbreak while doing the L-line. fprintf(stderr, FLFMT "Warning : not using L line for FAST_BREAK.\n", FL); rv=diag_tty_fastbreak(dl0d, 50-WUPFLUSH); } else { //normal fast break on K and L. //note : if LLINE_INV is 1, then we need to clear RTS to pull L down ! if (diag_tty_control(dl0d, !(dumb_flags & CLEAR_DTR), !(dumb_flags & LLINE_INV)) < 0) { fprintf(stderr, FLFMT "fastinit: Failed to set L\\_\n", FL); return DIAG_ERR_GENERAL; } rv=diag_tty_break(dl0d, 25); //K line low for 25ms /* Now restore DTR/RTS */ if (diag_tty_control(dl0d, !(dumb_flags & CLEAR_DTR), (dumb_flags & SET_RTS)) < 0) { fprintf(stderr, FLFMT "fastinit: Failed to restore DTR & RTS!\n", FL); } diag_os_millisleep(25-WUPFLUSH); } //if FAST_BREAK } else { // do K line only if (dumb_flags & FAST_BREAK) { rv=diag_tty_fastbreak(dl0d, 50-WUPFLUSH); } else { //normal break rv=diag_tty_break(dl0d, 25); //K line low for 25ms diag_os_millisleep(25-WUPFLUSH); } } //if USE_LLINE // here we have WUPFLUSH ms before tWUP is done; we use this // short time to flush RX buffers. (L2 needs to send a StartComm // request very soon.) diag_tty_read(dl0d, cbuf, sizeof(cbuf), WUPFLUSH); //there may have been a problem in diag_tty_break, if so : if (rv) { fprintf(stderr, FLFMT " L0 fastinit : problem !\n", FL); return DIAG_ERR_GENERAL; } return 0; }
static void diag_l0_dumb_Lline(struct diag_l0_device *dl0d, uint8_t ecuaddr) { /* * The bus has been high for w0 ms already, now send the * 8 bit ecuaddr at 5 baud LSB first * */ int i, rv=0; // uint8_t cbuf[10]; // We also toggle DTR to disable RXD (blocking it at logical 1). // However, at least one system I tested doesn't react well to // DTR-toggling. /* Set RTS low, for 200ms (Start bit) */ if (diag_tty_control(dl0d, (dumb_flags & CLEAR_DTR), !(dumb_flags & LLINE_INV)) < 0) { fprintf(stderr, FLFMT "_LLine: Failed to set DTR & RTS\n", FL); return; } diag_os_millisleep(BPS_PERIOD); /* 200ms -5% */ for (i=0; i<8; i++) { if (ecuaddr & (1<<i)) { /* High */ rv |= diag_tty_control(dl0d, (dumb_flags & CLEAR_DTR), (dumb_flags & LLINE_INV)); } else { /* Low */ rv |= diag_tty_control(dl0d, (dumb_flags & CLEAR_DTR), !(dumb_flags & LLINE_INV)); } if (rv < 0) { fprintf(stderr, FLFMT "_LLine: Failed to set DTR & RTS\n", FL); return; } diag_os_millisleep(BPS_PERIOD); /* 200ms -5% */ } /* And set high for the stop bit */ if (diag_tty_control(dl0d, (dumb_flags & CLEAR_DTR), !(dumb_flags & LLINE_INV)) < 0) { fprintf(stderr, FLFMT "_LLine: Failed to set DTR & RTS\n", FL); return; } diag_os_millisleep(BPS_PERIOD); /* 200ms -5% */ /* Now put DTR/RTS back correctly so RX side is enabled */ if (diag_tty_control(dl0d, !(dumb_flags & CLEAR_DTR), (dumb_flags & SET_RTS)) < 0) { fprintf(stderr, FLFMT "_LLine: Failed to restore DTR & RTS\n", FL); } /* And clear out the break XXX no, _slowinit will do this for us after calling dumb_Lline*/ // diag_tty_read(dl0d, cbuf, sizeof(cbuf), 20); return; }
/* * Slowinit: * We need to send a byte (the address) at 5 baud, then * switch back to 10400 baud * and then wait W1 (60-300ms) until we get Sync byte 0x55. * Caller (in L2 typically) must have waited with bus=idle beforehand. * This optionally does the L_line stuff according to the flags in dumb_flags. * Ideally returns 0 (success) immediately after receiving Sync byte. * This one, like fastinit, doesnt diag_iseterr when returning errors * since _initbus() takes care of that. * */ static int diag_l0_dumb_slowinit(struct diag_l0_device *dl0d, struct diag_l1_initbus_args *in, struct diag_l0_dumb_device *dev) { uint8_t cbuf[10]; int rv; unsigned int tout; struct diag_serial_settings set; if (diag_l0_debug & DIAG_DEBUG_PROTO) { fprintf(stderr, FLFMT "slowinit dl0d=%p address 0x%X\n", FL, (void *)dl0d, in->addr); } //two methods of sending at 5bps. Most USB-serial converts don't support such a slow bitrate ! if (dumb_flags & MAN_BREAK) { //MAN_BREAK means we bitbang K and optionally L as well. if (dumb_flags & USE_LLINE) { //do manual 5bps init on K and L. //we need to send the byte at in->addr, bit by bit. int bitcounter; uint8_t tempbyte=in->addr; diag_tty_control(dl0d, !(dumb_flags & CLEAR_DTR), !(dumb_flags & LLINE_INV)); //L is the logical opposite of RTS... diag_tty_break(dl0d, BPS_PERIOD); //start startbit for (bitcounter=0; bitcounter<=7; bitcounter++) { //LSB first. if (tempbyte & 1) { diag_tty_control(dl0d, !(dumb_flags & CLEAR_DTR), (dumb_flags & LLINE_INV)); //release L diag_os_millisleep(BPS_PERIOD); } else { unsigned int lowtime=BPS_PERIOD; //to prevent spurious breaks if we have a sequence of 0's : //this is an RLE of sorts... for (; bitcounter <=6; bitcounter++) { if (tempbyte & 2) //test bit 1; we just tested bit 0 before getting here. break; lowtime += BPS_PERIOD; tempbyte = tempbyte >>1; } //this way, we know for sure the next bit is 1 (either bit 7==1 or stopbit==1 !) diag_tty_control(dl0d, !(dumb_flags & CLEAR_DTR), !(dumb_flags & LLINE_INV)); //pull L down diag_tty_break(dl0d, lowtime); } tempbyte = tempbyte >>1; } //at this point we just finished the last bit, we'll wait the duration of the stop bit. diag_tty_control(dl0d, !(dumb_flags & CLEAR_DTR), (dumb_flags & SET_RTS)); //release L diag_os_millisleep(BPS_PERIOD); //stop bit } else {
/* * Open the diagnostic device, returns a file descriptor * records original state of term interface so we can restore later */ static struct diag_l0_device * diag_l0_muleng_open(const char *subinterface, int iProtocol) { int rv; struct diag_l0_device *dl0d; struct diag_l0_muleng_device *dev; struct diag_serial_settings set; if (diag_l0_debug & DIAG_DEBUG_OPEN) { fprintf(stderr, FLFMT "open subinterface %s protocol %d\n", FL, subinterface, iProtocol); } diag_l0_muleng_init(); if ((rv=diag_calloc(&dev, 1))) return diag_pseterr(rv); dev->protocol = iProtocol; dl0d = diag_l0_new(&diag_l0_me, (void *)dev); if (!dl0d) { free(dev); return diag_pseterr(rv); } /* try to open TTY */ if ((rv=diag_tty_open(dl0d, subinterface))) { diag_l0_del(dl0d); free(dev); return diag_pseterr(rv); } /* And set to 19200 baud , 8N1 */ set.speed = 19200; set.databits = diag_databits_8; set.stopbits = diag_stopbits_1; set.parflag = diag_par_n; if ((rv=diag_tty_setup(dl0d, &set))) { diag_l0_muleng_close(dl0d); return diag_pseterr(rv); } /* And set DTR high and RTS low to power the device */ if ((rv=diag_tty_control(dl0d, 1, 0))) { diag_l0_muleng_close(dl0d); return diag_pseterr(rv); } diag_tty_iflush(dl0d); /* Flush unread input */ return dl0d ; }
/* * Open the diagnostic device, returns a file descriptor * records original state of term interface so we can restore later */ static struct diag_l0_device * diag_l0_dumb_open(const char *subinterface, int iProtocol) { int rv; struct diag_l0_device *dl0d; struct diag_l0_dumb_device *dev; if (diag_l0_debug & DIAG_DEBUG_OPEN) { fprintf(stderr, FLFMT "open subinterface %s protocol %d\n", FL, subinterface, iProtocol); } diag_l0_dumb_init(); //make sure it is initted if ((rv=diag_calloc(&dev, 1))) return diag_pseterr(DIAG_ERR_NOMEM); dev->protocol = iProtocol; dl0d = diag_l0_new(&diag_l0_dumb, (void *)dev); if (!dl0d) { free(dev); return diag_pseterr(rv); } /* try to open TTY */ if ((rv=diag_tty_open(dl0d, subinterface))) { diag_l0_del(dl0d); free(dev); return diag_pseterr(rv); } /* * We set RTS to low, and DTR high, because this allows some * interfaces to work than need power from the DTR/RTS lines; * this is altered according to dumb_flags. */ if (diag_tty_control(dl0d, !(dumb_flags & CLEAR_DTR), (dumb_flags & SET_RTS)) < 0) { diag_l0_dumb_close(&dl0d); return diag_pseterr(DIAG_ERR_GENERAL); } if (dumb_flags & DUMBDEFAULTS) dumb_flags = DUMBDEFAULTS & MAN_BREAK; (void)diag_tty_iflush(dl0d); /* Flush unread input */ return dl0d; }