⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trouble_code_reader.c

📁 国外一个非常经典的OBD2车辆检测的实例源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
         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 + -