restructuration

This commit is contained in:
2025-11-08 10:10:11 +01:00
parent 12ea087cae
commit fed66fbea8
10 changed files with 16 additions and 6 deletions

145
src/igc.c Normal file
View File

@@ -0,0 +1,145 @@
/*
* 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
*/
#define _GNU_SOURCE
#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);
}

92
src/igc.h Normal file
View File

@@ -0,0 +1,92 @@
/*
* IGC parser
* @brief parse IGC file, get all data points, compute average horizontal/vertical speed, print to STDOUT
*
* @author xamidev <xamidev@riseup.net>
* @license GNU GPL v3
*/
#ifndef IGC_H
#define IGC_H
#define SMALL_NAME_MAX 32
#define NAME_MAX 256
#define TMP_SIZE 8
#include "linkage.h"
enum IGC_RecordType
{
MANUFACTURER = 'A',
HEADER = 'H',
EXTENSION = 'I',
J_EXTENSION = 'J',
DECLARATION = 'C',
SATELLITES = 'F',
DATAPOINT = 'B',
DIFFERENTIAL_GPS = 'D',
PILOT_EVENT = 'E',
GEN_PURPOSE_PLACEHOLDER = 'K',
COMMENT = 'L',
SEC_KEY = 'G',
};
enum Cardinals
{
NORTH = 'N',
SOUTH = 'S',
EAST = 'E',
WEST = 'W'
};
struct Coord
{
char cardinal;
int deg;
int min;
int sec;
};
struct IGC_Header
{
int day;
int month;
int year;
// Not exhaustive
char pilot_name[NAME_MAX];
char crew2_name[NAME_MAX];
char aircraft_name[NAME_MAX];
char aircraft_registration_no[NAME_MAX];
char gps_datum[NAME_MAX];
// (not too important; ignored for now, may be part of "verbose" setting later)
char firmware_ver[NAME_MAX];
char hardware_ver[NAME_MAX];
char frtype[NAME_MAX];
char press_alt_sensor[NAME_MAX];
};
struct IGC_DataPoint
{
// timestamp
int hour;
int minute;
int second;
// coordinates
struct Coord lat;
struct Coord lon;
// altitude
int baro_alt;
int gps_alt;
};
void parse_igc_file(FILE* fp, struct IGC_Header* hdr, struct dp_node* list);
struct IGC_DataPoint* parse_datapoint(char* line);
void show_datapoint(struct IGC_DataPoint* dp);
void show_header_info(struct IGC_Header* hdr);
struct IGC_Header* parse_header_record(struct IGC_Header* hdr, char* line);
#endif

69
src/linkage.c Normal file
View File

@@ -0,0 +1,69 @@
/*
* IGC parser - data linking module (doubly linked datapoint list)
* @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 "igc.h"
#include "linkage.h"
struct dp_node* create_datapoint_list()
{
struct dp_node* head = (struct dp_node*)calloc(1, sizeof(struct dp_node));
head->data = NULL;
head->prev = NULL;
head->next = NULL;
return head;
}
void append_datapoint(struct dp_node* list, struct IGC_DataPoint* dp)
{
struct dp_node* new = (struct dp_node*)calloc(1, sizeof(struct dp_node));
if (list->next == NULL)
{
list->next = new;
new->prev = list;
new->next = NULL;
new->data = dp;
return;
}
while (list->next != NULL)
{
list = list->next;
}
list->next = new;
new->prev = list;
new->next = NULL;
new->data = dp;
return;
}
void print_datapoint_list(struct dp_node* list)
{
if (list->data == NULL)
{
// We're at head!
list = list->next;
}
while (list->next != NULL)
{
show_datapoint(list->data);
printf(" <-> ");
list = list->next;
}
puts("NULL");
return;
}

29
src/linkage.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* IGC parser - data linking module (doubly linked datapoint list)
* @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
*/
#ifndef LINKAGE_H
#define LINKAGE_H
#include "igc.h"
struct dp_node
{
struct IGC_DataPoint* data;
struct dp_node* prev;
struct dp_node* next;
};
struct dp_node* create_datapoint_list();
void append_datapoint(struct dp_node* list, struct IGC_DataPoint* dp);
void print_datapoint_list(struct dp_node* list);
#endif

61
src/main.c Normal file
View File

@@ -0,0 +1,61 @@
/*
* 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 "raylib.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "igc.h"
#include "linkage.h"
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("Usage: %s <file>\n", argv[0]);
return -EINVAL;
}
char filename[NAME_MAX] = {0};
strncpy(filename, argv[1], NAME_MAX-1);
FILE* fp = fopen(filename, "r");
if (!fp)
{
printf("Couldn't open file %s\n", filename);
return -EINVAL;
}
struct dp_node* head = create_datapoint_list();
struct IGC_Header* hdr = (struct IGC_Header*)calloc(1, sizeof(struct IGC_Header));
parse_igc_file(fp, hdr, head);
print_datapoint_list(head);
// Raylib test window
SetTraceLogLevel(4);
const int screenWidth = 800;
const int screenHeight = 600;
InitWindow(screenWidth, screenHeight, "Raylib basic window");
SetTargetFPS(60);
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(RAYWHITE);
DrawText("It works!", 20, 20, 20, BLACK);
EndDrawing();
}
CloseWindow();
return EXIT_SUCCESS;
}