Major overhault to add libuv event loop. Enhancements to config file to support profiles.

This commit is contained in:
Paul Dino Jones 2024-08-30 13:46:56 -04:00
parent 607a7ad7c3
commit 40726c06c8
14 changed files with 744 additions and 250 deletions

View File

@ -37,10 +37,10 @@ add_executable(monocoque src/monocoque/monocoque.c)
if(USE_PULSEAUDIO) if(USE_PULSEAUDIO)
message("Using pulseaudio backend...") message("Using pulseaudio backend...")
add_compile_definitions(USE_PULSEAUDIO=true) add_compile_definitions(USE_PULSEAUDIO=true)
target_link_libraries(monocoque m hidapi-hidraw pulse serialport xml2 argtable2 config gameloop helper devices slog simulatorapi) target_link_libraries(monocoque m hidapi-hidraw pulse serialport xml2 argtable2 config gameloop helper devices slog simulatorapi uv xdg-basedir)
else() else()
message("Using portaudio backend...") message("Using portaudio backend...")
target_link_libraries(monocoque m hidapi-hidraw portaudio serialport xml2 argtable2 config gameloop helper devices slog simulatorapi) target_link_libraries(monocoque m hidapi-hidraw portaudio serialport xml2 argtable2 config gameloop helper devices slog simulatorapi uv xdg-basedir)
endif() endif()
target_include_directories(monocoque PUBLIC config ${LIBXML_INCLUDE_DIR}) target_include_directories(monocoque PUBLIC config ${LIBXML_INCLUDE_DIR})

View File

@ -78,15 +78,12 @@ void stream_state_cb(pa_stream *s, void *mainloop) {
int usb_generic_shaker_free(SoundDevice* sounddevice) int usb_generic_shaker_free(SoundDevice* sounddevice)
{ {
int err = 0; int err = 0;
//err = Pa_CloseStream( sounddevice->stream );
//if( err != paNoError )
//{
// err = Pa_Terminate();
//}
if (sounddevice->stream) if (sounddevice->stream)
{ {
pa_stream_disconnect(sounddevice->stream);
pa_stream_unref(sounddevice->stream); pa_stream_unref(sounddevice->stream);
pa_xfree(sounddevice->stream); // why is this wrong
//pa_xfree(sounddevice->stream);
} }
return err; return err;
} }

View File

@ -104,8 +104,7 @@ int sounddev_free(SimDevice* this)
{ {
SoundDevice* sounddevice = (void *) this->derived; SoundDevice* sounddevice = (void *) this->derived;
//figure out why this is causing problems usb_generic_shaker_free(sounddevice);
//usb_generic_shaker_free(sounddevice);
free(sounddevice); free(sounddevice);

View File

@ -3,6 +3,7 @@ set(gameloop_source_files
gameloop.h gameloop.h
tachconfig.c tachconfig.c
tachconfig.h tachconfig.h
loopdata.h
) )
set(LIBXML_INCLUDE_DIR /usr/include/libxml2) set(LIBXML_INCLUDE_DIR /usr/include/libxml2)

View File

@ -7,8 +7,11 @@
#include <poll.h> #include <poll.h>
#include <termios.h> #include <termios.h>
#include <signal.h> #include <signal.h>
#include <uv.h>
#include "gameloop.h" #include "gameloop.h"
#include "loopdata.h"
#include "../helper/parameters.h" #include "../helper/parameters.h"
#include "../helper/confighelper.h" #include "../helper/confighelper.h"
#include "../devices/simdevice.h" #include "../devices/simdevice.h"
@ -22,15 +25,17 @@ bool go = false;
bool go2 = false; bool go2 = false;
struct sigaction act; struct sigaction act;
void sighandler(int signum, siginfo_t* info, void* ptr)
{ uv_idle_t idler;
sloge("caught signal"); uv_timer_t datachecktimer;
go = false; uv_timer_t datamaptimer;
go2 = false;
//gfx_clear(pixels, pixels_len); bool doui = false;
//gfx_swapbuffers(); int appstate = 0;
//gfx_close();
} void shmdatamapcallback(uv_timer_t* handle);
void datacheckcallback(uv_timer_t* handle);
void startdatalogger(MonocoqueSettings* ms, loop_data* l);
int showstats(SimData* simdata) int showstats(SimData* simdata)
{ {
@ -181,26 +186,61 @@ int showstats(SimData* simdata)
fflush(stdout); fflush(stdout);
} }
void shmdatamapcallback(uv_timer_t* handle)
{
int clilooper(SimDevice* devices, int numdevices, Parameters* p, SimData* simdata, SimMap* simmap) void* b = uv_handle_get_data((uv_handle_t*) handle);
loop_data* f = (loop_data*) b;
SimData* simdata = f->simdata;
SimMap* simmap = f->simmap;
MonocoqueSettings* ms = f->ms;
//appstate = 2;
if (appstate == 2)
{ {
struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI }; simdatamap(simdata, simmap, f->sim);
double update_rate = DEFAULT_UPDATE_RATE;
char ch; if (doui == true)
int t=0;
int s=0;
go2 = true;
slogd("game data found, starting game loop");
while (go2 == true && simdata->simstatus > 1)
{ {
simdatamap(simdata, simmap, p->sim); slogi("looking for ui config %s", ms->config_str);
showstats(simdata); int confignum = getconfigtouse(ms->config_str, simdata->car, f->sim);
t++; int configureddevices;
s++; configcheck(ms->config_str, confignum, &configureddevices);
if(simdata->rpms<100)
DeviceSettings* ds = malloc(configureddevices * sizeof(DeviceSettings));
slogd("loading confignum %i, with %i devices.", confignum, configureddevices);
f->numdevices = uiloadconfig(ms->config_str, confignum, configureddevices, ms, ds);
f->simdevices = malloc(f->numdevices * sizeof(SimDevice));
int initdevices = devinit(f->simdevices, configureddevices, ds, ms);
int i = 0;
for( i = 0; i < configureddevices; i++)
{ {
simdata->rpms=100; settingsfree(ds[i]);
} }
free(ds);
doui = false;
}
else
{
showstats(simdata);
SimDevice* devices = f->simdevices;
int numdevices = f->numdevices;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
}
}
if (f->simstate == false || simdata->simstatus <= 1 || appstate <= 1)
{
f->uion = false;
SimDevice* devices = f->simdevices;
int numdevices = f->numdevices;
for (int x = 0; x < numdevices; x++) for (int x = 0; x < numdevices; x++)
{ {
@ -209,51 +249,82 @@ int clilooper(SimDevice* devices, int numdevices, Parameters* p, SimData* simdat
devices[x].update(&devices[x], simdata); devices[x].update(&devices[x], simdata);
} }
} }
for (int x = 0; x < numdevices; x++)
if( poll(&mypoll, 1, 1000.0/update_rate) )
{ {
if (devices[x].initialized == true)
{
devices[x].free(&devices[x]);
}
}
free(devices);
int r = simfree(simdata, simmap, f->sim);
slogd("simfree returned %i", r);
f->numdevices = 0;
slogi("stopped mapping data, press q again to quit");
//stopui(ms->ui_type, f);
// free loop data
uv_timer_stop(handle);
uv_timer_start(&datachecktimer, datacheckcallback, 3000, 1000);
}
}
void datacheckcallback(uv_timer_t* handle)
{
void* b = uv_handle_get_data((uv_handle_t*) handle);
loop_data* f = (loop_data*) b;
SimData* simdata = f->simdata;
SimMap* simmap = f->simmap;
if ( appstate == 1 )
{
getSim(simdata, simmap, &f->simstate, &f->sim);
}
if (f->simstate == true)
{
if ( appstate == 1 )
{
appstate++;
doui = true;
uv_timer_start(&datamaptimer, shmdatamapcallback, 2000, 16);
uv_timer_stop(handle);
}
}
if (appstate == 0)
{
slogi("stopping checking for data");
uv_timer_stop(handle);
}
}
void cb(uv_poll_t* handle, int status, int events)
{
char ch;
scanf("%c", &ch); scanf("%c", &ch);
if (ch == 'q') if (ch == 'q')
{ {
slogd("User gameloop exit requested."); appstate--;
go2 = false; slogi("User requested stop appstate is now %i", appstate);
} fprintf(stdout, "User requested stop appstate is now %i\n", appstate);
} fflush(stdout);
} }
simdata->velocity = 0; if (appstate == 0)
simdata->rpms = 100;
simdata->gear = MONOCOQUE_GEAR_NEUTRAL;
for (int x = 0; x < numdevices; x++)
{ {
if (devices[x].initialized == true) slogi("Monocoque is exiting...");
uv_timer_stop(&datachecktimer);
uv_poll_stop(handle);
}
}
int monocoque_mainloop(MonocoqueSettings* ms)
{ {
devices[x].update(&devices[x], simdata);
}
}
fprintf(stdout, "\n");
int r = simfree(simdata, simmap, p->sim);
slogd("simfree returned %i", r);
return 0;
}
int looper(SimDevice* devices, int numdevices, Parameters* p)
{
memset(&act, 0, sizeof(act));
act.sa_sigaction = sighandler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGTERM, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGTSTP, &act, NULL);
SimData* simdata = malloc(sizeof(SimData)); SimData* simdata = malloc(sizeof(SimData));
SimMap* simmap = malloc(sizeof(SimMap)); SimMap* simmap = malloc(sizeof(SimMap));
simdata->tyrediameter[0] = -1;
simdata->tyrediameter[1] = -1;
simdata->tyrediameter[2] = -1;
simdata->tyrediameter[3] = -1;
struct termios newsettings, canonicalmode; struct termios newsettings, canonicalmode;
tcgetattr(0, &canonicalmode); tcgetattr(0, &canonicalmode);
@ -265,64 +336,190 @@ int looper(SimDevice* devices, int numdevices, Parameters* p)
char ch; char ch;
struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI }; struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
uv_poll_t* poll = (uv_poll_t*) malloc(uv_handle_size(UV_POLL));
loop_data* baton = (loop_data*) malloc(sizeof(loop_data));
baton->simmap = simmap;
baton->simdata = simdata;
baton->ms = ms;
baton->simstate = false;
baton->uion = false;
baton->sim = 0;
baton->req.data = (void*) baton;
uv_handle_set_data((uv_handle_t*) &datachecktimer, (void*) baton);
uv_handle_set_data((uv_handle_t*) &datamaptimer, (void*) baton);
uv_handle_set_data((uv_handle_t*) poll, (void*) baton);
appstate = 1;
slogd("setting initial app state");
uv_timer_init(uv_default_loop(), &datachecktimer);
fprintf(stdout, "Searching for sim data... Press q to quit...\n"); fprintf(stdout, "Searching for sim data... Press q to quit...\n");
p->simon = false; uv_timer_start(&datachecktimer, datacheckcallback, 1000, 1000);
double update_rate = SIM_CHECK_RATE;
go = true;
while (go == true)
{
p->simon = false;
getSim(simdata, simmap, &p->simon, &p->sim);
if (p->simon == true && simdata->simstatus > 1)
{
slogi("preparing game loop with %i devices...", numdevices);
slogi("sending initial data to devices"); if (0 != uv_poll_init(uv_default_loop(), poll, 0))
simdata->velocity = 16;
simdata->rpms = 100;
for (int x = 0; x < numdevices; x++)
{ {
devices[x].update(&devices[x], simdata); return 1;
} };
sleep(3); if (0 != uv_poll_start(poll, UV_READABLE, cb))
{
return 2;
};
clilooper(devices, numdevices, p, simdata, simmap);
}
if (p->simon == true)
{
p->simon = false;
fprintf(stdout, "Searching for sim data... Press q again to quit...\n");
sleep(2);
}
if (poll(&mypoll, 1, 1000.0/update_rate) ) uv_timer_init(uv_default_loop(), &datamaptimer);
{
if (go != false )
{
scanf("%c", &ch);
if(ch == 'q')
{
slogd("User application exit requested.");
go = false;
}
}
}
}
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
fprintf(stdout, "\n"); fprintf(stdout, "\n");
fflush(stdout); fflush(stdout);
tcsetattr(0, TCSANOW, &canonicalmode); tcsetattr(0, TCSANOW, &canonicalmode);
int r = simfree(simdata, simmap, p->sim);
slogd("simfree returned %i", r);
free(simdata); free(simdata);
free(simmap); free(simmap);
return 0; return 0;
} }
//int clilooper(SimDevice* devices, int numdevices, Parameters* p, SimData* simdata, SimMap* simmap)
//{
// struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
// double update_rate = DEFAULT_UPDATE_RATE;
// char ch;
// int t=0;
// int s=0;
// go2 = true;
// slogd("game data found, starting game loop");
// while (go2 == true && simdata->simstatus > 1)
// {
// simdatamap(simdata, simmap, p->sim);
// showstats(simdata);
// t++;
// s++;
// if(simdata->rpms<100)
// {
// simdata->rpms=100;
// }
//
// for (int x = 0; x < numdevices; x++)
// {
// if (devices[x].initialized == true)
// {
// devices[x].update(&devices[x], simdata);
// }
// }
//
// if( poll(&mypoll, 1, 1000.0/update_rate) )
// {
// scanf("%c", &ch);
// if(ch == 'q')
// {
// slogd("User gameloop exit requested.");
// go2 = false;
// }
// }
// }
//
// simdata->velocity = 0;
// simdata->rpms = 100;
// simdata->gear = MONOCOQUE_GEAR_NEUTRAL;
// for (int x = 0; x < numdevices; x++)
// {
// if (devices[x].initialized == true)
// {
// devices[x].update(&devices[x], simdata);
// }
// }
//
// fprintf(stdout, "\n");
// int r = simfree(simdata, simmap, p->sim);
// slogd("simfree returned %i", r);
//
// return 0;
//}
//int looper(SimDevice* devices, int numdevices, Parameters* p)
//{
// memset(&act, 0, sizeof(act));
// act.sa_sigaction = sighandler;
// act.sa_flags = SA_SIGINFO;
// sigaction(SIGTERM, &act, NULL);
// sigaction(SIGINT, &act, NULL);
// sigaction(SIGTSTP, &act, NULL);
//
// SimData* simdata = malloc(sizeof(SimData));
// SimMap* simmap = malloc(sizeof(SimMap));
// simdata->tyrediameter[0] = -1;
// simdata->tyrediameter[1] = -1;
// simdata->tyrediameter[2] = -1;
// simdata->tyrediameter[3] = -1;
//
// struct termios newsettings, canonicalmode;
// tcgetattr(0, &canonicalmode);
// newsettings = canonicalmode;
// newsettings.c_lflag &= (~ICANON & ~ECHO);
// newsettings.c_cc[VMIN] = 1;
// newsettings.c_cc[VTIME] = 0;
// tcsetattr(0, TCSANOW, &newsettings);
// char ch;
// struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
//
// fprintf(stdout, "Searching for sim data... Press q to quit...\n");
// p->simon = false;
// double update_rate = SIM_CHECK_RATE;
// go = true;
// while (go == true)
// {
// p->simon = false;
// getSim(simdata, simmap, &p->simon, &p->sim);
//
// if (p->simon == true && simdata->simstatus > 1)
// {
// slogi("preparing game loop with %i devices...", numdevices);
//
//
// slogi("sending initial data to devices");
// simdata->velocity = 16;
// simdata->rpms = 100;
// for (int x = 0; x < numdevices; x++)
// {
// devices[x].update(&devices[x], simdata);
// }
// sleep(3);
//
// clilooper(devices, numdevices, p, simdata, simmap);
// }
// if (p->simon == true)
// {
// p->simon = false;
// fprintf(stdout, "Searching for sim data... Press q again to quit...\n");
// sleep(2);
// }
//
// if (poll(&mypoll, 1, 1000.0/update_rate) )
// {
// if (go != false )
// {
// scanf("%c", &ch);
// if(ch == 'q')
// {
// slogd("User application exit requested.");
// go = false;
// }
// }
// }
// }
//
// fprintf(stdout, "\n");
// fflush(stdout);
// tcsetattr(0, TCSANOW, &canonicalmode);
//
// int r = simfree(simdata, simmap, p->sim);
// slogd("simfree returned %i", r);
// free(simdata);
// free(simmap);
//
// return 0;
//}
int tester(SimDevice* devices, int numdevices) int tester(SimDevice* devices, int numdevices)
{ {

View File

@ -3,3 +3,5 @@
int tester(SimDevice* devices, int numdevices); int tester(SimDevice* devices, int numdevices);
int looper(SimDevice* devices, int numdevices, Parameters* p); int looper(SimDevice* devices, int numdevices, Parameters* p);
int monocoque_mainloop(MonocoqueSettings* ms);

View File

@ -0,0 +1,25 @@
#ifndef _LOOPDATA_H
#define _LOOPDATA_H
#include <uv.h>
#include "../helper/parameters.h"
#include "../helper/confighelper.h"
#include "../devices/simdevice.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simmapper.h"
typedef struct loop_data
{
uv_work_t req;
Simulator sim;
bool simstate;
bool uion;
int numdevices;
MonocoqueSettings* ms;
SimData* simdata;
SimMap* simmap;
SimDevice* simdevices;
} loop_data;
#endif

View File

@ -176,6 +176,55 @@ int strtodev(const char* device_type, const char* device_subtype, DeviceSettings
return MONOCOQUE_ERROR_NONE; return MONOCOQUE_ERROR_NONE;
} }
int getconfigtouse(const char* config_file_str, char* car, int sim)
{
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
return -1;
}
config_setting_t* config = NULL;
config_setting_t* config_widgets = NULL;
config = config_lookup(&cfg, "configs");
int configs = config_setting_length(config);
const char* temp;
config_setting_t* config_config = NULL;
int j = 0;
if ( configs == 1 )
{
return 0;
}
int confignum = 0;
for (j = 0; j < configs; j++)
{
config_config = config_setting_get_elem(config, j);
int found = 0;
int csim = 0;
config_setting_lookup_int(config_config, "sim", &csim);
if (csim != sim && csim != 0)
{
continue;
}
found = config_setting_lookup_string(config_config, "car", &temp);
if(strcicmp("default", car) == 0)
{
confignum = j;
}
if(strcicmp(temp, car) != 0)
{
continue;
}
confignum = j;
break;
}
return confignum;
}
int loadtachconfig(const char* config_file, DeviceSettings* ds) int loadtachconfig(const char* config_file, DeviceSettings* ds)
{ {
@ -312,6 +361,28 @@ int loadconfig(const char* config_file, DeviceSettings* ds)
return 0; return 0;
} }
int configcheck(const char* config_file_str, int confignum, int* devices)
{
slogt("ui config check");
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
}
config_setting_t* config = NULL;
config = config_lookup(&cfg, "configs");
config_setting_t* selectedconfig = config_setting_get_elem(config, confignum);
slogt("selected num %i", confignum);
config_setting_t* config_devices = NULL;
config_devices = config_setting_lookup(selectedconfig, "devices");
*devices = config_setting_length(config_devices);
config_destroy(&cfg);
return 0;
//return cfg;
}
int devsetup(const char* device_type, const char* device_subtype, const char* config_file, MonocoqueSettings* ms, DeviceSettings* ds, config_setting_t* device_settings) int devsetup(const char* device_type, const char* device_subtype, const char* config_file, MonocoqueSettings* ms, DeviceSettings* ds, config_setting_t* device_settings)
{ {
int error = MONOCOQUE_ERROR_NONE; int error = MONOCOQUE_ERROR_NONE;
@ -442,6 +513,69 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
return error; return error;
} }
int uiloadconfig(const char* config_file_str, int confignum, int configureddevices, MonocoqueSettings* ms, DeviceSettings* ds)
{
int numdevices = 0;
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
}
else
{
slogi("Parsing config file");
config_setting_t* config = NULL;
config = config_lookup(&cfg, "configs");
config_setting_t* selectedconfig = config_setting_get_elem(config, confignum);
config_setting_t* config_devices = NULL;
config_devices = config_setting_lookup(selectedconfig, "devices");
int i = 0;
int error = MONOCOQUE_ERROR_NONE;
while (i<configureddevices)
{
error = MONOCOQUE_ERROR_NONE;
DeviceSettings settings;
config_setting_t* config_device = config_setting_get_elem(config_devices, i);
const char* device_type;
const char* device_subtype;
const char* device_config_file;
config_setting_lookup_string(config_device, "device", &device_type);
config_setting_lookup_string(config_device, "type", &device_subtype);
config_setting_lookup_string(config_device, "config", &device_config_file);
//slogt("device type: %s", device_type);
//slogt("device sub type: %s", device_subtype);
//slogt("device config file: %s", device_config_file);
if (error == MONOCOQUE_ERROR_NONE)
{
error = devsetup(device_type, device_subtype, device_config_file, ms, &settings, config_device);
}
if (error == MONOCOQUE_ERROR_NONE)
{
numdevices++;
}
ds[i] = settings;
i++;
}
}
config_destroy(&cfg);
return numdevices;
}
int settingsfree(DeviceSettings ds) int settingsfree(DeviceSettings ds)
{ {

View File

@ -117,6 +117,9 @@ typedef struct
int configcheck; int configcheck;
int useconfig; int useconfig;
char* tyre_diameter_config; char* tyre_diameter_config;
char* config_str;
char* log_filename_str;
char* log_dirname_str;
} }
MonocoqueSettings; MonocoqueSettings;
@ -186,4 +189,10 @@ int settingsfree(DeviceSettings ds);
int strcicmp(char const *a, char const *b); int strcicmp(char const *a, char const *b);
int getconfigtouse(const char* config_file_str, char* car, int sim);
int configcheck(const char* config_file_str, int confignum, int* devices);
int uiloadconfig(const char* config_file_str, int confignum, int configureddevices, MonocoqueSettings* ms, DeviceSettings* ds);
#endif #endif

View File

@ -13,6 +13,36 @@
#include <string.h> #include <string.h>
void create_dir(char* dir)
{
struct stat st = {0};
if (stat(dir, &st) == -1)
{
mkdir(dir, 0700);
}
}
void create_xdg_dir(const char* dir)
{
struct stat st = {0};
if (stat(dir, &st) == -1)
{
mkdir(dir, 0700);
}
}
char* create_user_dir(char* home_dir_str, const char* dirtype, const char* programname)
{
// +3 for slashes
size_t ss = (4 + strlen(home_dir_str) + strlen(dirtype) + strlen(programname));
char* config_dir_str = malloc(ss);
snprintf (config_dir_str, ss, "%s/%s/%s/", home_dir_str, dirtype, programname);
create_dir(config_dir_str);
return config_dir_str;
}
char* gethome() char* gethome()
{ {
char* homedir = getenv("HOME"); char* homedir = getenv("HOME");
@ -175,28 +205,67 @@ void restrict_folders_to_cache(char* path, int cachesize)
} }
bool does_directory_exist(char* path, char* dirname) bool does_directory_exist(char* path)
{ {
struct dirent* de; DIR* dir = opendir(path);
DIR* dr = opendir(path); if (dir)
if (dr == NULL)
{ {
printf("Could not open current directory"); // Directory exists
closedir(dir);
return true;
}
else
{
// Directory does not exist or cannot be opened
return false; return false;
} }
}
// Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html bool does_file_exist(const char* file)
bool answer = false;
while ((de = readdir(dr)) != NULL)
{ {
if (strcmp(dirname,de->d_name) == 0) if (file == NULL)
{ {
answer = true; return false;
} }
#if defined(OS_WIN)
#if defined(WIN_API)
// if you want the WinAPI, versus CRT
if (strnlen(file, MAX_PATH+1) > MAX_PATH)
{
// ... throw error here or ...
return false;
} }
DWORD res = GetFileAttributesA(file);
closedir(dr); return (res != INVALID_FILE_ATTRIBUTES &&
return answer; !(res& FILE_ATTRIBUTE_DIRECTORY));
#else
// Use Win CRT
struct stat fi;
if (_stat(file, &fi) == 0)
{
#if defined(S_ISSOCK)
// sockets come back as a 'file' on some systems
// so make sure it's not a socket or directory
// (in other words, make sure it's an actual file)
return !(S_ISDIR(fi.st_mode)) &&
!(S_ISSOCK(fi.st_mode));
#else
return !(S_ISDIR(fi.st_mode));
#endif
}
return false;
#endif
#else
struct stat fi;
if (stat(file, &fi) == 0)
{
#if defined(S_ISSOCK)
return !(S_ISDIR(fi.st_mode)) &&
!(S_ISSOCK(fi.st_mode));
#else
return !(S_ISDIR(fi.st_mode));
#endif
}
return false;
#endif
} }

View File

@ -3,10 +3,14 @@
#include <stdbool.h> #include <stdbool.h>
void create_dir(char* dir);
void create_xdg_dir(const char* dir);
char* create_user_dir(char* home_dir_str, const char* dirtype, const char* programpath);
char* gethome(); char* gethome();
char* str2md5(const char* str, int length); char* str2md5(const char* str, int length);
bool does_directory_exist(char* path, char* dirname); bool does_directory_exist(char* path);
void restrict_folders_to_cache(char* path, int cachesize); void restrict_folders_to_cache(char* path, int cachesize);
void delete_dir(char* path); void delete_dir(char* path);
bool does_file_exist(const char* file);
#endif #endif

View File

@ -2,12 +2,39 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <libgen.h>
#include <libconfig.h> #include <libconfig.h>
#include <argtable2.h> #include <argtable2.h>
#include <regex.h> #include <regex.h>
int freeparams(Parameters* p)
{
if(p->config_dirpath != NULL)
{
free(p->config_dirpath);
}
if(p->config_filepath != NULL)
{
free(p->config_filepath);
}
if(p->log_filename_str != NULL)
{
free(p->log_filename_str);
}
if(p->log_fullfilename_str != NULL)
{
free(p->log_fullfilename_str);
}
if(p->log_dirname_str != NULL)
{
free(p->log_dirname_str);
}
return 0;
}
ConfigError getParameters(int argc, char** argv, Parameters* p) ConfigError getParameters(int argc, char** argv, Parameters* p)
{ {
@ -18,6 +45,10 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
p->max_revs = 0; p->max_revs = 0;
p->verbosity_count = 0; p->verbosity_count = 0;
p->user_specified_config_file = false;
p->user_specified_log_file = false;
p->user_specified_config_dir = false;
// setup argument handling structures // setup argument handling structures
const char* progname = "monocoque"; const char* progname = "monocoque";
@ -26,11 +57,13 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
struct arg_lit* arg_verbosity3 = arg_litn("v","verbose", 0, 2, "increase logging verbosity"); struct arg_lit* arg_verbosity3 = arg_litn("v","verbose", 0, 2, "increase logging verbosity");
struct arg_rex* cmd1 = arg_rex1(NULL, NULL, "play", NULL, REG_ICASE, NULL); struct arg_rex* cmd1 = arg_rex1(NULL, NULL, "play", NULL, REG_ICASE, NULL);
struct arg_str* arg_sim = arg_strn("s", "sim", "<gamename>", 0, 1, NULL); struct arg_file* arg_conf = arg_filen(NULL, "uiconf", "<config_file>", 0, 1, NULL);
struct arg_file* arg_log = arg_filen("l", "log", "<log_file>", 0, 1, NULL);
struct arg_str* arg_confdir = arg_strn(NULL, "configdir", "config_dir>", 0, 1, NULL);
struct arg_lit* help = arg_litn(NULL,"help", 0, 1, "print this help and exit"); struct arg_lit* help = arg_litn(NULL,"help", 0, 1, "print this help and exit");
struct arg_lit* vers = arg_litn(NULL,"version", 0, 1, "print version information and exit"); struct arg_lit* vers = arg_litn(NULL,"version", 0, 1, "print version information and exit");
struct arg_end* end1 = arg_end(20); struct arg_end* end1 = arg_end(20);
void* argtable1[] = {cmd1,arg_sim,arg_verbosity1,help,vers,end1}; void* argtable1[] = {cmd1,arg_log,arg_conf,arg_verbosity1,help,vers,end1};
int nerrors1; int nerrors1;
struct arg_rex* cmd2a = arg_rex1(NULL, NULL, "config", NULL, REG_ICASE, NULL); struct arg_rex* cmd2a = arg_rex1(NULL, NULL, "config", NULL, REG_ICASE, NULL);
@ -83,8 +116,24 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
if (nerrors1==0) if (nerrors1==0)
{ {
p->program_action = A_PLAY; p->program_action = A_PLAY;
p->sim_string = arg_sim->sval[0];
p->verbosity_count = arg_verbosity1->count; p->verbosity_count = arg_verbosity1->count;
if(arg_conf->count > 0)
{
p->config_filepath = strdup(arg_conf->filename[0]);
p->user_specified_config_file = true;
}
if(arg_log->count > 0)
{
char* filename = strdup(arg_log->filename[0]);
p->log_fullfilename_str = strdup(arg_log->filename[0]);
p->log_filename_str = strdup(arg_log->basename[0]);
char* dname;
dname = dirname(filename);
p->log_dirname_str = strdup(dname);
p->user_specified_log_file = true;
free(filename);
}
exitcode = E_SUCCESS_AND_DO; exitcode = E_SUCCESS_AND_DO;
} }
else else

View File

@ -15,6 +15,16 @@ typedef struct
Simulator sim; Simulator sim;
bool simon; bool simon;
char* config_filepath;
char* config_dirpath;
bool user_specified_config_file;
bool user_specified_config_dir;
bool user_specified_log_file;
char* log_filename_str;
char* log_fullfilename_str;
char* log_dirname_str;
} }
Parameters; Parameters;
@ -35,6 +45,7 @@ typedef enum
} }
ConfigError; ConfigError;
int freeparams(Parameters* p);
ConfigError getParameters(int argc, char** argv, Parameters* p); ConfigError getParameters(int argc, char** argv, Parameters* p);
struct _errordesc struct _errordesc

View File

@ -2,8 +2,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <string.h> #include <string.h>
#include <basedir_fs.h>
#include <libconfig.h> #include <libconfig.h>
#include "gameloop/gameloop.h" #include "gameloop/gameloop.h"
#include "gameloop/tachconfig.h" #include "gameloop/tachconfig.h"
#include "devices/simdevice.h" #include "devices/simdevice.h"
@ -14,27 +15,7 @@
#include "simulatorapi/simapi/simapi/simdata.h" #include "simulatorapi/simapi/simapi/simdata.h"
#include "slog/slog.h" #include "slog/slog.h"
#define PROGRAM_NAME "monocoque"
int create_dir(char* dir)
{
struct stat st = {0};
if (stat(dir, &st) == -1)
{
mkdir(dir, 0700);
}
}
char* create_user_dir(char* dirtype)
{
char* home_dir_str = gethome();
char* config_dir_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen(dirtype) + strlen("monocoque/"));
strcpy(config_dir_str, home_dir_str);
strcat(config_dir_str, dirtype);
strcat(config_dir_str, "monocoque");
create_dir(config_dir_str);
free(config_dir_str);
}
void display_banner() void display_banner()
{ {
@ -45,10 +26,57 @@ void display_banner()
printf("/_/ /_/ \\____/ /_/ |_/ \\____/ \\____/ \\____/ \\___\\_\\\\____/ /_____/ \n"); printf("/_/ /_/ \\____/ /_/ |_/ \\____/ \\____/ \\____/ \\___\\_\\\\____/ /_____/ \n");
} }
void SetSettingsFromParameters(Parameters* p, MonocoqueSettings* ms, char* configdir_str, char* cachedir_str)
{
if(p->user_specified_config_file == true && does_file_exist(p->config_filepath))
{
ms->config_str = strdup(p->config_filepath);
}
else
{
if(p->user_specified_config_dir == true && does_directory_exist(p->config_dirpath))
{
asprintf(&ms->config_str, "%s/%s", p->config_dirpath, "monocoque.config");
}
else
{
asprintf(&ms->config_str, "%s%s", configdir_str, "monocoque.config");
}
}
if(p->user_specified_log_file == true && does_file_exist(p->log_fullfilename_str))
{
ms->log_dirname_str = strdup(p->log_dirname_str);
ms->log_filename_str = strdup(p->log_filename_str);
}
else
{
ms->log_dirname_str = strdup(cachedir_str);
ms->log_filename_str = strdup("monocoque.log");
}
ms->program_action = A_TEST;
if (p->program_action == A_PLAY)
{
ms->program_action = A_PLAY;
}
if (p->program_action == A_CONFIG_TACH)
{
ms->program_action = A_CONFIG_TACH;
}
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
display_banner(); display_banner();
char* home_dir_str = gethome();
if(home_dir_str == NULL)
{
fprintf(stderr, "You need a home directory");
return 0;
}
Parameters* p = malloc(sizeof(Parameters)); Parameters* p = malloc(sizeof(Parameters));
MonocoqueSettings* ms = malloc(sizeof(MonocoqueSettings));; MonocoqueSettings* ms = malloc(sizeof(MonocoqueSettings));;
@ -57,33 +85,47 @@ int main(int argc, char** argv)
{ {
goto cleanup_final; goto cleanup_final;
} }
ms->program_action = p->program_action;
char* home_dir_str = gethome(); xdgHandle xdg;
create_user_dir("/.config/"); if(!xdgInitHandle(&xdg))
create_user_dir("/.cache/"); {
char* config_file_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen("/.config/") + strlen("monocoque/monocoque.config")); fprintf(stderr, "Function xdgInitHandle() failed, is $HOME unset?");
}
const char* config_home_str = xdgConfigHome(&xdg);
const char* cache_home_str = xdgCacheHome(&xdg);
char* cachedir_str = NULL;
char* configdir_str = NULL;
if(p->user_specified_config_file == false && p->user_specified_config_dir == false)
{
create_xdg_dir(config_home_str);
configdir_str = create_user_dir(home_dir_str, ".config", PROGRAM_NAME);
}
if(p->user_specified_log_file == false)
{
create_xdg_dir(cache_home_str);
cachedir_str = create_user_dir(home_dir_str, ".cache", PROGRAM_NAME);
}
SetSettingsFromParameters(p, ms, configdir_str, cachedir_str);
freeparams(p);
free(p);
//char* config_file_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen("/.config/") + strlen("monocoque/monocoque.config"));
size_t diameters_file_sz = snprintf(NULL, 0, "%s/.config/monocoque/diameters.config", home_dir_str); size_t diameters_file_sz = snprintf(NULL, 0, "%s/.config/monocoque/diameters.config", home_dir_str);
diameters_file_sz += 1; diameters_file_sz += 1;
char* diameters_file_str = ( char* ) malloc(diameters_file_sz); char* diameters_file_str = ( char* ) malloc(diameters_file_sz);
snprintf(diameters_file_str, diameters_file_sz, "%s/.config/monocoque/diameters.config", home_dir_str); snprintf(diameters_file_str, diameters_file_sz, "%s/.config/monocoque/diameters.config", home_dir_str);
char* cache_dir_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen("/.cache/monocoque/"));
strcpy(config_file_str, home_dir_str);
strcat(config_file_str, "/.config/");
strcpy(cache_dir_str, home_dir_str);
strcat(cache_dir_str, "/.cache/monocoque/");
strcat(config_file_str, "monocoque/monocoque.config");
slog_config_t slgCfg; slog_config_t slgCfg;
slog_config_get(&slgCfg); slog_config_get(&slgCfg);
slgCfg.eColorFormat = SLOG_COLORING_TAG; slgCfg.eColorFormat = SLOG_COLORING_TAG;
slgCfg.eDateControl = SLOG_TIME_ONLY; slgCfg.eDateControl = SLOG_TIME_ONLY;
strcpy(slgCfg.sFileName, "monocoque.log"); strcpy(slgCfg.sFileName, ms->log_filename_str);
strcpy(slgCfg.sFilePath, cache_dir_str); strcpy(slgCfg.sFilePath, ms->log_dirname_str);
slgCfg.nTraceTid = 0; slgCfg.nTraceTid = 0;
slgCfg.nToScreen = 1; slgCfg.nToScreen = 1;
slgCfg.nUseHeap = 0; slgCfg.nUseHeap = 0;
@ -105,24 +147,22 @@ int main(int argc, char** argv)
ms->configcheck = 0; ms->configcheck = 0;
free(diameters_file_str); free(diameters_file_str);
slogi("Loading configuration file: %s", config_file_str); slogi("Loading configuration file: %s", ms->config_str);
slogd("using diameters file %s %i", ms->tyre_diameter_config, ms->configcheck); slogd("using diameters file %s %i", ms->tyre_diameter_config, ms->configcheck);
config_t cfg; config_t cfg;
config_init(&cfg); config_init(&cfg);
config_setting_t* config_devices = NULL; config_setting_t* config_devices = NULL;
if (!config_read_file(&cfg, config_file_str)) if (!config_read_file(&cfg, ms->config_str))
{ {
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg)); fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
goto cleanup_final;
} }
else else
{ {
slogi("Openend monocoque configuration file"); slogi("Openend monocoque configuration file");
config_devices = config_lookup(&cfg, "devices");
} }
free(config_file_str);
free(cache_dir_str);
if (p->program_action == A_CONFIG_TACH) if (ms->program_action == A_CONFIG_TACH)
{ {
int error = 0; int error = 0;
SimDevice* tachdev = malloc(sizeof(SimDevice)); SimDevice* tachdev = malloc(sizeof(SimDevice));
@ -169,70 +209,25 @@ int main(int argc, char** argv)
{ {
int error = 0; int error = 0;
int configureddevices = config_setting_length(config_devices);
int numdevices = 0;
DeviceSettings ds[configureddevices];
slogi("found %i devices in configuration", configureddevices);
int i = 0;
error = MONOCOQUE_ERROR_NONE; error = MONOCOQUE_ERROR_NONE;
while (i<configureddevices)
{
DeviceSettings settings;
config_setting_t* config_device = config_setting_get_elem(config_devices, i);
const char* device_type;
const char* device_subtype;
const char* device_config_file;
config_setting_lookup_string(config_device, "device", &device_type);
config_setting_lookup_string(config_device, "type", &device_subtype);
config_setting_lookup_string(config_device, "config", &device_config_file);
//slogt("device type: %s", device_type);
//slogt("device sub type: %s", device_subtype);
//slogt("device config file: %s", device_config_file);
if (error == MONOCOQUE_ERROR_NONE)
{
error = devsetup(device_type, device_subtype, device_config_file, ms, &settings, config_device);
}
if (error == MONOCOQUE_ERROR_NONE)
{
numdevices++;
}
ds[i] = settings;
i++;
}
i = 0;
int j = 0;
error = MONOCOQUE_ERROR_NONE;
setupsound(); setupsound();
if (p->program_action == A_PLAY) if (ms->program_action == A_PLAY)
{ {
ms->useconfig = 1; ms->useconfig = 1;
} }
SimDevice* devices = malloc(numdevices * sizeof(SimDevice));
int initdevices = devinit(devices, configureddevices, ds, ms);
bool pulseaudio = false;
if (p->program_action == A_PLAY) bool pulseaudio = false;
if (ms->program_action == A_PLAY)
{ {
slogi("running monocoque in gameloop mode.."); slogi("running monocoque in gameloop mode..");
//error = strtogame(p->sim_string, ms);
//if (error != MONOCOQUE_ERROR_NONE)
//{
// goto cleanup_final;
//}
#ifdef USE_PULSEAUDIO #ifdef USE_PULSEAUDIO
pa_threaded_mainloop_unlock(mainloop); pa_threaded_mainloop_unlock(mainloop);
pulseaudio = true; pulseaudio = true;
#endif #endif
error = looper(devices, numdevices, p); //error = looper(devices, numdevices, p);
error = monocoque_mainloop(ms);
if (error == MONOCOQUE_ERROR_NONE) if (error == MONOCOQUE_ERROR_NONE)
{ {
slogi("Game loop exited succesfully with error code: %i", error); slogi("Game loop exited succesfully with error code: %i", error);
@ -252,7 +247,23 @@ int main(int argc, char** argv)
#endif #endif
ms->useconfig = 0; ms->useconfig = 0;
error = tester(devices, numdevices);
int confignum = getconfigtouse(ms->config_str, "default", 0);
int configureddevices;
configcheck(ms->config_str, confignum, &configureddevices);
DeviceSettings* ds = malloc(configureddevices * sizeof(DeviceSettings));
slogd("loading confignum %i, with %i devices.", confignum, configureddevices);
int numdevices = uiloadconfig(ms->config_str, confignum, configureddevices, ms, ds);
SimDevice* simdevices = malloc(numdevices * sizeof(SimDevice));
int initdevices = devinit(simdevices, configureddevices, ds, ms);
for( int i = 0; i < configureddevices; i++)
{
settingsfree(ds[i]);
}
free(ds);
error = tester(simdevices, numdevices);
if (error == MONOCOQUE_ERROR_NONE) if (error == MONOCOQUE_ERROR_NONE)
{ {
slogi("Test exited succesfully with error code: %i", error); slogi("Test exited succesfully with error code: %i", error);
@ -261,35 +272,22 @@ int main(int argc, char** argv)
{ {
sloge("Test exited with error code: %i", error); sloge("Test exited with error code: %i", error);
} }
}
for (int x = 0; x < numdevices; x++) for (int x = 0; x < numdevices; x++)
{ {
if (devices[x].initialized == true) if (simdevices[x].initialized == true)
{ {
devices[x].free(&devices[x]); simdevices[x].free(&simdevices[x]);
}
} }
} }
if(pulseaudio == true) if(pulseaudio == true)
{ {
freesound(); freesound();
} }
i = 0;
// improve the api around the config helper
// i don't like that i stack allocated but hid a malloc inside
for( i = 0; i < configureddevices; i++)
{
settingsfree(ds[i]);
}
} }
configcleanup:
config_destroy(&cfg);
cleanup_final: cleanup_final:
if(ms->tyre_diameter_config != NULL) if(ms->tyre_diameter_config != NULL)
@ -297,7 +295,6 @@ cleanup_final:
free(ms->tyre_diameter_config); free(ms->tyre_diameter_config);
} }
free(ms); free(ms);
free(p);
exit(0); exit(0);
} }