📄 trouble_code_reader.c
字号:
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "globals.h"
#include "serial.h"
#include "options.h"
#include "custom_gui.h"
#include "error_handlers.h"
#include "trouble_code_reader.h"
#define MSG_READ_CODES MSG_USER
#define MSG_CLEAR_CODES MSG_USER+1
#define MSG_READY MSG_USER+2
#define CRQ_NONE 0
#define NUM_OF_CODES 1
#define READ_CODES 2
#define READ_PENDING 3
#define CLEAR_CODES 4
#define FIELD_DELIMITER '\t'
#define RECORD_DELIMITER 0xA
#define SIM_CODES_STRING "43012507360455\n43114301960234\n43044302990357\n43C001C101C106"
#define NUM_OF_RETRIES 3
#define CLEAR_CODES_WARNING \
"This will reset the MIL and clear all emission-related diagnostic information, including:\n\n\
- Diagnostic trouble codes\n\
- Freeze frame data\n\
- Oxygen sensor test data\n\
- Status of system monitoring tests\n\
- On-board monitoring tests results\n\
- Distance travelled while MIL activated\n\
- Number of warm-ups since DTCs cleared\n\
- Distance travelled since DTCs cleared\n\
- Engine run time while MIL activated\n\
- Time since DTCs cleared\n\n\
Other manufacturer-specific \"clearing/resetting\" actions may occur. The loss of data may cause \
the vehicle to run poorly for a short period of time while the ECU recalibrates itself."
typedef struct TROUBLE_CODE
{
char code[7];
char *description;
char *solution;
int pending;
struct TROUBLE_CODE *next;
} TROUBLE_CODE;
static char mfr_code_description[] = "Manufacturer-specific code. Please refer to your vehicle's service manual for more information";
static char mfr_pending_code_description[] = "[Pending]\nManufacturer-specific code. Please refer to your vehicle's service manual for more information";
static char code_no_description[] = "";
static char pending_code_no_description[] = "[Pending]";
static int num_of_codes_reported = 0;
static int current_code_index;
static int simulate = FALSE;
static int mil_is_on; // MIL is ON or OFF
static TROUBLE_CODE *trouble_codes = NULL;
static void add_trouble_code(const TROUBLE_CODE *);
static TROUBLE_CODE *get_trouble_code(int index);
static int get_number_of_codes();
static void clear_trouble_codes();
// procedure definitions:
static int tr_code_proc(int msg, DIALOG *d, int c);
static int mil_status_proc(int msg, DIALOG *d, int c);
static int mil_text_proc(int msg, DIALOG *d, int c);
static int simulate_proc(int msg, DIALOG *d, int c);
static int is_mfr_code(const char *code);
static int num_of_codes_proc(int msg, DIALOG *d, int c);
static int code_list_proc(int msg, DIALOG *d, int c);
static char *code_list_getter(int index, int *list_size);
static int read_tr_codes_proc(int msg, DIALOG *d, int c);
static int clear_codes_proc(int msg, DIALOG *d, int c);
static int tr_description_proc(int msg, DIALOG *d, int c);
static int tr_solution_proc(int msg, DIALOG *d, int c);
static int current_code_proc(int msg, DIALOG *d, int c);
// function definitions:
static void read_codes();
static void trouble_codes_simulator(int show);
static int handle_num_of_codes(char *);
static int handle_read_codes(char *, int);
static void populate_trouble_codes_list();
static void swap_codes(TROUBLE_CODE *, TROUBLE_CODE *);
static void handle_errors(int error, int operation);
static PACKFILE *file_handle(char code_letter);
static DIALOG read_codes_dialog[] =
{
/* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
{ d_clear_proc, 0, 0, 0, 0, 0, C_WHITE, 0, 0, 0, 0, NULL, NULL, NULL },
{ d_box_proc, 25, 25, 112, 24, C_BLACK, C_DARK_GRAY, 0, 0, 0, 0, NULL, NULL, NULL },
{ code_list_proc, 25, 96, 112, 208, C_BLACK, C_LIGHT_GRAY, 0, 0, 0, 0, code_list_getter, NULL, NULL },
{ caption_proc, 81, 28, 54, 19, C_WHITE, C_TRANSP, 0, 0, 0, 0, "Current DTC", NULL, NULL },
{ d_box_proc, 25, 49, 112, 40, C_BLACK, C_LIGHT_GRAY, 0, 0, 0, 0, NULL, NULL, NULL },
{ current_code_proc, 81, 57, 54, 24, C_BLACK, C_LIGHT_GRAY, 0, 0, 0, 0, NULL, NULL, NULL },
{ d_box_proc, 25, 311, 112, 64, C_BLACK, C_WHITE, 0, 0, 0, 0, NULL, NULL, NULL },
{ num_of_codes_proc, 81, 319, 54, 24, C_BLACK, C_WHITE, 0, 0, 0, 0, NULL, NULL, NULL },
{ st_ctext_proc, 80, 351, 55, 20, C_BLACK, C_TRANSP, 0, 0, 0, 0, "DTCs", NULL, NULL },
{ d_box_proc, 25, 383, 112, 72, C_BLACK, C_WHITE, 0, 0, 0, 0, NULL, NULL, NULL },
{ mil_status_proc, 56, 390, 50, 30, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
{ mil_text_proc, 81, 430, 54, 23, C_BLACK, C_WHITE, 0, 0, 0, 0, NULL, NULL, NULL },
{ d_box_proc, 152, 25, 463, 24, C_BLACK, C_DARK_GRAY, 0, 0, 0, 0, NULL, NULL, NULL },
{ caption_proc, 383, 28, 230, 19, C_WHITE, C_TRANSP, 0, 0, 0, 0, "Diagnostic Trouble Code Definition", NULL, NULL },
{ tr_description_proc, 152, 49, 463, 100, C_BLACK, C_LIGHT_GRAY, 0, 0, 0, 0, NULL, NULL, NULL },
{ d_box_proc, 152, 164, 463, 25, C_BLACK, C_DARK_GRAY, 0, 0, 0, 0, NULL, NULL, NULL },
{ caption_proc, 383, 167, 230, 20, C_WHITE, C_TRANSP, 0, 0, 0, 0, "Possible Causes And Known Solutions", NULL, NULL },
{ tr_solution_proc, 152, 189, 463, 185, C_BLACK, C_LIGHT_GRAY, 0, 0, 0, 0, NULL, NULL, NULL },
{ simulate_proc, 152, 408, 88, 16, C_BLACK, C_WHITE, 0, 0, 1, 0, "Simulate", NULL, NULL },
{ read_tr_codes_proc, 256, 408, 110, 48, C_BLACK, C_GREEN, 'r', D_EXIT, 0, 0, "&Read", NULL, NULL },
{ clear_codes_proc, 381, 408, 110, 48, C_BLACK, C_DARK_YELLOW, 'c', D_EXIT, 0, 0, "&Clear", NULL, NULL },
{ d_button_proc, 506, 408, 110, 48, C_BLACK, C_GREEN, 'm', D_EXIT, 0, 0, "Main &Menu", NULL, NULL },
{ tr_code_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
{ NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
};
static DIALOG confirm_clear_dialog[] =
{
/* (proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
{ d_shadow_box_proc, 0, 0, 440, 460, C_BLACK, C_WHITE, 0, 0, 0, 0, NULL, NULL, NULL },
{ d_shadow_box_proc, 0, 0, 440, 24, C_BLACK, C_DARK_GRAY, 0, 0, 0, 0, NULL, NULL, NULL },
{ caption_proc, 220, 2, 218, 19, C_WHITE, C_TRANSP, 0, 0, 0, 0, "Clear Trouble Codes", NULL, NULL },
{ super_textbox_proc, 16, 32, 408, 332, C_BLACK, C_WHITE, 0, 0, 0, 0, CLEAR_CODES_WARNING, NULL, NULL },
{ caption_proc, 220, 372, 204, 24, C_RED, C_TRANSP, 0, 0, 0, 0, "Are you sure you want to do this?", NULL, NULL },
{ d_button_proc, 72, 408, 140, 35, C_BLACK, C_GREEN, 'y', D_EXIT, 0, 0, "&Yes, I am sure", NULL, NULL },
{ d_button_proc, 228, 408, 140, 35, C_BLACK, C_DARK_YELLOW, 'n', D_EXIT, 0, 0, "&No, cancel", NULL, NULL },
{ NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
};
int display_trouble_codes()
{
int ret;
mil_is_on = FALSE; // reset MIL status
num_of_codes_reported = 0;
clear_trouble_codes();
centre_dialog(confirm_clear_dialog); // center the popup dialog
if (comport.status == USER_IGNORED)
comport.status = NOT_OPEN;
ret = do_dialog(read_codes_dialog, -1);
if (get_number_of_codes() > 0) // if the structure is not empty,
clear_trouble_codes();
return ret;
}
void trouble_codes_simulator(int show)
{
char buf[128];
if (show)
{
strcpy(buf, SIM_CODES_STRING);
process_response(NULL, buf);
clear_trouble_codes();
num_of_codes_reported = handle_read_codes(buf, FALSE);
populate_trouble_codes_list();
mil_is_on = TRUE;
}
else
{
clear_trouble_codes();
num_of_codes_reported = 0;
mil_is_on = FALSE;
}
broadcast_dialog_message(MSG_READY, 0);
}
int current_code_proc(int msg, DIALOG *d, int c)
{
switch (msg)
{
case MSG_START:
d->dp2 = datafile[ARIAL18_FONT].dat;
d->dp = empty_string;
break;
case MSG_READY:
if (get_number_of_codes() == 0)
d->dp = empty_string;
else
d->dp = get_trouble_code(current_code_index)->code;
return D_REDRAWME;
case MSG_DRAW:
rectfill(screen, d->x-d->w, d->y, d->x+d->w-1, d->y+d->h-1, d->bg); // clear the element
break;
}
return st_ctext_proc(msg, d, c);
}
int tr_description_proc(int msg, DIALOG *d, int c) // procedure which displays a textbox
{
TROUBLE_CODE *dtc;
switch (msg)
{
case MSG_START:
d->dp = empty_string;
break;
case MSG_READY:
if (get_number_of_codes() == 0)
d->dp = empty_string;
else
{
if (!(dtc = get_trouble_code(current_code_index)))
d->dp = empty_string;
else
{
if (!(d->dp = dtc->description))
{
if (is_mfr_code(dtc->code))
d->dp = (dtc->pending) ? mfr_pending_code_description : mfr_code_description;
else
d->dp = (dtc->pending) ? pending_code_no_description : code_no_description;
}
}
}
return D_REDRAWME;
}
return d_textbox_proc(msg, d, c);
}
int tr_solution_proc(int msg, DIALOG *d, int c) // procedure which displays a textbox
{
switch (msg)
{
case MSG_START:
d->dp = empty_string;
break;
case MSG_READY:
if (get_number_of_codes() == 0)
d->dp = empty_string;
else if(!(d->dp = get_trouble_code(current_code_index)->solution))
d->dp = empty_string;
return D_REDRAWME;
}
return d_textbox_proc(msg, d, c);
}
int num_of_codes_proc(int msg, DIALOG *d, int c)
{
switch (msg)
{
case MSG_START:
d->dp2 = datafile[ARIAL18_FONT].dat;
if (!(d->dp = calloc(8, sizeof(char))))
fatal_error("Could not allocate enough memory for num_of_codes_proc buffer");
strcpy(d->dp, "0");
break;
case MSG_END:
free(d->dp);
break;
case MSG_DRAW:
rectfill(screen, d->x-d->w, d->y, d->x+d->w-1, d->y+d->h-1, d->bg); // clear the element
break;
case MSG_READY:
sprintf(d->dp, "%i", num_of_codes_reported);
return D_REDRAWME;
}
return st_ctext_proc(msg, d, c);
}
int mil_status_proc(int msg, DIALOG *d, int c)
{
switch (msg)
{
case MSG_START:
d->dp = datafile[MIL_OFF_BMP].dat;
break;
case MSG_READY:
if (mil_is_on)
d->dp = datafile[MIL_ON_BMP].dat;
else
d->dp = datafile[MIL_OFF_BMP].dat;
return D_REDRAWME;
}
return d_bitmap_proc(msg, d, c);
}
int mil_text_proc(int msg, DIALOG *d, int c)
{
switch (msg)
{
case MSG_START:
if (!(d->dp = calloc(16, sizeof(char))))
fatal_error("Could not allocate enough memory for mil_text_proc buffer");
strcpy(d->dp, "MIL is OFF");
break;
case MSG_END:
free(d->dp);
break;
case MSG_DRAW:
rectfill(screen, d->x-d->w, d->y, d->x+d->w-1, d->y+d->h-1, d->bg); // clear the element
break;
case MSG_READY:
if (mil_is_on)
strcpy(d->dp, "MIL is ON");
else
strcpy(d->dp, "MIL is OFF");
return D_REDRAWME;
}
return st_ctext_proc(msg, d, c);
}
int simulate_proc(int msg, DIALOG *d, int c)
{
int ret;
switch (msg)
{
case MSG_READ_CODES: case MSG_CLEAR_CODES:
// if we are currently reading or clearing codes, and the button is enabled,
if (!(d->flags & D_DISABLED))
{
d->flags |= D_DISABLED; // disable the button
return D_REDRAWME;
}
break;
case MSG_READY:
// if we're not reading or clearing codes, and the button is disabled,
if (d->flags & D_DISABLED)
{
d->flags &= ~D_DISABLED; // enable it
return D_REDRAWME;
}
break;
}
ret = d_check_proc(msg, d, c);
if ((d->flags & D_SELECTED) && (d->d2 == 0))
{
d->d2 = 1;
simulate = TRUE;
trouble_codes_simulator(TRUE);
}
else if (!(d->flags & D_SELECTED) && (d->d2 == 1))
{
d->d2 = 0;
simulate = FALSE;
trouble_codes_simulator(FALSE);
}
return ret;
}
void read_codes()
{
while (comport.status != READY)
{
if (alert("Port is not ready.", "Please check that you specified the correct port", "and that no other application is using it", "Configure &Port", "&Cancel", 'p', 'c') == 1)
display_options(); // let the user choose correct settings
else
return;
}
clear_trouble_codes();
num_of_codes_reported = 0;
mil_is_on = FALSE;
broadcast_dialog_message(MSG_READY, 0);
broadcast_dialog_message(MSG_READ_CODES, 0);
}
int read_tr_codes_proc(int msg, DIALOG *d, int c)
{
int ret;
switch (msg)
{
case MSG_READ_CODES: case MSG_CLEAR_CODES:
// if we are currently reading or clearing codes, and the button is enabled,
if (!(d->flags & D_DISABLED))
{
d->flags |= D_DISABLED; // disable the button
return D_REDRAWME;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -