145 lines
4.1 KiB
C
145 lines
4.1 KiB
C
/*
|
|
* IGC parser
|
|
* @brief parse IGC file, get all data points, compute average horizontal/vertical speed, print to STDOUT
|
|
*
|
|
* As per standard: https://xp-soaring.github.io/igc_file_format/igc_format_2008.html
|
|
* https://xp-soaring.github.io/igc_file_format/igc_fr_specification_with_al8_2023-2-1_0.pdf
|
|
*
|
|
* @author xamidev <xamidev@riseup.net>
|
|
* @license GNU GPL v3
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include "igc.h"
|
|
#include "linkage.h"
|
|
|
|
struct IGC_DataPoint* parse_datapoint(char* line)
|
|
{
|
|
// There probably exists a better and/or prettier way
|
|
struct IGC_DataPoint* dp = (struct IGC_DataPoint*)malloc(sizeof(struct IGC_DataPoint));
|
|
char hour[3], min[3], sec[3] = {0};
|
|
char lat_d[3], lat_m[3], lat_s[4] = {0};
|
|
char lon_d[4], lon_m[3], lon_s[4] = {0};
|
|
char baro_alt[6], gps_alt[6] = {0};
|
|
|
|
memcpy(hour, line+1, 2);
|
|
memcpy(min, line+3, 2);
|
|
memcpy(sec, line+5, 2);
|
|
memcpy(lat_d, line+7, 2);
|
|
memcpy(lat_m, line+9, 2);
|
|
memcpy(lat_s, line+11, 3);
|
|
memcpy(lon_d, line+15, 3);
|
|
memcpy(lon_m, line+18, 2);
|
|
memcpy(lon_s, line+20, 3);
|
|
memcpy(baro_alt, line+25, 5);
|
|
memcpy(gps_alt, line+30, 5);
|
|
|
|
dp->hour = atoi(hour);
|
|
dp->minute = atoi(min);
|
|
dp->second = atoi(sec);
|
|
dp->lat.deg = atoi(lat_d);
|
|
dp->lat.min = atoi(lat_m);
|
|
dp->lat.sec = atoi(lat_s);
|
|
dp->lat.cardinal = line[14] == NORTH ? NORTH : SOUTH;
|
|
dp->lon.deg = atoi(lon_d);
|
|
dp->lon.min = atoi(lon_m);
|
|
dp->lon.sec = atoi(lon_s);
|
|
dp->lon.cardinal = line[23] == EAST ? EAST : WEST;
|
|
dp->baro_alt = atoi(baro_alt);
|
|
dp->gps_alt = atoi(gps_alt);
|
|
|
|
return dp;
|
|
}
|
|
|
|
void show_datapoint(struct IGC_DataPoint* dp)
|
|
{
|
|
printf("Data point: %02d:%02d:%02d | %d°%d'%d\"%c %d°%d'%d\"%c | Baro: %dm GPS: %dm\n", dp->hour, dp->minute, dp->second, dp->lat.deg, dp->lat.min, dp->lat.sec, dp->lat.cardinal, dp->lon.deg, dp->lon.min, dp->lon.sec, dp->lon.cardinal, dp->baro_alt, dp->gps_alt);
|
|
}
|
|
|
|
void show_header_info(struct IGC_Header* hdr)
|
|
{
|
|
printf("*** Flight information:\nDate: %02d/%02d/%02d\nPilot: %sCopilot: %sAircraft: %sRegistration: %s", hdr->day, hdr->month, hdr->year, hdr->pilot_name, hdr->crew2_name, hdr->aircraft_name, hdr->aircraft_registration_no);
|
|
}
|
|
|
|
struct IGC_Header* parse_header_record(struct IGC_Header* hdr, char* line)
|
|
{
|
|
if (strncmp(line, "HFDTEDATE", 9) == 0)
|
|
{
|
|
strtok(line, ":");
|
|
char* date_str = strtok(NULL, ":");
|
|
char day[3], month[3], year[3] = {0};
|
|
|
|
memcpy(day, date_str, 2);
|
|
memcpy(month, date_str+2, 2);
|
|
memcpy(year, date_str+4, 2);
|
|
|
|
hdr->day = atoi(day);
|
|
hdr->month = atoi(month);
|
|
hdr->year = atoi(year);
|
|
}
|
|
if (strncmp(line, "HFPLTPILOTINCHARGE", 18) == 0)
|
|
{
|
|
strtok(line, ":");
|
|
strncpy(hdr->pilot_name, strtok(NULL, ":"), SMALL_NAME_MAX);
|
|
}
|
|
if (strncmp(line, "HFCM2CREW2", 10) == 0)
|
|
{
|
|
strtok(line, ":");
|
|
strncpy(hdr->crew2_name, strtok(NULL, ":"), SMALL_NAME_MAX);
|
|
}
|
|
if (strncmp(line, "HFGTYGLIDERTYPE", 15) == 0)
|
|
{
|
|
strtok(line, ":");
|
|
strncpy(hdr->aircraft_name, strtok(NULL, ":"), SMALL_NAME_MAX);
|
|
}
|
|
if (strncmp(line, "HFGIDGLIDERID", 13) == 0)
|
|
{
|
|
strtok(line, ":");
|
|
strncpy(hdr->aircraft_registration_no, strtok(NULL, ":"), SMALL_NAME_MAX);
|
|
}
|
|
if (strncmp(line, "HFDTMGPSDATUM", 13) == 0)
|
|
{
|
|
strtok(line, ":");
|
|
strncpy(hdr->gps_datum, strtok(NULL, ":"), SMALL_NAME_MAX);
|
|
}
|
|
return hdr;
|
|
}
|
|
|
|
void parse_igc_file(FILE* fp, struct IGC_Header* hdr, struct dp_node* list)
|
|
{
|
|
size_t len = 0;
|
|
char* line = NULL;
|
|
|
|
while (getline(&line, &len, fp) != -1)
|
|
{
|
|
switch(line[0])
|
|
{
|
|
case MANUFACTURER:
|
|
printf("Manufacturer info: %s", line);
|
|
break;
|
|
case COMMENT:
|
|
printf("Comment: %s", line);
|
|
break;
|
|
case DATAPOINT:
|
|
struct IGC_DataPoint* dp = parse_datapoint(line);
|
|
//show_datapoint(dp);
|
|
// Doubly linked list of points (so theyre joined in chronological order; opens possibilities for analysis later)
|
|
append_datapoint(list, dp);
|
|
break;
|
|
case HEADER:
|
|
hdr = parse_header_record(hdr, line);
|
|
break;
|
|
case SEC_KEY:
|
|
printf("Security key found: %s", line);
|
|
break;
|
|
default:
|
|
printf("Unhandled record type '%c'\n", line[0]);
|
|
break;
|
|
}
|
|
}
|
|
show_header_info(hdr);
|
|
}
|