Compare commits

...

18 Commits

Author SHA1 Message Date
6f0fb8cefd Merge pull request 'moving development to master for a while since there is no need for branching yet' (#8) from duckdb into master
Reviewed-on: #8
2026-01-08 14:48:09 +01:00
53a2194bde added all the new error codes for the exits currently in the code 2026-01-08 12:53:49 +01:00
25a9dfb349 added path checking for input file and exit codes 2026-01-08 12:34:05 +01:00
b380f203e3 added valgrind toggle 2026-01-08 12:33:39 +01:00
615d8c7f06 query lap timestamps 2026-01-06 22:19:08 +01:00
f52d081d04 getting laptime data to know how many lapinfo needs to be allocated 2026-01-03 20:44:21 +01:00
abe3a2dbb1 changed makefile run command to run with valgrind and default data file 2026-01-03 20:43:51 +01:00
92cf26fcf6 moved table names to separate file 2026-01-03 20:43:21 +01:00
2e8f90eb3e fixed memory leak, did not free validity 2026-01-02 20:06:10 +01:00
ebd4fceda0 compile commands, working on storing the database data and refactoring the code to read the data 2026-01-02 20:01:19 +01:00
68b774e296 working on separating data by laps 2025-12-31 23:30:18 +01:00
c236ffee20 updated makefile with debug and release configuration 2025-12-30 14:45:12 +01:00
76586cc029 updated makefile for windows build to copy the dll to builddir 2025-12-29 15:30:51 +01:00
dcd589f669 added table entries from the default configuration file provided by LMU 2025-12-29 14:59:04 +01:00
33cb91f9a9 fixed data type when getting the data from the chunk 2025-12-29 14:10:40 +01:00
d8854ce4fc reading data from the database basics 2025-12-29 13:46:15 +01:00
23ab97aca8 reading in duckdb filepath as arg and opening the database 2025-12-28 21:32:38 +01:00
80d061d2f1 linking duckdb as a dynamic lib for avoiding linking errors 2025-12-28 21:32:05 +01:00
13 changed files with 440 additions and 12 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -3,32 +3,51 @@ SRCDIR = src
BUILDDIR = build
VENDORDIR = vendor
target = linux
target ?= linux
profile ?= debug
valgrind ?= false
ifeq ($(target), windows)
CC = x86_64-w64-mingw32-gcc
CXX = x86_64-w64-mingw32-g++
EXT = .exe
CFLAGS = -Wall -o2 -I$(SRCDIR) -I$(VENDORDIR)/mariadb/include -I$(VENDORDIR)/duckdb/windows/include
OPT_FLAGS = -O2 -DNDEBUG
INCLUDES = -I$(SRCDIR) -I$(VENDORDIR)/mariadb/include -I$(VENDORDIR)/duckdb/windows/include
LIBS = -L$(VENDORDIR)/mariadb/lib -llibmariadb -L$(VENDORDIR)/duckdb/windows/lib -lduckdb
# Command to copy DLL after build
POST_BUILD_CMD = @cp $(VENDORDIR)/duckdb/windows/lib/duckdb.dll $(BUILDDIR)
else
CC = gcc
CXX = g++
EXT =
CFLAGS = -Wall -O2 -I$(SRCDIR) `pkg-config --cflags libmariadb` -I$(VENDORDIR)/duckdb/linux/include
LIBS = `pkg-config --libs libmariadb` -L$(VENDORDIR)/duckdb/linux/lib -lduckdb_static
INCLUDES = -I$(SRCDIR) `pkg-config --cflags libmariadb` -I$(VENDORDIR)/duckdb/linux/include
LIBS = `pkg-config --libs libmariadb` -L$(VENDORDIR)/duckdb/linux/lib -lduckdb
POST_BUILD_CMD = @echo "Build complete."
# Profile Logic
ifeq ($(profile), release)
OPT_FLAGS = -O3 -DNDEBUG -march=native
else
OPT_FLAGS = -O0 -g -DDEBUG -Wall -Wextra
endif
endif
# Combine Flags
CFLAGS = -Wall $(OPT_FLAGS) $(INCLUDES)
SRC = $(shell find $(SRCDIR) -name "*.c")
OBJ = $(SRC:$(SRCDIR)/%.c=$(BUILDDIR)/%.o)
all: $(BUILDDIR)/$(APPNAME)$(EXT)
$(BUILDDIR)/$(APPNAME)$(EXT): $(OBJ)
@echo "Linking $@"
@echo "Linking $@ (Target: $(target), Profile: $(profile))"
@mkdir -p $(dir $@)
$(CC) $(OBJ) -o $@ $(LIBS)
$(POST_BUILD_CMD)
$(BUILDDIR)/%.o: $(SRCDIR)/%.c
@echo "Compiling $<"
@@ -38,7 +57,13 @@ $(BUILDDIR)/%.o: $(SRCDIR)/%.c
clean:
rm -rf $(BUILDDIR)
ifeq ($(valgrind), true)
RUN_CMD = valgrind --leak-check=full ./$(BUILDDIR)/$(APPNAME)$(EXT)
else
RUN_CMD = ./$(BUILDDIR)/$(APPNAME)$(EXT)
endif
run: all
./$(BUILDDIR)/$(APPNAME)$(EXT)
$(RUN_CMD) ./data/Circuit.duckdb
.PHONY: all clean run

44
compile_commands.json Normal file
View File

@@ -0,0 +1,44 @@
[
{
"arguments": [
"/usr/bin/gcc",
"-Wall",
"-O0",
"-g",
"-DDEBUG",
"-Wall",
"-Wextra",
"-Isrc",
"-I/usr/include/mysql/",
"-Ivendor/duckdb/linux/include",
"-c",
"-o",
"build/lapinfo.o",
"src/lapinfo.c"
],
"directory": "/home/tom/Dev/HardCompound",
"file": "/home/tom/Dev/HardCompound/src/lapinfo.c",
"output": "/home/tom/Dev/HardCompound/build/lapinfo.o"
},
{
"arguments": [
"/usr/bin/gcc",
"-Wall",
"-O0",
"-g",
"-DDEBUG",
"-Wall",
"-Wextra",
"-Isrc",
"-I/usr/include/mysql/",
"-Ivendor/duckdb/linux/include",
"-c",
"-o",
"build/main.o",
"src/main.c"
],
"directory": "/home/tom/Dev/HardCompound",
"file": "/home/tom/Dev/HardCompound/src/main.c",
"output": "/home/tom/Dev/HardCompound/build/main.o"
}
]

BIN
data/Circuit.duckdb Normal file

Binary file not shown.

9
src/exit_code.h Normal file
View File

@@ -0,0 +1,9 @@
typedef enum {
EXIT_OK = 0,
ERR_ARGUMENT = 1,
ERR_FILE = 2,
ERR_DATABASE = 3,
ERR_CONNECTION = 4,
ERR_MEMORY = 5,
ERR_QUERY = 6,
} exit_code;

18
src/lapinfo.c Normal file
View File

@@ -0,0 +1,18 @@
#include <stdint.h>
#include <stdlib.h>
#include "lapinfo.h"
void free_telemetry_info(TelemetryInfo *t) {
free(t->data);
free(t->validity);
// free(t);
}
void destroyLapinfo(LapInfo *info) {
free_telemetry_info(&info->throttle_pos);
free_telemetry_info(&info->brake_pos);
free_telemetry_info(&info->steering_pos);
free_telemetry_info(&info->speed);
// free(info);
}

31
src/lapinfo.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include <stdint.h>
typedef enum {
BOOL,
INT,
FLOAT,
DOUBLE,
} TelemetryDataType;
typedef struct {
TelemetryDataType type;
int8_t frequency;
void *data;
uint64_t *validity;
uint32_t data_size;
uint32_t data_last_index;
} TelemetryInfo;
typedef struct {
int lap_number;
double start_time;
TelemetryInfo throttle_pos; // freq: 50
TelemetryInfo brake_pos; // freq: 50
TelemetryInfo steering_pos; // freq: 100
TelemetryInfo speed;
} LapInfo;
void free_telemetry_info(TelemetryInfo *t);
void destroyLapinfo(LapInfo *info);

View File

@@ -1,6 +1,196 @@
#include <duckdb.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
int main(){
printf("Hello World");
return 0;
#include "exit_code.h"
#include "lapinfo.h"
bool is_valid_path(const char *path) {
if (path == NULL) {
return false;
}
const char *dot = strrchr(path, '.'); // find the last dot which is for the extension
if (!dot || strcmp(dot, ".duckdb") != 0) {
return false;
}
struct stat path_stat;
if (stat(path, &path_stat) != 0) {
return false; // path does not exist
}
if (!S_ISREG(path_stat.st_mode)) {
return false; // checks if it is a regular file
}
return true;
}
void get_data_from_db(const char *query, duckdb_connection *conn, TelemetryInfo *info) {
duckdb_result result;
duckdb_query(*conn, query, &result);
while (true) {
duckdb_data_chunk data_chunk = duckdb_fetch_chunk(result);
if (!data_chunk) {
break;
}
idx_t row_count = duckdb_data_chunk_get_size(data_chunk); // number of rows from the data chunk
// set column
duckdb_vector col1 = duckdb_data_chunk_get_vector(data_chunk, 0);
void *col1_data = duckdb_vector_get_data(col1);
uint64_t *col1_validity = duckdb_vector_get_validity(col1);
for (idx_t row = 0; row < row_count; row++) {
if (duckdb_validity_row_is_valid(col1_validity, row)) {
switch (info->type) {
case FLOAT:
((float *)info->data)[info->data_last_index] = ((float *)col1_data)[row];
info->data_last_index++;
break;
case BOOL:
((bool *)info->data)[info->data_last_index] = ((bool *)col1_data)[row];
info->data_last_index++;
break;
case DOUBLE:
((double *)info->data)[info->data_last_index] = ((double *)col1_data)[row];
info->data_last_index++;
break;
case INT:
((int32_t *)info->data)[info->data_last_index] = ((int32_t *)col1_data)[row];
info->data_last_index++;
break;
}
// printf("%f, ", ((float *)col1_data)[row]);
} else {
printf("NULL");
}
}
duckdb_destroy_data_chunk(&data_chunk);
}
duckdb_destroy_result(&result);
}
int main(int argc, char **argv) {
printf("\nHello from HardCompound!\n");
if (argc < 2) {
printf("You need to specify a duckdb file path! Terminating!\n");
exit(ERR_ARGUMENT);
}
if (!is_valid_path(argv[1])) {
printf("The file you gave is not valid. Exiting!");
exit(ERR_FILE);
}
printf("First argument: %s\n", argv[1]);
duckdb_database db;
if (duckdb_open(argv[1], &db) == DuckDBError) {
printf("Error opening duckdb file, terminating!\n");
exit(ERR_DATABASE);
}
duckdb_connection conn;
if (duckdb_connect(db, &conn) == DuckDBError) {
printf("Error connecting to the duckdb database! Terminating!\n");
duckdb_close(&db);
exit(ERR_CONNECTION);
}
// get how many laps is in the session and allocate that many LapInfo-s
duckdb_result lap_count_res;
int32_t lap_count = 0;
duckdb_query(conn, "Select count(value) from Lap\n", &lap_count_res);
duckdb_data_chunk data_chunk = duckdb_fetch_chunk(lap_count_res);
if (!data_chunk) {
printf("Error in retrieving laps");
duckdb_disconnect(&conn);
duckdb_close(&db);
exit(ERR_QUERY);
}
// set column
duckdb_vector col1 = duckdb_data_chunk_get_vector(data_chunk, 0);
int32_t *col1_data = (int32_t *)duckdb_vector_get_data(col1);
uint64_t *col1_validity = duckdb_vector_get_validity(col1);
idx_t row_count = duckdb_data_chunk_get_size(data_chunk); // number of rows from the data chunk
for (idx_t row = 0; row < row_count; row++) {
if (duckdb_validity_row_is_valid(col1_validity, 0)) {
lap_count = col1_data[0];
}
}
duckdb_destroy_data_chunk(&data_chunk);
duckdb_destroy_result(&lap_count_res);
printf("Lap count: %d\n", lap_count);
LapInfo *session_data = calloc(lap_count, sizeof(LapInfo));
double *lap_timestamps = calloc(lap_count, sizeof(double));
if (!session_data) {
printf("Session data failed to allocate!");
exit(ERR_MEMORY);
}
if (!lap_timestamps) {
printf("Lap timestaps array failed to init!");
exit(ERR_MEMORY);
}
duckdb_result lap_timestamps_res;
if (duckdb_query(conn, "Select ts as DOUBLE from Lap\n", &lap_timestamps_res) == DuckDBError) {
exit(ERR_QUERY);
}
int current_index = 0;
while (true) {
duckdb_data_chunk data_chunk_2 = duckdb_fetch_chunk(lap_timestamps_res);
if (!data_chunk_2) {
break;
}
idx_t current_chunk_size = duckdb_data_chunk_get_size(data_chunk_2);
duckdb_vector col2 = duckdb_data_chunk_get_vector(data_chunk_2, 0);
double *ts_data = (double *)duckdb_vector_get_data(col2);
uint64_t *col2_validity = duckdb_vector_get_validity(col2);
for (idx_t row = 0; row < current_chunk_size; row++) {
if (!col2_validity || duckdb_validity_row_is_valid(col2_validity, row)) {
if (current_index < lap_count) {
lap_timestamps[current_index++] = ts_data[row];
}
}
}
duckdb_destroy_data_chunk(&data_chunk_2);
}
duckdb_destroy_result(&lap_timestamps_res);
for (int i = 0; i < lap_count; i++) {
printf("%f, ", lap_timestamps[i]);
}
printf("\n");
free(session_data);
printf("Shutting down HardCompound!\n");
printf("Closing database and any connection.\n");
duckdb_disconnect(&conn);
duckdb_close(&db);
return EXIT_OK;
}

111
src/tables.c Normal file
View File

@@ -0,0 +1,111 @@
const char *channel_tables[] = {"Ambient Temperature",
"Brake Pos",
"Brake Pos Unfiltered",
"Brake Thickness",
"Brakes Air Temp",
"Brakes Force",
"Brakes Temp",
"Clutch Pos",
"Clutch Pos Unfiltered",
"Clutch RPM",
"Drag",
"Engine Oil Temp",
"Engine RPM",
"Engine Water Temp",
"FFB Output",
"Front3rdDeflection",
"FrontDownForce",
"FrontRideHeight",
"FrontWingHeight",
"Fuel Level",
"G Force Lat",
"G Force Long",
"G Force Vert",
"GPS Latitude",
"GPS Longitude",
"GPS Speed",
"GPS Time",
"Ground Speed",
"Lap Dist",
"Lateral Acceleration",
"Longitudinal Acceleration",
"OverheatingState",
"Path Lateral",
"ReadDownForce",
"Rear3rdDeflection",
"RearRideHeight",
"Regen Rate",
"RideHeights",
"SoC",
"Steered Angle",
"Steering Pos",
"Steering Pos Unfiltered",
"Steering Shaft Torque",
"Susp Pos",
"Throttle Pos",
"Throttle Pos Unfiltered",
"Time Behind Next",
"Total Dist",
"Track Edge",
"Track Temperature",
"Turbo Boost Pressure",
"Tyres Wear",
"TyresCarcassTemp",
"TyresPressure",
"TyresRimTemp",
"TyresRubberTemp",
"TyresTempCentre",
"TyresTempLeft",
"TyresTempRight",
"Virtual Energy",
"Wheel Speed",
"Wind Heading",
"Wind Speed",
"Yaw Rate"};
const int channel_table_count = sizeof(channel_tables) / sizeof(channel_tables[0]);
const char *event_tables[] = {"ABS",
"ABSLevel",
"AntiStall Activated",
"Best LapTime",
"Best Sector1",
"Best Sector2",
"Brake Bias Rear",
"Brake Migration",
"CloudDarkness",
"Current LapTime",
"Current Sector",
"Current Sector1",
"Current Sector2",
"Engine Max RPM",
"Finish Status",
"FrontFlapActivated",
"FuelMixtureMap",
"Gear",
"Headlights State",
"In Pits",
"Lap",
"Lap Time",
"Last Sector1",
"Last Sector2",
"LastImpactMagnitude",
"LaunchControlActive",
"Minimum Path Wetness",
"OffpathWetness",
"RearFlapActivated",
"RearFlapLegalStatus",
"Sector1 Flag",
"Sector2 Flag",
"Sector3 Flag",
"Speed Limiter",
"SurfaceTypes",
"TC",
"TCCut",
"TCLevel",
"TCSlipAngle",
"TyresCompound",
"WheelsDetached",
"Yellow Flag State"};
const int event_table_count = sizeof(event_tables) / sizeof(event_tables[0]);