📄 trouble_code_reader.c
字号:
ret = ret + (temp & 0x7F);
}
else
break;
}
return ret;
}
int parse_dtcs(const char *response, int pending)
{
char code_letter[] = "PCBU";
int dtc_count = 0;
int i, j;
TROUBLE_CODE temp_trouble_code;
for(i = 0; i < strlen(response); i += 4) // read codes
{
temp_trouble_code.code[0] = ' '; // make first position a blank space
// begin to copy from response to temp_trouble_code.code beginning with position #1
for (j = 1; j < 5; j++)
temp_trouble_code.code[j] = response[i+j-1];
temp_trouble_code.code[j] = '\0'; // terminate string
if (strcmp(temp_trouble_code.code, " 0000") == 0) // if there's no trouble code,
break; // break out of the for() loop
// begin with position #1 (skip blank space), convert to hex, extract first two bits
// use the result as an index into the code_letter array to get the corresponding code letter
temp_trouble_code.code[0] = code_letter[strtol(temp_trouble_code.code + 1, NULL, 16) >> 14];
temp_trouble_code.code[1] = (strtol(temp_trouble_code.code + 1, NULL, 16) >> 12) & 0x03;
temp_trouble_code.code[1] += 0x30; // convert to ASCII
if (pending)
{
temp_trouble_code.code[5] = '*';
temp_trouble_code.code[6] = 0;
temp_trouble_code.pending = TRUE;
}
else
temp_trouble_code.pending = FALSE;
temp_trouble_code.description = NULL; // clear the corresponding description...
temp_trouble_code.solution = NULL; // ..and solution
add_trouble_code(&temp_trouble_code);
dtc_count++;
}
return dtc_count;
}
/* NOTE:
* ELM327 multi-message CAN responses are parsed using the following assumptions:
* - max 8 ECUs (per ISO15765-4 standard)
* - max 51 DTCs per ECU - there is no way to tell which ECU a response belongs to when the message counter wraps (0-F)
* - ECUs respond sequentially (i.e. 2nd msg from the 1st ECU to respond will come before 2nd msg from the 2nd ECU to respond)
* This has been observed imperically (in fact most of the time 2nd ECU lags several messages behind the 1st ECU),
* this should be true for most cases due to arbitration, unless 1st ECU takes a very long time to prepare next message,
* which should not happen. There is no other choice at the moment, unless we turn on headers, but that would mean rewriting
* whole communication paradigm.
*/
int handle_read_codes(char *vehicle_response, int pending)
{
int dtc_count = 0;
char *start = vehicle_response;
char filter[3];
char msg[48];
int can_resp_cnt = 0;
int can_msg_cnt = 0;
int can_resp_len[8];
char *can_resp_buf[8]; // 8 CAN ECUs max
int buf_len, max_len, trim;
int i, j;
// First, look for non-CAN and single-message CAN responses
strcpy(filter, (pending) ? "47" : "43");
while (find_valid_response(msg, start, filter, &start))
{
if (strlen(msg) == 4) // skip '4X 00' CAN responses
continue;
// if even number of bytes (CAN), skip first 2 bytes, otherwise, skip 1 byte
i = (((strlen(msg)/2) & 0x01) == 0) ? 4 : 2;
dtc_count += parse_dtcs(msg + i, pending);
}
// Look for CAN multi-message responses
start = vehicle_response;
while (find_valid_response(msg, start, "", &start)) // step through all responses
{
if (strlen(msg) == 3) // we're looking for 3-byte response length messages
{
can_resp_len[can_resp_cnt] = strtol(msg, NULL, 16); // get total length for the response
can_resp_buf[can_resp_cnt] = calloc((can_resp_len[can_resp_cnt]-2)*2 + 1, sizeof(char));
i = ceil((float)(can_resp_len[can_resp_cnt] + 1) / 7); // calculate number of messages necessary to transmit specified number of bytes
can_msg_cnt = MAX(can_msg_cnt, i); // calculate max number of messages for any response
can_resp_cnt++;
}
}
for (i = 0; i < can_msg_cnt; i++)
{
j = 0;
start = vehicle_response;
sprintf(filter, "%X:", i);
while (find_valid_response(msg, start, filter, &start))
{
for (; j < can_resp_cnt; j++) // find next response that is not full
{
buf_len = strlen(can_resp_buf[j]);
max_len = (can_resp_len[j]-2)*2;
if (buf_len < max_len)
{
// first response -- skip '0:4XXX', all other -- skip 'X:'
// first response -- 6 bytes total, all other -- 7 bytes
// if this is last message for a response, trim padding
trim = (buf_len + strlen(msg) - 2 >= max_len) ? buf_len + strlen(msg) - 2 - max_len : 0;
strncat(can_resp_buf[j], msg + ((i == 0) ? 6 : 2), (i == 0) ? 8 : 14 - trim);
j++;
break;
}
}
}
}
for (i = 0; i < can_resp_cnt; i++)
{
dtc_count += parse_dtcs(can_resp_buf[i], pending);
free(can_resp_buf[i]);
}
return dtc_count; // return the actual number of codes read
}
void populate_trouble_codes_list()
{
char character;
int i, j, min;
char temp_buf[1024];
TROUBLE_CODE *trouble_code;
int count = get_number_of_codes();
PACKFILE *code_def_file;
if (count == 0)
return;
for (i = 0; i < count; i++) // sort codes in ascending order
{
min = i;
for (j = i+1; j < count; j++)
if(strcmp(get_trouble_code(j)->code, get_trouble_code(min)->code) < 0)
min = j;
swap_codes(get_trouble_code(i), get_trouble_code(min));
}
for (trouble_code = trouble_codes; trouble_code; trouble_code = trouble_code->next) // search for descriptions and solutions
{
// pass the letter (B, C, P, or U) to file_handle, which returns the file handle
// if we reached EOF, or the file does not exist, go to the next DTC
if ((code_def_file = file_handle(trouble_code->code[0])) == NULL)
continue;
while (TRUE)
{
j = 0;
// copy DTC from file to temp_buf
while (((character = pack_getc(code_def_file)) != FIELD_DELIMITER) && (character != RECORD_DELIMITER) && (character != EOF))
{
temp_buf[j] = character;
j++;
}
temp_buf[j] = '\0';
if (character == EOF) // reached end of file, break out of while()
break; // advance to next code
if (strncmp(trouble_code->code, temp_buf, 5) == 0) // if we found the code,
{
if (character == RECORD_DELIMITER) // reached end of record, no description or solution,
break; // break out of while(), advance to next code
j = 0;
//copy description from file to temp_buf
while (((character = pack_getc(code_def_file)) != FIELD_DELIMITER) && (character != RECORD_DELIMITER) && (character != EOF))
{
temp_buf[j] = character;
j++;
}
temp_buf[j] = '\0'; // terminate string
if (j > 0)
{
if (!(trouble_code->description = (char *)malloc(sizeof(char)*(j + 1 + ((trouble_code->pending) ? 10 : 0)))))
{
sprintf(temp_error_buf, "Could not allocate enough memory for trouble code description [%i]", count);
fatal_error(temp_error_buf);
}
if (trouble_code->pending)
{
strcpy(trouble_code->description, "[Pending]\n");
strcpy(trouble_code->description + 10, temp_buf); // copy description from temp_buf
}
else
strcpy(trouble_code->description, temp_buf); // copy description from temp_buf
}
if (character == FIELD_DELIMITER) // if we have solution,
{
j = 0;
// copy solution from file to temp_buf
while (((character = pack_getc(code_def_file)) != RECORD_DELIMITER) && (character != EOF))
{
temp_buf[j] = character;
j++;
}
temp_buf[j] = '\0'; // terminate string
if (j > 0)
{
if (!(trouble_code->solution = (char *)malloc(sizeof(char)*(j+1))))
{
sprintf(temp_error_buf, "Could not allocate enough memory for trouble code solution [%i]", count);
fatal_error(temp_error_buf);
}
strcpy(trouble_code->solution, temp_buf); // copy solution from temp_buf
}
}
break; // break out of while(TRUE)
}
else
{
// skip to next record
while (((character = pack_getc(code_def_file)) != RECORD_DELIMITER) && (character != EOF));
if (character == EOF)
break; // break out of while(TRUE), advance to next code
}
} // end of while(TRUE)
} // end of for() loop
file_handle(0); // close the code definition file if it's still open
}
void handle_errors(int error, int operation)
{
static int retry_attempts = NUM_OF_RETRIES;
if (error == BUS_ERROR || error == UNABLE_TO_CONNECT || error == BUS_INIT_ERROR)
{
display_error_message(error, FALSE);
retry_attempts = NUM_OF_RETRIES;
clear_trouble_codes();
num_of_codes_reported = 0;
mil_is_on = FALSE;
broadcast_dialog_message(MSG_READY, 0); // tell everyone that we're done
}
else // if we received "BUS BUSY", "DATA ERROR", "<DATA ERROR", SERIAL_ERROR, or RUBBISH,
{ // try to re-send the request, do nothing if successful and alert user if failed:
if(retry_attempts > 0) //
{
retry_attempts--;
switch (operation)
{
case READ_CODES:
case READ_PENDING:
case NUM_OF_CODES: // if we are currently reading codes,
broadcast_dialog_message(MSG_READ_CODES, 0); // try reading again
break;
case CLEAR_CODES: // if we are currently clearing codes,
broadcast_dialog_message(MSG_CLEAR_CODES, 0); // try clearing again
break;
}
}
else
{
display_error_message(error, FALSE);
retry_attempts = NUM_OF_RETRIES; // reset the number of retry attempts
clear_trouble_codes();
num_of_codes_reported = 0;
mil_is_on = FALSE;
broadcast_dialog_message(MSG_READY, 0); // tell everyone that we're done
}
}
}
void swap_codes(TROUBLE_CODE *code1, TROUBLE_CODE *code2)
{
char temp_str[256];
int temp_int;
temp_int = code1->pending;
strcpy(temp_str, code1->code);
code1->pending = code2->pending;
strcpy(code1->code, code2->code);
code2->pending = temp_int;
strcpy(code2->code, temp_str);
}
void add_trouble_code(const TROUBLE_CODE * init_code)
{
TROUBLE_CODE *next = trouble_codes;
if (!(trouble_codes = (TROUBLE_CODE *)malloc(sizeof(TROUBLE_CODE))))
fatal_error("Could not allocate enough memory for new trouble code");
if (init_code)
{
strcpy(trouble_codes->code, init_code->code);
trouble_codes->description = init_code->description;
trouble_codes->solution = init_code->solution;
trouble_codes->pending = init_code->pending;
}
else
{
trouble_codes->code[0] = 0;
trouble_codes->description = NULL;
trouble_codes->solution = NULL;
trouble_codes->pending = FALSE;
}
trouble_codes->next = next;
}
TROUBLE_CODE *get_trouble_code(int index)
{
int i;
TROUBLE_CODE *trouble_code = trouble_codes;
for(i = 0; i < index; i++)
{
if (trouble_code->next == NULL)
return NULL;
trouble_code = trouble_code->next;
}
return trouble_code;
}
int get_number_of_codes()
{
TROUBLE_CODE *trouble_code = trouble_codes;
int ret = 0;
while(trouble_code)
{
trouble_code = trouble_code->next;
ret++;
}
return ret;
}
void clear_trouble_codes()
{
TROUBLE_CODE *next;
while (trouble_codes)
{
next = trouble_codes->next;
if (trouble_codes->description)
free(trouble_codes->description);
if (trouble_codes->solution)
free(trouble_codes->solution);
free(trouble_codes);
trouble_codes = next;
}
}
PACKFILE *file_handle(char code_letter)
{
static PACKFILE *file = NULL;
static char current_code_letter = 0;
char file_name[30];
if (code_letter == 0)
{
current_code_letter = 0;
if (file != NULL)
pack_fclose(file);
file = NULL;
}
else if (code_letter != current_code_letter)
{
if (file != NULL)
{
pack_fclose(file);
file = NULL;
}
sprintf(file_name, "%s#%ccodes", code_defs_file_name, tolower(code_letter));
packfile_password(PASSWORD);
file = pack_fopen(file_name, F_READ_PACKED);
packfile_password(NULL);
current_code_letter = code_letter;
}
if (file == NULL)
return NULL;
if (pack_feof(file) == TRUE)
return NULL;
return file;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -