| 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 | * L3 code to do SAE J1979 messaging |
| 24 | * |
| 25 | */ |
| 26 | |
| 27 | |
| 28 | #include <assert.h> |
| 29 | #include <stdint.h> |
| 30 | #include <stdio.h> |
| 31 | #include <stdlib.h> |
| 32 | #include <string.h> |
| 33 | |
| 34 | #include "diag.h" |
| 35 | #include "diag_os.h" |
| 36 | #include "diag_err.h" |
| 37 | #include "diag_l1.h" |
| 38 | #include "diag_l2.h" |
| 39 | #include "diag_l3.h" |
| 40 | #include "diag_l3_saej1979.h" |
| 41 | #include "utlist.h" |
| 42 | |
| 43 | |
| 44 | /* internal data used by each connection */ |
| 45 | struct l3_j1979_int { |
| 46 | uint8_t src; //source address ("tester ID") |
| 47 | |
| 48 | /* Received data buffer, and offset into it */ |
| 49 | uint8_t rxbuf[MAXRBUF]; |
| 50 | int rxoffset; |
| 51 | }; |
| 52 | |
| 53 | /* |
| 54 | * Return the expected J1979 packet length for a given mode byte |
| 55 | * This includes *only* up to 7 data bytes (headers and checksum are stripped and |
| 56 | * generated in L2) |
| 57 | * |
| 58 | * XXX DOESN'T COPE WITH in-frame-response - will break check routine as well |
| 59 | * Also doesn't support 15765 (CAN) which has more modes. |
| 60 | * |
| 61 | * Get this wrong and all will fail, it's used to frame the incoming messages |
| 62 | * properly |
| 63 | */ |
| 64 | static int diag_l3_j1979_getlen(uint8_t *data, int len) { |
| 65 | static const int rqst_lengths[] = { -1, 2, 3, 1, 1, 2, 2, 1, 7, 2 }; |
| 66 | int rv; |
| 67 | uint8_t mode; |
| 68 | |
| 69 | if (len < 1) { /* Need at least 1 data byte*/ |
| 70 | return diag_iseterr(DIAG_ERR_INCDATA); |
| 71 | } |
| 72 | |
| 73 | mode = data[0]; |
| 74 | |
| 75 | //J1979 specifies 9 modes (0x01 - 0x09) except with iso15765 (CAN) which has 0x0A modes. |
| 76 | |
| 77 | if (mode > 0x49) { |
| 78 | return diag_iseterr(DIAG_ERR_BADDATA); |
| 79 | } |
| 80 | |
| 81 | if (mode < 0x41) { |
| 82 | if (mode <= 9) { |
| 83 | return rqst_lengths[mode]; |
| 84 | } |
| 85 | return diag_iseterr(DIAG_ERR_BADDATA); |
| 86 | } |
| 87 | |
| 88 | rv = DIAG_ERR_BADDATA; |
| 89 | |
| 90 | //Here, all modes < 0x0A are taken care of. |
| 91 | //Modes > 0x40 are responses and therefore need specific treatment |
| 92 | //data[1] contains the PID / TID number. |
| 93 | switch (mode) { |
| 94 | case 0x41: |
| 95 | case 0x42: //almost identical modes except PIDS 1,2 |
| 96 | // Note : mode 2 responses will be +1 longer because of the frame_no byte. |
| 97 | if ((data[1] & 0x1f) == 0) { |
| 98 | /* return supported PIDs */ |
| 99 | rv=6; //6.1.2.2 |
| 100 | break; |
| 101 | } |
| 102 | |
| 103 | switch (data[1]) { |
| 104 | case 1: //Status. Only with service 01 (mode 0x41) |
| 105 | if (mode == 0x42) { |
| 106 | rv=DIAG_ERR_BADDATA; |
| 107 | } else { |
| 108 | rv = 6; |
| 109 | } |
| 110 | break; |
| 111 | case 2: //request freeze DTC. Only with Service 02 (mode=0x42) |
| 112 | if (mode == 0x41) { |
| 113 | rv = DIAG_ERR_BADDATA; |
| 114 | } else { |
| 115 | rv = 4; |
| 116 | } |
| 117 | break; |
| 118 | case 3: |
| 119 | rv = 4; |
| 120 | break; |
| 121 | case 0x04: |
| 122 | case 0x05: |
| 123 | rv=3; |
| 124 | break; |
| 125 | case 0x06: |
| 126 | case 0x07: |
| 127 | case 0x08: |
| 128 | case 0x09: |
| 129 | case 0x55: |
| 130 | case 0x56: |
| 131 | case 0x57: |
| 132 | case 0x58: |
| 133 | //XXX For PIDs 0x06 thru 0x09 and 0x55-0x58, there may be an additional data byte based on PID 0x13 / 0x1D results |
| 134 | // (presence of a bank3 O2 sensor. Not implemented... |
| 135 | rv=3; |
| 136 | break; |
| 137 | case 0x0A: |
| 138 | case 0x0B: //IMAP |
| 139 | rv=3; |
| 140 | break; |
| 141 | case 0x0C: //RPM |
| 142 | rv=4; |
| 143 | break; |
| 144 | case 0x0D: //VSS |
| 145 | case 0x0E: |
| 146 | case 0x0F: //IAT |
| 147 | rv=3; |
| 148 | break; |
| 149 | case 0x10: //MAF |
| 150 | rv=4; |
| 151 | break; |
| 152 | case 0x11: //TPS |
| 153 | case 0x12: |
| 154 | case 0x13: //O2Sloc |
| 155 | rv = 3; |
| 156 | break; |
| 157 | case 0x14: //0x14-0x1B:O2 stuff |
| 158 | case 0x15: |
| 159 | case 0x16: |
| 160 | case 0x17: |
| 161 | case 0x18: |
| 162 | case 0x19: |
| 163 | case 0x1A: |
| 164 | case 0x1B: |
| 165 | rv = 4; |
| 166 | break; |
| 167 | case 0x1C: //OBD |
| 168 | case 0x1D: //O2Sloc |
| 169 | case 0x1E: |
| 170 | rv = 2; |
| 171 | break; |
| 172 | case 0x1F: //RUNTM |
| 173 | rv = 4; |
| 174 | break; |
| 175 | //TODO : PIDS 0x21 etc |
| 176 | default: |
| 177 | /* Sometime add J2190 support (PID>0x1F) */ |
| 178 | rv = DIAG_ERR_BADDATA; |
| 179 | break; |
| 180 | } //PIDs for modes 1 and 2 |
| 181 | //For mode 2 responses, actual length is 1 byte longer than Mode 1 resps because of Frame No |
| 182 | if (mode == 0x42 && rv) { |
| 183 | rv += 1; |
| 184 | } |
| 185 | break; |
| 186 | case 0x43: |
| 187 | rv=7; //6.3.2.4 |
| 188 | break; |
| 189 | case 0x44: |
| 190 | rv = 1; //6.4.2.2 |
| 191 | break; |
| 192 | case 0x45: |
| 193 | if ((data[1] & 0x1f) == 0) { |
| 194 | rv = 7; // Read supported TIDs, 6.5.2.2 |
| 195 | } else if (data[1] <= 4) { |
| 196 | rv=4; //J1979 sec 6.5.2.4 : conditional TIDs. |
| 197 | } else { |
| 198 | rv = 6; // Request TID result |
| 199 | } |
| 200 | break; |
| 201 | case 0x46: |
| 202 | //6.6.2.2 supported PIDs : len=7 |
| 203 | //6.6.2.4 : 7 bytes; last 2 are "conditional" in meaning only, always present ?? |
| 204 | case 0x47: //6.7.2.2 |
| 205 | case 0x48: //6.8.2.1 |
| 206 | rv = 7; |
| 207 | break; |
| 208 | case 0x49: //6.9.1 |
| 209 | if ((data[1] & 0x1f) ==0) { |
| 210 | rv=7; //supported INFOTYPES |
| 211 | } else if (data[1] & 1) { |
| 212 | //INFOTYPE is odd: |
| 213 | rv=7; |
| 214 | } else { |
| 215 | //even |
| 216 | rv=3; |
| 217 | } |
| 218 | break; |
| 219 | default: |
| 220 | break; |
| 221 | } |
| 222 | return rv; |
| 223 | } |
| 224 | |
| 225 | |
| 226 | /* |
| 227 | * Send a J1979 packet - we know the length (from looking at the data) |
| 228 | * since we're L3, we assume msg->data[0] is the mode (service id), i.e. there |
| 229 | * aren't any headers. |
| 230 | */ |
| 231 | static int diag_l3_j1979_send(struct diag_l3_conn *d_l3_conn, struct diag_msg *msg) { |
| 232 | int rv; |
| 233 | struct diag_l2_conn *d_conn; |
| 234 | struct l3_j1979_int *l3i = d_l3_conn->l3_int; |
| 235 | // uint8_t buf[32]; |
| 236 | |
| 237 | /* Get l2 connection info */ |
| 238 | d_conn = d_l3_conn->d_l3l2_conn; |
| 239 | |
| 240 | DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_WRITE, DIAG_DBGLEVEL_V, |
| 241 | FLFMT "send %u bytes, l2 flags 0x%X\n", |
| 242 | FL, msg->len, d_l3_conn->d_l3l2_flags); |
| 243 | |
| 244 | //and make sure src address was set in msg: |
| 245 | if (!msg->src) { |
| 246 | msg->src = 0xF1; |
| 247 | } |
| 248 | |
| 249 | /* Note source address on 1st send */ |
| 250 | if (l3i->src == 0) { |
| 251 | l3i->src = msg->src; |
| 252 | } |
| 253 | |
| 254 | //we can't set destination address because it's L2-defined. |
| 255 | // (iso14230 : dest = 0x33 phys; |
| 256 | // (iso9141 + J1850 : dest = 0x6A ) |
| 257 | |
| 258 | |
| 259 | /* L2 does framing, adds addressing and CRC, so do nothing else*/ |
| 260 | rv = diag_l2_send(d_conn, msg); |
| 261 | |
| 262 | return rv; |
| 263 | } |
| 264 | |
| 265 | /* |
| 266 | * RX callback, called as data received from L2. If we get a full message, |
| 267 | * call L3 callback routine |
| 268 | */ |
| 269 | static void diag_l3_rcv_callback(void *handle, struct diag_msg *msg) { |
| 270 | /* |
| 271 | * Got some data from L2, build it into a L3 message, if |
| 272 | * message is complete call next layer callback routine |
| 273 | */ |
| 274 | struct diag_l3_conn *d_l3_conn = (struct diag_l3_conn *)handle; |
| 275 | struct l3_j1979_int *l3i = d_l3_conn->l3_int; |
| 276 | |
| 277 | DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V, |
| 278 | FLFMT |
| 279 | "rcv_callback for %u bytes fmt 0x%X conn rxoffset %d\n", |
| 280 | FL, msg->len, msg->fmt, l3i->rxoffset); |
| 281 | |
| 282 | if (msg->fmt & DIAG_FMT_FRAMED) { |
| 283 | /* Send data upward if needed */ |
| 284 | if (d_l3_conn->callback) { |
| 285 | d_l3_conn->callback(d_l3_conn->handle, msg); |
| 286 | } |
| 287 | } else { |
| 288 | /* Add data to the receive buffer on the L3 connection */ |
| 289 | memcpy(&l3i->rxbuf[l3i->rxoffset], |
| 290 | msg->data, msg->len); //XXX possible buffer overflow ! |
| 291 | l3i->rxoffset += msg->len; |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | |
| 296 | /* |
| 297 | * Process_data() - this is the routine that works out the framing |
| 298 | * of the data , if recv() was always called at the correct time and |
| 299 | * in the correct way then we would have one and one complete message |
| 300 | * received by the L2 code normally - however, we cant be sure of that |
| 301 | * so we employ this algorithm |
| 302 | * |
| 303 | * Look at the data and try and work out the length of the message based |
| 304 | * on the J1979 protocol. Returns length (excluding headers & checksum !) |
| 305 | * VVVVVVVV |
| 306 | * Note: J1979 doesn't specify particular checksums beyond what 9141 and 14230 already provide, |
| 307 | * i.e. a J1979 message is maximum 7 bytes long except on CANBUS. |
| 308 | * headers, address and checksum are handled and stripped at the l2 level (9141, 14230, etc); |
| 309 | * |
| 310 | * Another validity check is comparing message length (expected vs real); not implemented XXX? |
| 311 | * Upper levels can also verify that the responses correspond to the requests (i.e. Service ID 0x02 -> 0x42 ) |
| 312 | * XXX Broken for the moment because I'm moving the header stuff completely out of L3 |
| 313 | * |
| 314 | */ |
| 315 | static void diag_l3_j1979_process_data(struct diag_l3_conn *d_l3_conn) { |
| 316 | /* Process the received data into messages if complete */ |
| 317 | struct diag_msg *msg; |
| 318 | int sae_msglen; |
| 319 | struct l3_j1979_int *l3i = d_l3_conn->l3_int; |
| 320 | |
| 321 | while (l3i->rxoffset) { |
| 322 | int badpacket=0; |
| 323 | |
| 324 | sae_msglen = diag_l3_j1979_getlen(l3i->rxbuf, |
| 325 | l3i->rxoffset); //set expected packet length based on SID + TID |
| 326 | |
| 327 | DIAG_DBGMDATA(diag_l3_debug, DIAG_DEBUG_PROTO, DIAG_DBGLEVEL_V, |
| 328 | l3i->rxbuf, l3i->rxoffset -1, |
| 329 | FLFMT "process_data rxoffset is %d sae_msglen is %ld; \n", |
| 330 | FL, l3i->rxoffset, (long)sae_msglen); |
| 331 | |
| 332 | if (sae_msglen < 0 || sae_msglen > 255) { |
| 333 | if (sae_msglen == DIAG_ERR_INCDATA) { |
| 334 | /* Not enough data in this frame, this isn't catastrophic */ |
| 335 | return; |
| 336 | } |
| 337 | /* Duff data received, bad news ! */ |
| 338 | badpacket = 1; |
| 339 | } |
| 340 | |
| 341 | if (badpacket || (sae_msglen <= l3i->rxoffset)) { |
| 342 | |
| 343 | /* Bad packet, or full packet, need to tell user */ |
| 344 | uint8_t *data = NULL; |
| 345 | |
| 346 | if (diag_calloc(&msg, 1)) { |
| 347 | /* Stuffed, no memory, cant do anything */ |
| 348 | return; |
| 349 | } |
| 350 | |
| 351 | if (!badpacket) { |
| 352 | if (diag_malloc(&data, (size_t)sae_msglen)) { |
| 353 | free(msg); |
| 354 | return; |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | if (badpacket || (data == NULL)) { |
| 359 | /* Failure indicated by zero len msg */ |
| 360 | msg->data = NULL; |
| 361 | msg->len = 0; |
| 362 | } else { |
| 363 | msg->fmt = DIAG_FMT_ISO_FUNCADDR; |
| 364 | // XXX This won't do at all ! |
| 365 | //msg->type = l3i->rxbuf[0]; //nobody checks this |
| 366 | msg->dest = l3i->rxbuf[1]; |
| 367 | msg->src = l3i->rxbuf[2]; |
| 368 | /* Copy in J1979 part of message */ |
| 369 | memcpy(data, &l3i->rxbuf[3], (size_t)(sae_msglen - 4)); |
| 370 | /* remove whole message from rx buf */ |
| 371 | memmove(l3i->rxbuf, |
| 372 | &l3i->rxbuf[sae_msglen], |
| 373 | (size_t)sae_msglen); |
| 374 | |
| 375 | l3i->rxoffset -= sae_msglen; |
| 376 | |
| 377 | msg->data = data; |
| 378 | msg->len = (uint8_t) sae_msglen - 4; |
| 379 | } |
| 380 | |
| 381 | msg->rxtime = diag_os_getms(); |
| 382 | |
| 383 | /* Add it to the list */ |
| 384 | LL_CONCAT(d_l3_conn->msg, msg); |
| 385 | |
| 386 | if (badpacket) { |
| 387 | /* No point in continuing */ |
| 388 | break; |
| 389 | } |
| 390 | } else { |
| 391 | /* Need some more data */ |
| 392 | break; |
| 393 | } |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | /* |
| 398 | * Receive a J1979 frame (building it as we get small amounts of data) |
| 399 | * |
| 400 | * - timeout expiry will cause return before complete packet |
| 401 | * |
| 402 | * Successful packet receive will call the callback routine with the message |
| 403 | * XXX currently broken because I'm halfway through modifying _process_data |
| 404 | */ |
| 405 | static int diag_l3_j1979_recv(struct diag_l3_conn *d_l3_conn, unsigned int timeout, |
| 406 | void (* rcv_call_back)(void *handle,struct diag_msg *), void *handle) { |
| 407 | int rv; |
| 408 | struct diag_msg *msg; |
| 409 | unsigned int tout; |
| 410 | int state; |
| 411 | //State machine: |
| 412 | #define ST_STATE1 1 // timeout=0 to get data already in buffer |
| 413 | #define ST_STATE2 2 |
| 414 | #define ST_STATE3 3 |
| 415 | #define ST_STATE4 4 |
| 416 | |
| 417 | if (d_l3_conn->d_l3l2_flags & DIAG_L2_FLAG_FRAMED) { |
| 418 | /* |
| 419 | * L2 does framing stuff , which means we get one message |
| 420 | * with nicely formed frames |
| 421 | */ |
| 422 | state = ST_STATE4; |
| 423 | } else { |
| 424 | state = ST_STATE1; |
| 425 | } |
| 426 | |
| 427 | /* Store the callback routine for use if needed */ |
| 428 | d_l3_conn->callback = rcv_call_back; |
| 429 | d_l3_conn->handle = handle; |
| 430 | |
| 431 | /* |
| 432 | * This works by doing a read with a timeout of 0, to collect |
| 433 | * any data that was present on the link, if no messages complete |
| 434 | * then read with the normal timeout, then read with a timeout |
| 435 | * of p4max ms until no more data is left (or timeout), then call |
| 436 | * the callback routine (if there is a complete message) |
| 437 | */ |
| 438 | while (1) { |
| 439 | /* State machine for setting timeout values */ |
| 440 | switch (state) { |
| 441 | case ST_STATE1: |
| 442 | tout = 0; |
| 443 | break; |
| 444 | case ST_STATE2: |
| 445 | tout = timeout; |
| 446 | break; |
| 447 | case ST_STATE3: |
| 448 | tout = 5; /* XXX should be p4max */ |
| 449 | break; |
| 450 | case ST_STATE4: |
| 451 | tout = timeout; |
| 452 | break; |
| 453 | default: |
| 454 | break; |
| 455 | } |
| 456 | |
| 457 | DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_PROTO, DIAG_DBGLEVEL_V, |
| 458 | FLFMT "recv state %d tout %u\n", |
| 459 | FL, state, tout); |
| 460 | |
| 461 | /* |
| 462 | * Call L2 receive, L2 will build up the datapacket and |
| 463 | * call the callback routine if needed, we use a timeout |
| 464 | * of zero to see if data exists *now*, |
| 465 | */ |
| 466 | rv = diag_l2_recv(d_l3_conn->d_l3l2_conn, tout, |
| 467 | diag_l3_rcv_callback, (void *)d_l3_conn); |
| 468 | |
| 469 | DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_PROTO, DIAG_DBGLEVEL_V, |
| 470 | FLFMT "recv returns %d\n", FL, rv); |
| 471 | |
| 472 | if ((rv < 0) && (rv != DIAG_ERR_TIMEOUT)) { |
| 473 | break; /* Some nasty failure */ |
| 474 | } |
| 475 | |
| 476 | if (rv == DIAG_ERR_TIMEOUT) { |
| 477 | if ( (state == ST_STATE3) || (state == ST_STATE4) ) { |
| 478 | /* Finished */ |
| 479 | break; |
| 480 | } |
| 481 | if ( (state == ST_STATE1) && (d_l3_conn->msg == NULL) ) { |
| 482 | /* |
| 483 | * Try again, with real timeout |
| 484 | * (and thus sleep) |
| 485 | */ |
| 486 | state = ST_STATE2; |
| 487 | tout = timeout; |
| 488 | continue; |
| 489 | } |
| 490 | } |
| 491 | |
| 492 | if (state != ST_STATE4) { |
| 493 | /* Process the data into messages */ |
| 494 | diag_l3_j1979_process_data(d_l3_conn); |
| 495 | |
| 496 | DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_PROTO, DIAG_DBGLEVEL_V, |
| 497 | FLFMT "recv process_data called, msg %p\n", |
| 498 | FL, (void *)d_l3_conn->msg); |
| 499 | |
| 500 | /* |
| 501 | * If there is a full message, remove it, call back |
| 502 | * the user call back routine with it, and free it |
| 503 | */ |
| 504 | msg = d_l3_conn->msg; |
| 505 | if (msg) { |
| 506 | d_l3_conn->msg = msg->next; |
| 507 | |
| 508 | rcv_call_back(handle, msg); |
| 509 | diag_freemsg(msg); |
| 510 | rv = 0; |
| 511 | /* And quit while we are ahead */ |
| 512 | break; |
| 513 | } |
| 514 | } |
| 515 | /* We do not have a complete message (yet) */ |
| 516 | if (state == ST_STATE2) { |
| 517 | /* Part message, see if we get some more */ |
| 518 | state = ST_STATE3; |
| 519 | } |
| 520 | if (state == ST_STATE1) { |
| 521 | /* Ok, try again with proper timeout */ |
| 522 | state = ST_STATE2; |
| 523 | } |
| 524 | if ((state == ST_STATE3) || (state == ST_STATE4)) { |
| 525 | /* Finished, we only do read once in this state */ |
| 526 | break; |
| 527 | } |
| 528 | } |
| 529 | |
| 530 | return rv; |
| 531 | } |
| 532 | |
| 533 | |
| 534 | |
| 535 | /* |
| 536 | * This is called without the ADDR_ADDR_1 on it, ie it contains |
| 537 | * just the SAEJ1979 data |
| 538 | * Returns a string with the description + data associated with a J1979 message. |
| 539 | * Doesn't do any data scaling / conversion. |
| 540 | */ |
| 541 | |
| 542 | void diag_l3_j1979_decode(UNUSED(struct diag_l3_conn *d_l3_conn), |
| 543 | struct diag_msg *msg, char *buf, size_t bufsize) { |
| 544 | unsigned i, j; |
| 545 | |
| 546 | char buf2[80]; |
| 547 | |
| 548 | char area; //for DTCs |
| 549 | |
| 550 | if (msg->data[0] & 0x40) { |
| 551 | snprintf(buf, bufsize, "J1979 response "); |
| 552 | } else { |
| 553 | snprintf(buf, bufsize, "J1979 request "); |
| 554 | } |
| 555 | |
| 556 | switch (msg->data[0]) { |
| 557 | case 0x01: |
| 558 | snprintf(buf2, sizeof(buf2), "Mode 1 PID 0x%02X", msg->data[1]); |
| 559 | smartcat(buf, bufsize, buf2); |
| 560 | break; |
| 561 | case 0x41: |
| 562 | snprintf(buf2, sizeof(buf2),"Mode 1 Data: PID 0x%02X ", msg->data[1]); |
| 563 | smartcat(buf, bufsize, buf2); |
| 564 | for (i=2; i < msg->len; i++) { |
| 565 | snprintf(buf2, sizeof(buf2), "0x%02X ", msg->data[i]); |
| 566 | smartcat(buf, bufsize, buf2); |
| 567 | } |
| 568 | break; |
| 569 | case 0x02: |
| 570 | snprintf(buf2, sizeof(buf2), "Mode 2 PID 0x%02X Frame 0x%02X", msg->data[1], |
| 571 | msg->data[2]); |
| 572 | smartcat(buf, bufsize, buf2); |
| 573 | break; |
| 574 | case 0x42: |
| 575 | snprintf(buf2, sizeof(buf2),"Mode 2 FreezeFrame Data: PID 0x%02X Frame 0x%02X ", |
| 576 | msg->data[1], msg->data[2]); |
| 577 | smartcat(buf, bufsize, buf2); |
| 578 | for (i=3; i < msg->len; i++) { |
| 579 | snprintf(buf2, sizeof(buf2), "0x%02X ", msg->data[i]); |
| 580 | smartcat(buf, bufsize, buf2); |
| 581 | } |
| 582 | break; |
| 583 | case 0x03: |
| 584 | snprintf(buf2, sizeof(buf2),"Mode 3 (Powertrain DTCs)"); |
| 585 | smartcat(buf, bufsize, buf2); |
| 586 | break; |
| 587 | case 0x07: |
| 588 | snprintf(buf2, sizeof(buf2), |
| 589 | "Request Non-Continuous Monitor System Test Results"); |
| 590 | smartcat(buf, bufsize, buf2); |
| 591 | break; |
| 592 | case 0x47: |
| 593 | snprintf(buf2, sizeof(buf2), "Non-Continuous Monitor System "); |
| 594 | smartcat(buf, bufsize, buf2); |
| 595 | /* Fallthru */ |
| 596 | case 0x43: |
| 597 | snprintf(buf2, sizeof(buf2),"DTCs: "); |
| 598 | smartcat(buf, bufsize, buf2); |
| 599 | for (i=0, j=1; i<3; i++, j+=2) { |
| 600 | if ((msg->data[j] == 0) && |
| 601 | (msg->data[j + 1] == 0)) { |
| 602 | continue; |
| 603 | } |
| 604 | |
| 605 | switch ((msg->data[j] >> 6) & 0x03) { |
| 606 | case 0: |
| 607 | area = 'P'; |
| 608 | break; |
| 609 | case 1: |
| 610 | area = 'C'; |
| 611 | break; |
| 612 | case 2: |
| 613 | area = 'B'; |
| 614 | break; |
| 615 | case 3: |
| 616 | area = 'U'; |
| 617 | break; |
| 618 | default: |
| 619 | fprintf(stderr, "Illegal msg->data[%u] value\n", j); |
| 620 | area = 'X'; |
| 621 | break; |
| 622 | } |
| 623 | snprintf(buf2, sizeof(buf2), "%c%02X%02X ", area, msg->data[j] & 0x3f, |
| 624 | msg->data[j+1]&0xff); |
| 625 | smartcat(buf, bufsize, buf2); |
| 626 | } |
| 627 | break; |
| 628 | case 0x04: |
| 629 | snprintf(buf2, sizeof(buf2), "Clear DTCs"); |
| 630 | smartcat(buf, bufsize, buf2); |
| 631 | break; |
| 632 | case 0x44: |
| 633 | snprintf(buf2, sizeof(buf2), "DTCs cleared"); |
| 634 | smartcat(buf, bufsize, buf2); |
| 635 | break; |
| 636 | case 0x05: |
| 637 | snprintf(buf2, sizeof(buf2), "Oxygen Sensor Test ID 0x%02X Sensor 0x%02X", |
| 638 | msg->data[1], msg->data[2]); |
| 639 | smartcat(buf, bufsize, buf2); |
| 640 | break; |
| 641 | case 0x45: |
| 642 | snprintf(buf2, sizeof(buf2), "Oxygen Sensor TID 0x%02X Sensor 0x%02X ", |
| 643 | msg->data[1], msg->data[2]); |
| 644 | smartcat(buf, bufsize, buf); |
| 645 | for (i=3; i < msg->len; i++) { |
| 646 | snprintf(buf2, sizeof(buf2), "0x%02X ", msg->data[i]); |
| 647 | smartcat(buf, bufsize, buf2); |
| 648 | } |
| 649 | break; |
| 650 | case 0x06: |
| 651 | snprintf(buf2, sizeof(buf2), "Onboard monitoring test request TID 0x%02X", msg->data[1]); |
| 652 | smartcat(buf, bufsize, buf2); |
| 653 | break; |
| 654 | case 0x46: |
| 655 | snprintf(buf2, sizeof(buf2),"Onboard monitoring test result TID 0x%02X ", msg->data[1]); |
| 656 | smartcat(buf, bufsize, buf2); |
| 657 | for (i=2; i < msg->len; i++) { |
| 658 | snprintf(buf2, sizeof(buf2), "0x%02X ", msg->data[i]); |
| 659 | smartcat(buf, bufsize, buf2); |
| 660 | } |
| 661 | break; |
| 662 | case 0x08: |
| 663 | snprintf(buf2, sizeof(buf2), "Request control of onboard system TID 0x%02X", msg->data[1]); |
| 664 | smartcat(buf, bufsize, buf2); |
| 665 | break; |
| 666 | case 0x48: |
| 667 | snprintf(buf2, sizeof(buf2), "Control of onboard system response TID 0x%02X ", msg->data[1]); |
| 668 | smartcat(buf, bufsize, buf2); |
| 669 | for (i=2; i < msg->len; i++) { |
| 670 | snprintf(buf2, sizeof(buf2), "0x%02X ", msg->data[i]); |
| 671 | smartcat(buf, bufsize, buf2); |
| 672 | } |
| 673 | break; |
| 674 | case 0x09: |
| 675 | snprintf(buf2, sizeof(buf2), "Request vehicle information infotype 0x%02X", msg->data[1]); |
| 676 | smartcat(buf, bufsize, buf2); |
| 677 | break; |
| 678 | case 0x49: |
| 679 | snprintf(buf2, sizeof(buf2), "Vehicle information infotype 0x%02X ", msg->data[1]); |
| 680 | smartcat(buf, bufsize, buf2); |
| 681 | for (i=2; i < msg->len; i++) { |
| 682 | snprintf(buf2, sizeof(buf2), "0x%02X ", msg->data[i]); |
| 683 | smartcat(buf, bufsize, buf2); |
| 684 | } |
| 685 | break; |
| 686 | default: |
| 687 | snprintf(buf2, sizeof(buf2),"UnknownType 0x%02X: Data Dump: ", msg->data[0]); |
| 688 | smartcat(buf, bufsize, buf2); |
| 689 | for (i=0; i < msg->len; i++) { |
| 690 | snprintf(buf2, sizeof(buf2), "0x%02X ", msg->data[i]); |
| 691 | smartcat(buf, bufsize, buf2); |
| 692 | } |
| 693 | } |
| 694 | return; |
| 695 | } |
| 696 | |
| 697 | |
| 698 | //Send a service 1, pid 0 request and check for a valid reply. |
| 699 | //ret 0 if ok |
| 700 | static int diag_l3_j1979_keepalive(struct diag_l3_conn *d_l3_conn) { |
| 701 | struct diag_msg msg = {0}; |
| 702 | struct diag_msg *rxmsg; |
| 703 | uint8_t data[6]; |
| 704 | int errval; |
| 705 | struct l3_j1979_int *l3i = d_l3_conn->l3_int; |
| 706 | |
| 707 | /* |
| 708 | * Service 1 Pid 0 request is the SAEJ1979 idle message |
| 709 | * XXX Need to get the address bytes correct |
| 710 | */ |
| 711 | msg.len = 2; |
| 712 | data[0] = 1; /* Mode 1 */ |
| 713 | data[1] = 0; /* Pid 0 */ |
| 714 | msg.data = data; |
| 715 | |
| 716 | /* |
| 717 | * And set the source address, if no sends have happened, then |
| 718 | * the src address will be 0, so use the default used in J1979 |
| 719 | */ |
| 720 | if (l3i->src) { |
| 721 | msg.src = l3i->src; |
| 722 | } else { |
| 723 | msg.src = 0xF1; /* Default as used in SAE J1979 */ |
| 724 | } |
| 725 | |
| 726 | /* Send it: using l3_request() makes sure the connection's timestamp is updated */ |
| 727 | rxmsg=diag_l3_request(d_l3_conn, &msg, &errval); |
| 728 | |
| 729 | if (rxmsg == NULL) { |
| 730 | return diag_ifwderr(errval); |
| 731 | } |
| 732 | |
| 733 | DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_PROTO, DIAG_DBGLEVEL_V, |
| 734 | FLFMT "keepalive : got %u bytes, %02X ...\n", |
| 735 | FL, rxmsg->len, rxmsg->data[0]); |
| 736 | |
| 737 | /* Check if its a valid SID 1 PID 0 response */ |
| 738 | if ((rxmsg->len < 1) || (rxmsg->data[0] != 0x41)) { |
| 739 | diag_freemsg(rxmsg); |
| 740 | return diag_iseterr(DIAG_ERR_ECUSAIDNO); |
| 741 | } |
| 742 | |
| 743 | diag_freemsg(rxmsg); |
| 744 | return 0; |
| 745 | |
| 746 | } |
| 747 | |
| 748 | //_start : send service 1 pid 0 request (J1979 keepalive); according to SAE J1979 (p.7) : |
| 749 | // " IMPORTANT - All emissions-related OBD ECUs which at least support one of the services defined in this |
| 750 | // document shall support service $01 and PID $00. Service $01 with PID $00 is defined as the universal |
| 751 | // "initialisation/keep alive/ping" message for all emissions-related OBD ECUs. " |
| 752 | //That sounds like a sure-fire way to make sure we have a succesful connection to a J1979-compliant ECU. |
| 753 | int diag_l3_j1979_start(struct diag_l3_conn *d_l3_conn) { |
| 754 | int rv; |
| 755 | struct l3_j1979_int *l3i; |
| 756 | |
| 757 | assert(d_l3_conn != NULL); |
| 758 | |
| 759 | rv = diag_calloc(&l3i, 1); |
| 760 | if (rv != 0) { |
| 761 | return diag_ifwderr(rv); |
| 762 | } |
| 763 | |
| 764 | d_l3_conn->l3_int = l3i; |
| 765 | |
| 766 | rv=diag_l3_j1979_keepalive(d_l3_conn); |
| 767 | |
| 768 | if (rv<0) { |
| 769 | fprintf(stderr, FLFMT "J1979 Keepalive failed ! Try to disconnect and reconnect.\n", FL); |
| 770 | free(l3i); |
| 771 | return diag_ifwderr(rv); |
| 772 | } |
| 773 | |
| 774 | |
| 775 | return 0; |
| 776 | } |
| 777 | |
| 778 | /* Stop communications : nothing defined, other than letting the link timeout (L2 defined). */ |
| 779 | int dl3_j1979_stop(struct diag_l3_conn *d_l3_conn) { |
| 780 | assert(d_l3_conn != NULL); |
| 781 | free(d_l3_conn->l3_int); |
| 782 | return 0; |
| 783 | } |
| 784 | |
| 785 | /* |
| 786 | * Timer routine, called with time (in ms) since the "timer" value in |
| 787 | * the L3 structure |
| 788 | * return 0 if ok |
| 789 | */ |
| 790 | static int diag_l3_j1979_timer(struct diag_l3_conn *d_l3_conn, unsigned long ms) { |
| 791 | int rv; |
| 792 | int debug_l2_orig=diag_l2_debug; //save debug flags; disable them for this procedure |
| 793 | int debug_l1_orig=diag_l1_debug; |
| 794 | |
| 795 | /* J1979 needs keepalive at least every 5 seconds (P3), we use 3.5s */ |
| 796 | |
| 797 | assert(d_l3_conn != NULL); |
| 798 | if (ms < J1979_KEEPALIVE) { |
| 799 | return 0; |
| 800 | } |
| 801 | |
| 802 | /* Does L2 do keepalive for us ? */ |
| 803 | if (d_l3_conn->d_l3l2_flags & DIAG_L2_FLAG_KEEPALIVE) { |
| 804 | return 0; |
| 805 | } |
| 806 | |
| 807 | /* OK, do keep alive on this connection */ |
| 808 | /* XXX Not async-signal-safe */ |
| 809 | DIAG_DBGM(diag_l3_debug, DIAG_DEBUG_TIMER, DIAG_DBGLEVEL_V, |
| 810 | FLFMT "\nP3 timeout impending for %p %lu ms\n", |
| 811 | FL, (void *)d_l3_conn, ms); |
| 812 | |
| 813 | diag_l2_debug=0; //disable |
| 814 | diag_l1_debug=0; |
| 815 | |
| 816 | rv=diag_l3_j1979_keepalive(d_l3_conn); |
| 817 | |
| 818 | if (rv<0) { |
| 819 | fprintf(stderr, FLFMT "J1979 Keepalive failed ! Try to disconnect and reconnect.\n", FL); |
| 820 | } |
| 821 | |
| 822 | diag_l2_debug=debug_l2_orig; //restore debug flags |
| 823 | diag_l1_debug=debug_l1_orig; |
| 824 | |
| 825 | return rv; |
| 826 | } |
| 827 | |
| 828 | const struct diag_l3_proto diag_l3_j1979 = { |
| 829 | "SAEJ1979", |
| 830 | diag_l3_j1979_start, |
| 831 | dl3_j1979_stop, |
| 832 | diag_l3_j1979_send, |
| 833 | diag_l3_j1979_recv, |
| 834 | NULL, //ioctl |
| 835 | diag_l3_base_request, |
| 836 | diag_l3_j1979_decode, |
| 837 | diag_l3_j1979_timer |
| 838 | }; |
| 839 | |