/* * Protocol receive routine * * Will sleep until a complete set of responses has been received, or fail * with a timeout error * * The interbyte type in data from an ECU is between P1Min and P1Max * The intermessage time for part of one response is P2Min and P2Max * * If we are running with an intelligent L1 interface, then we will be * getting one message per frame, and we will wait a bit longer * for extra messages */ static int diag_l2_proto_14230_recv(struct diag_l2_conn *d_l2_conn, unsigned int timeout, void (*callback)(void *handle, struct diag_msg *msg), void *handle) { int rv; /* Call internal routine */ rv = diag_l2_proto_14230_int_recv(d_l2_conn, timeout); if (rv < 0) /* Failure */ return rv; if (diag_l2_debug & DIAG_DEBUG_READ) fprintf(stderr, FLFMT "_int_recv : handle=%p timeout=%u\n", FL, (void *)handle, timeout); //%pcallback! we won't try to printf the callback pointer. /* * Call user callback routine */ if (callback) callback(handle, d_l2_conn->diag_msg); /* No longer needed */ diag_freemsg(d_l2_conn->diag_msg); d_l2_conn->diag_msg = NULL; if (diag_l2_debug & DIAG_DEBUG_READ) fprintf(stderr, FLFMT "_recv callback completed\n", FL); return 0; }
//iso14230 diag_l2_proto_request. See diag_l2.h //This handles busyRepeatRequest and RspPending negative responses. //return NULL if failed, or a newly alloced diag_msg if succesful. //Caller must free that diag_msg. //Sends using diag_l2_send() in order to have the timestamps updated static struct diag_msg * diag_l2_proto_14230_request(struct diag_l2_conn *d_l2_conn, struct diag_msg *msg, int *errval) { int rv; struct diag_msg *rmsg = NULL; int retries=3; //if we get a BusyRepeatRequest response. *errval=0; rv = diag_l2_send(d_l2_conn, msg); if (rv < 0) { *errval = rv; return diag_pseterr(rv); } while (1) { rv = diag_l2_proto_14230_int_recv(d_l2_conn, d_l2_conn->diag_l2_p2max + 10); if (rv < 0) { *errval = DIAG_ERR_TIMEOUT; return diag_pseterr(rv); } /* * The connection now has the received message data * stored, remove it and deal with it */ rmsg = d_l2_conn->diag_msg; d_l2_conn->diag_msg = NULL; /* Got a Error message */ if (rmsg->data[0] == DIAG_KW2K_RC_NR) { if (rmsg->data[2] == DIAG_KW2K_RC_B_RR) { /* * Msg is busyRepeatRequest * So do a send again (if retries>0) */ if (retries > 0) { rv = diag_l2_send(d_l2_conn, msg); } else { rv=DIAG_ERR_GENERAL; fprintf(stderr, FLFMT "got too many BusyRepeatRequest responses!\n", FL); } retries--; if (rv < 0) { *errval = rv; return diag_pseterr(rv); } if (diag_l2_debug & DIAG_DEBUG_PROTO) fprintf(stderr, FLFMT "got BusyRepeatRequest: retrying...\n", FL); diag_freemsg(rmsg); continue; } if (rmsg->data[2] == DIAG_KW2K_RC_RCR_RP) { /* * Msg is a requestCorrectlyRcvd-RspPending * so do read again */ if (diag_l2_debug & DIAG_DEBUG_PROTO) fprintf(stderr, FLFMT "got RspPending: retrying...\n", FL); diag_freemsg(rmsg); continue; } /* Some other type of error */ *errval= DIAG_ERR_ECUSAIDNO; break; } else { /* Success */ break; } } /* Return the message to user, who is responsible for freeing it */ return rmsg; }
/* * The complex initialisation routine for ISO14230, which supports * 2 types of initialisation (5-BAUD, FAST) and functional * and physical addressing. The ISO14230 spec describes CARB initialisation * which is done in the ISO9141 code * * Remember, we have to wait longer on smart L1 interfaces. */ static int diag_l2_proto_14230_startcomms( struct diag_l2_conn *d_l2_conn, flag_type flags, unsigned int bitrate, target_type target, source_type source) { struct diag_l2_14230 *dp; struct diag_msg msg={0}; uint8_t data[MAXRBUF]; int rv; unsigned int wait_time; uint8_t cbuf[MAXRBUF]; unsigned int timeout; struct diag_serial_settings set; struct diag_l1_initbus_args in; if (diag_calloc(&dp, 1)) return diag_iseterr(DIAG_ERR_NOMEM); d_l2_conn->diag_l2_proto_data = (void *)dp; dp->initype = flags & DIAG_L2_TYPE_INITMASK; //only keep initmode flags dp->srcaddr = source; dp->dstaddr = target; //set iso14230-specific flags according to what we were given if (flags & DIAG_L2_IDLE_J1978) dp->modeflags |= ISO14230_IDLE_J1978; if (flags & DIAG_L2_TYPE_FUNCADDR) dp->modeflags |= ISO14230_FUNCADDR; dp->first_frame = 1; if (diag_l2_debug & DIAG_DEBUG_PROTO) fprintf(stderr, FLFMT "_startcomms flags=0x%X tgt=0x%X src=0x%X\n", FL, flags, target, source); memset(data, 0, sizeof(data)); /* * If 0 has been specified, use the correct speed * for ISO14230 protocol */ if (bitrate == 0) bitrate = 10400; d_l2_conn->diag_l2_speed = bitrate; set.speed = bitrate; set.databits = diag_databits_8; set.stopbits = diag_stopbits_1; set.parflag = diag_par_n; /* Set the speed*/ if ((rv=diag_l2_ioctl(d_l2_conn, DIAG_IOCTL_SETSPEED, (void *) &set))) { free(dp); d_l2_conn->diag_l2_proto_data=NULL; //delete pointer to dp return diag_iseterr(rv); } dp->state = STATE_CONNECTING ; /* Flush unread input, then wait for idle bus. */ (void)diag_l2_ioctl(d_l2_conn, DIAG_IOCTL_IFLUSH, NULL); diag_os_millisleep(300); //inside this switch, we set rv=0 or rv=error before "break;" switch (dp->initype & DIAG_L2_TYPE_INITMASK) { /* Fast initialisation */ case DIAG_L2_TYPE_FASTINIT: /* Build an ISO14230 StartComms message */ if (flags & DIAG_L2_TYPE_FUNCADDR) { msg.fmt = DIAG_FMT_ISO_FUNCADDR; d_l2_conn->diag_l2_physaddr = 0; /* Don't know it yet */ in.physaddr = 0; } else { msg.fmt = 0; d_l2_conn->diag_l2_physaddr = target; in.physaddr = 1; } msg.src = source; msg.dest = target; msg.len = 1 ; data[0]= DIAG_KW2K_SI_SCR ; /* startCommunication rqst*/ msg.data = data; /* Do fast init stuff */ in.type = DIAG_L1_INITBUS_FAST; in.addr = target; in.testerid = source; rv = diag_l2_ioctl(d_l2_conn, DIAG_IOCTL_INITBUS, &in); // some L0 devices already do the full startcomm transaction: if ((d_l2_conn->diag_link->l1flags & DIAG_L1_DOESFULLINIT) && (rv==0)) { //TODO : somehow extract keybyte data for those cases... //original elm327s have the "atkw" command to get the keybytes, but clones suck. dp->state = STATE_ESTABLISHED; break; } if (rv < 0) break; /* Send the prepared message */ if (diag_l2_proto_14230_send(d_l2_conn, &msg)) { rv=DIAG_ERR_GENERAL; break; } if (d_l2_conn->diag_link->l1flags & DIAG_L1_DOESL2FRAME) timeout = 200; else timeout = d_l2_conn->diag_l2_p2max + RXTOFFSET; /* And wait for a response, ISO14230 says will arrive in P2 */ rv = diag_l2_proto_14230_int_recv(d_l2_conn, timeout); if (rv < 0) break; // _int_recv() should have filled d_l2_conn->diag_msg properly. // check if message is OK : if (d_l2_conn->diag_msg->fmt & DIAG_FMT_BADCS) { rv=DIAG_ERR_BADCSUM; break; } switch (d_l2_conn->diag_msg->data[0]) { case DIAG_KW2K_RC_SCRPR: /* StartComms positive response */ d_l2_conn->diag_l2_kb1 = d_l2_conn->diag_msg->data[1]; d_l2_conn->diag_l2_kb2 = d_l2_conn->diag_msg->data[2]; d_l2_conn->diag_l2_physaddr = d_l2_conn->diag_msg->src; if (diag_l2_debug & DIAG_DEBUG_PROTO) { fprintf(stderr, FLFMT "_StartComms Physaddr=0x%X KB1=%02X, KB2=%02X\n", FL, d_l2_conn->diag_l2_physaddr, d_l2_conn->diag_l2_kb1, d_l2_conn->diag_l2_kb2); } rv=0; dp->state = STATE_ESTABLISHED ; break; case DIAG_KW2K_RC_NR: if (diag_l2_debug & DIAG_DEBUG_PROTO) { fprintf(stderr, FLFMT "_StartComms got neg response\n", FL); } rv=DIAG_ERR_ECUSAIDNO; break; default: if (diag_l2_debug & DIAG_DEBUG_PROTO) { fprintf(stderr, FLFMT "_StartComms got unexpected response 0x%X\n", FL, d_l2_conn->diag_msg->data[0]); } rv=DIAG_ERR_ECUSAIDNO; break; } //switch data[0] break; //case _FASTINIT /* 5 Baud init */ case DIAG_L2_TYPE_SLOWINIT: in.type = DIAG_L1_INITBUS_5BAUD; in.addr = target; rv = diag_l2_ioctl(d_l2_conn, DIAG_IOCTL_INITBUS, &in); //some L0 devices handle the full init transaction: if ((d_l2_conn->diag_link->l1flags & DIAG_L1_DOESFULLINIT) && (rv==0)) { dp->state = STATE_ESTABLISHED ; break; } if (rv < 0) break; /* Mode bytes are in 7-Odd-1, read as 8N1 and ignore parity */ rv = diag_l1_recv (d_l2_conn->diag_link->diag_l2_dl0d, 0, cbuf, 2, 100); if (rv < 0) break; /* ISO14230 uses KB2 of 0x8F */ if (cbuf[1] != 0x8f) { rv=DIAG_ERR_WRONGKB; break; } /* Note down the mode bytes */ // KB1 : we eliminate the Parity bit (MSB !) d_l2_conn->diag_l2_kb1 = cbuf[0] & 0x7f; d_l2_conn->diag_l2_kb2 = cbuf[1]; if ( (d_l2_conn->diag_link->l1flags & DIAG_L1_DOESSLOWINIT) == 0) { /* * Now transmit KB2 inverted */ cbuf[0] = ~ d_l2_conn->diag_l2_kb2; rv = diag_l1_send (d_l2_conn->diag_link->diag_l2_dl0d, 0, cbuf, 1, d_l2_conn->diag_l2_p4min); /* * And wait for the address byte inverted */ //first init cbuf[0] to the wrong value in case l1_recv gets nothing cbuf[0]= (uint8_t) target; rv = diag_l1_recv (d_l2_conn->diag_link->diag_l2_dl0d, 0, cbuf, 1, 350); if (cbuf[0] != ((~target) & 0xFF) ) { fprintf(stderr, FLFMT "_startcomms : addr mismatch %02X!=%02X\n", FL, cbuf[0], (uint8_t) ~target); rv=DIAG_ERR_WRONGKB; break; } if (diag_l2_debug & DIAG_DEBUG_INIT) fprintf(stderr, FLFMT "ISO14230 KB1=%02X KB2=%02X\n", FL, d_l2_conn->diag_l2_kb1, d_l2_conn->diag_l2_kb2); } rv=0; dp->state = STATE_ESTABLISHED ; break; //case _SLOWINIT case DIAG_L2_TYPE_MONINIT: /* Monitor mode, don't send anything */ dp->state = STATE_ESTABLISHED ; rv = 0; break; default: rv = DIAG_ERR_INIT_NOTSUPP; break; } //end of switch dp->initype //At this point we just finished the handshake and got KB1 and KB2 if (rv < 0) { free(dp); d_l2_conn->diag_l2_proto_data=NULL; //delete pointer to dp return diag_iseterr(rv); } // Analyze keybytes and set modeflags properly. See // iso14230 5.2.4.1 & Table 8 dp->modeflags |= ((d_l2_conn->diag_l2_kb1 & 1)? ISO14230_FMTLEN:0) | ((d_l2_conn->diag_l2_kb1 & 2)? ISO14230_LENBYTE:0) | ((d_l2_conn->diag_l2_kb1 & 4)? ISO14230_SHORTHDR:0) | ((d_l2_conn->diag_l2_kb1 & 8)? ISO14230_LONGHDR:0); if (diag_l2_debug & DIAG_DEBUG_PROTO) fprintf(stderr, FLFMT "new modeflags=0x%04X\n", FL, dp->modeflags); //For now, we won't bother with Normal / Extended timings. We don't //need to unless we use the AccessTimingParameters service (scary) /* * Now, we want to remove any rubbish left * in inbound buffers, and wait for the bus to be * quiet for a while before we will communicate * (so that the next byte received is the first byte * of an iso14230 frame, not a middle byte) * We use 1/2 of P2max (inter response gap) or * 5 * p4max (inter byte delay), whichever is larger * a correct value to use */ wait_time = d_l2_conn->diag_l2_p2max / 2 ; if ((d_l2_conn->diag_l2_p4max * 5) > wait_time) wait_time = d_l2_conn->diag_l2_p4max * 5; while ( diag_l1_recv (d_l2_conn->diag_link->diag_l2_dl0d, 0, data, sizeof(data), wait_time) != DIAG_ERR_TIMEOUT) ; /* And we're done */ dp->state = STATE_ESTABLISHED ; return 0; }
//iso14230 diag_l2_proto_request. See diag_l2.h //This handles busyRepeatRequest and RspPending negative responses. //return NULL if failed, or a newly alloced diag_msg if succesful. //Caller must free that diag_msg. //Sends using diag_l2_send() in order to have the timestamps updated static struct diag_msg * diag_l2_proto_14230_request(struct diag_l2_conn *d_l2_conn, struct diag_msg *msg, int *errval) { int rv; struct diag_msg *rmsg = NULL; int retries=3; //if we get a BusyRepeatRequest response. *errval=0; rv = diag_l2_send(d_l2_conn, msg); if (rv < 0) { *errval = rv; return diag_pseterr(rv); } while (1) { /* do read only if no messages pending */ if (!d_l2_conn->diag_msg) { rv = diag_l2_proto_14230_int_recv(d_l2_conn, d_l2_conn->diag_l2_p2max + 10); if (rv < 0) { *errval = DIAG_ERR_TIMEOUT; if (rv == DIAG_ERR_TIMEOUT) { return NULL; } else { return diag_pseterr(rv); } } } /* * The connection now has the received message(s) * stored. Temporarily remove from dl2c */ rmsg = d_l2_conn->diag_msg; d_l2_conn->diag_msg = NULL; /* Check for negative response */ if (rmsg->data[0] != DIAG_KW2K_RC_NR) { /* Success */ break; } if (rmsg->data[2] == DIAG_KW2K_RC_B_RR) { /* * Msg is busyRepeatRequest * So send again (if retries>0). * * Is there any possibility that we would have received 2 messages, * {busyrepeatrequest + a valid (unrelated) response} ? * Not sure, let's simply discard everything. */ diag_freemsg(rmsg); if (retries > 0) { rv = diag_l2_send(d_l2_conn, msg); } else { rv=DIAG_ERR_GENERAL; fprintf(stderr, FLFMT "got too many BusyRepeatRequest responses!\n", FL); } retries--; if (rv < 0) { *errval = rv; return diag_pseterr(rv); } if (diag_l2_debug & DIAG_DEBUG_PROTO) fprintf(stderr, FLFMT "got BusyRepeatRequest: retrying...\n", FL); continue; } if (rmsg->data[2] == DIAG_KW2K_RC_RCR_RP) { /* * Msg is a requestCorrectlyRcvd-RspPending * so do read again */ if (diag_l2_debug & DIAG_DEBUG_PROTO) fprintf(stderr, FLFMT "got RspPending: retrying...\n", FL); /* reattach the rest of the chain, in case the good response * was already received */ d_l2_conn->diag_msg = rmsg->next; rmsg->next = NULL; diag_freemsg(rmsg); continue; } /* Some other type of error */ *errval= DIAG_ERR_ECUSAIDNO; break; } //while 1 /* Return the message to user, who is responsible for freeing it */ return rmsg; }