Use C to generate fit exceptions

  • Generate fit exceptions using C, with code attached

uint32_t startTime = 1007518019;
uint32_t timestamp = 1007518019;
  FILE *fp;
   data_crc = 0;
   fp = fopen("test.fit", "w+b");
   WriteFileHeader(fp);
   // Write file id message.
   {
      FIT_UINT8 local_mesg_number = 0;
      FIT_FILE_ID_MESG file_id;
      Fit_InitMesg(fit_mesg_defs[FIT_MESG_FILE_ID], &file_id);
      file_id.type = FIT_FILE_ACTIVITY;
      file_id.manufacturer = FIT_MANUFACTURER_CHILEAF;
      file_id.serial_number = 1000;
      file_id.product = 1;
      file_id.time_created = startTime;
      WriteMessageDefinition(local_mesg_number, fit_mesg_defs[FIT_MESG_FILE_ID], FIT_FILE_ID_MESG_DEF_SIZE, fp);
      WriteMessage(local_mesg_number, &file_id, FIT_FILE_ID_MESG_SIZE, fp);
   }
   {
       FIT_UINT8 local_mesg_number = 0;
       FIT_EVENT_MESG eventMesgStart;
       Fit_InitMesg(fit_mesg_defs[FIT_MESG_EVENT], &eventMesgStart);
       eventMesgStart.timestamp = startTime;
       eventMesgStart.event = FIT_EVENT_TIMER;
       eventMesgStart.event_type = FIT_EVENT_TYPE_START;
       WriteMessageDefinition(local_mesg_number, fit_mesg_defs[FIT_MESG_EVENT], FIT_EVENT_MESG_DEF_SIZE, fp);
       WriteMessage(local_mesg_number, &eventMesgStart, FIT_EVENT_MESG_SIZE, fp);
   }
   {
       FIT_UINT8 local_mesg_number = 0;
       FIT_RECORD_MESG recordMesg;
       Fit_InitMesg(fit_mesg_defs[FIT_MESG_RECORD], &recordMesg);
       
       for (FIT_UINT16 i = 0; i < 1; i++)
       {
           recordMesg.heart_rate = (FIT_UINT8)(200);
           recordMesg.timestamp =  timestamp;
           WriteMessageDefinition(local_mesg_number, fit_mesg_defs[FIT_MESG_RECORD], FIT_RECORD_MESG_DEF_SIZE, fp);
           WriteMessage(local_mesg_number, &recordMesg, FIT_RECORD_MESG_SIZE, fp);
           timestamp++;
       }

   }
   {
       
           FIT_UINT8 local_mesg_number = 0;
           FIT_SESSION_MESG sessionMesg;
            Fit_InitMesg(fit_mesg_defs[FIT_MESG_SESSION], &sessionMesg);
            sessionMesg.timestamp = timestamp;
            sessionMesg.start_time = startTime;
            sessionMesg.total_elapsed_time = (timestamp- startTime);
            sessionMesg.total_timer_time = (timestamp- startTime);
            sessionMesg.sport = FIT_SPORT_STAND_UP_PADDLEBOARDING;
            sessionMesg.sub_sport = FIT_SUB_SPORT_GENERIC;
            sessionMesg.first_lap_index = 0;
            sessionMesg.num_laps = 1;
          
           WriteMessageDefinition(local_mesg_number, fit_mesg_defs[FIT_MESG_SESSION], FIT_SESSION_MESG_TIME_IN_HR_ZONE_COUNT, fp);
           WriteMessage(local_mesg_number, &sessionMesg, FIT_SESSION_MESG_SIZE, fp);
       
   }
    {

       FIT_UINT8 local_mesg_number = 0;
       FIT_ACTIVITY_MESG activityMesg;
       Fit_InitMesg(fit_mesg_defs[FIT_MESG_ACTIVITY], &activityMesg);
       activityMesg.timestamp = timestamp;
       activityMesg.num_sessions = 1;
       activityMesg.local_timestamp = -7 * 3600+ timestamp;
       WriteMessageDefinition(local_mesg_number, fit_mesg_defs[FIT_MESG_ACTIVITY], FIT_ACTIVITY_MESG_DEF_SIZE, fp);
       WriteMessage(local_mesg_number, &activityMesg, FIT_ACTIVITY_MESG_SIZE, fp);

   }
    fwrite(&data_crc, 1, sizeof(FIT_UINT16), fp);
    WriteFileHeader(fp);
    fclose(fp);

  • The value of FIT_SESSION_MESG_SIZE has increased over time and is now greater than 255 bytes. The size parameter of the WriteMessageDefinition, WriteMessage, and WriteData functions all use uint8, and that is probably what is causing the issue. The fix is to change the type of the mesg_def_size, mesg_size, and data_size parameters to be a uint32.

    The attached code created the attached FIT file.

    encode.c.zip

    test.fit

  • hi,

        One more question,Some timestamp are multiplied by 1000 and some times are not. May I know the reason? Thank you!


    lap_mesg.timestamp = timestamp;
    lap_mesg.start_time = start_time;
    lap_mesg.total_elapsed_time = (timestamp - start_time) * 1000;
    lap_mesg.total_timer_time = (timestamp - start_time) * 1000;

  • Some fields need a scale and offset applied to them. You can find the scale and offset values in Profile.xlsx and in the comments in the c/example.h header file. When encoding a file, you apply the offset and then apply the scale.

    total_elapsed_time is typically a float, so that you can have millisecond resolution, but is stored in the file as a uint32. That is why the scale for that field is 1000.

    This only applies to the C SDK. The other SDKs apply the scale and offset for you.

  • Hi Ben FIT,

          Can't FIT file operation be interrupted? For example, after writing the header to close the file, then re-open the file, and then write the rest of the content, the last generated FIT file will have unsupported types.What is the reason for this?

      Thanks!

  • In the example code, at the end right before the file header is updated the two byte CRC is written to the end of the file.

    From the example code.

    // Write CRC.
    fwrite(&data_crc, 1, sizeof(FIT_UINT16), fp);
    // Update file header with data size.
    WriteFileHeader(fp);
    //  Close the file
    fclose(fp);
    ...
    If you need to reopen the file and continue writing messages, then there are a few things that you need to do.
    1. Open the file for reading and writing
    2. Read the header size from the first byte, or assume that it is FIT_FILE_HDR_SIZE (14)
    3. Read the data size from the header
    4. fseek() to the end of the file and read the two byte CRC value
    5. Store the CRC value from the file in the data_crc variable. That way the data_crc value can be updated the next time data is written to the file.
    6. fseek() to the end of the data, so that the next write operation will overwrite the CRC value in the file.
    7. Write the new messages
    8. Write the CRC
    9. Update the header.

    I may be missing a step, but those are the basic steps.