diff --git a/CMakeLists.txt b/CMakeLists.txt index a76cabc..ad3a81d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,10 +37,10 @@ add_executable(monocoque src/monocoque/monocoque.c) if(USE_PULSEAUDIO) message("Using pulseaudio backend...") 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() 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() target_include_directories(monocoque PUBLIC config ${LIBXML_INCLUDE_DIR}) diff --git a/src/monocoque/devices/sound/usb_generic_shaker_pulse.c b/src/monocoque/devices/sound/usb_generic_shaker_pulse.c index 3d924bd..1a4c416 100644 --- a/src/monocoque/devices/sound/usb_generic_shaker_pulse.c +++ b/src/monocoque/devices/sound/usb_generic_shaker_pulse.c @@ -78,15 +78,12 @@ void stream_state_cb(pa_stream *s, void *mainloop) { int usb_generic_shaker_free(SoundDevice* sounddevice) { int err = 0; - //err = Pa_CloseStream( sounddevice->stream ); - //if( err != paNoError ) - //{ - // err = Pa_Terminate(); - //} if (sounddevice->stream) { + pa_stream_disconnect(sounddevice->stream); pa_stream_unref(sounddevice->stream); - pa_xfree(sounddevice->stream); + // why is this wrong + //pa_xfree(sounddevice->stream); } return err; } diff --git a/src/monocoque/devices/sounddevice.c b/src/monocoque/devices/sounddevice.c index a85375c..50a0e06 100644 --- a/src/monocoque/devices/sounddevice.c +++ b/src/monocoque/devices/sounddevice.c @@ -104,8 +104,7 @@ int sounddev_free(SimDevice* this) { SoundDevice* sounddevice = (void *) this->derived; - //figure out why this is causing problems - //usb_generic_shaker_free(sounddevice); + usb_generic_shaker_free(sounddevice); free(sounddevice); diff --git a/src/monocoque/gameloop/CMakeLists.txt b/src/monocoque/gameloop/CMakeLists.txt index 8a32d67..13a0629 100644 --- a/src/monocoque/gameloop/CMakeLists.txt +++ b/src/monocoque/gameloop/CMakeLists.txt @@ -3,6 +3,7 @@ set(gameloop_source_files gameloop.h tachconfig.c tachconfig.h + loopdata.h ) set(LIBXML_INCLUDE_DIR /usr/include/libxml2) diff --git a/src/monocoque/gameloop/gameloop.c b/src/monocoque/gameloop/gameloop.c index fe60be4..6e67231 100644 --- a/src/monocoque/gameloop/gameloop.c +++ b/src/monocoque/gameloop/gameloop.c @@ -7,8 +7,11 @@ #include #include #include +#include #include "gameloop.h" +#include "loopdata.h" + #include "../helper/parameters.h" #include "../helper/confighelper.h" #include "../devices/simdevice.h" @@ -22,15 +25,17 @@ bool go = false; bool go2 = false; struct sigaction act; -void sighandler(int signum, siginfo_t* info, void* ptr) -{ - sloge("caught signal"); - go = false; - go2 = false; - //gfx_clear(pixels, pixels_len); - //gfx_swapbuffers(); - //gfx_close(); -} + +uv_idle_t idler; +uv_timer_t datachecktimer; +uv_timer_t datamaptimer; + +bool doui = false; +int appstate = 0; + +void shmdatamapcallback(uv_timer_t* handle); +void datacheckcallback(uv_timer_t* handle); +void startdatalogger(MonocoqueSettings* ms, loop_data* l); int showstats(SimData* simdata) { @@ -181,26 +186,61 @@ int showstats(SimData* simdata) fflush(stdout); } - -int clilooper(SimDevice* devices, int numdevices, Parameters* p, SimData* simdata, SimMap* simmap) +void shmdatamapcallback(uv_timer_t* handle) { - 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) + + 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) { - simdatamap(simdata, simmap, p->sim); - showstats(simdata); - t++; - s++; - if(simdata->rpms<100) + simdatamap(simdata, simmap, f->sim); + + if (doui == true) { - simdata->rpms=100; + slogi("looking for ui config %s", ms->config_str); + int confignum = getconfigtouse(ms->config_str, simdata->car, f->sim); + int configureddevices; + configcheck(ms->config_str, confignum, &configureddevices); + + 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++) + { + 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++) { @@ -209,51 +249,82 @@ int clilooper(SimDevice* devices, int numdevices, Parameters* p, SimData* simdat 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) + for (int x = 0; x < numdevices; x++) { - devices[x].update(&devices[x], simdata); + 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); } } - fprintf(stdout, "\n"); - int r = simfree(simdata, simmap, p->sim); - slogd("simfree returned %i", r); - - return 0; + if (appstate == 0) + { + slogi("stopping checking for data"); + uv_timer_stop(handle); + } } -int looper(SimDevice* devices, int numdevices, Parameters* p) +void cb(uv_poll_t* handle, int status, int events) +{ + char ch; + scanf("%c", &ch); + if (ch == 'q') + { + appstate--; + slogi("User requested stop appstate is now %i", appstate); + fprintf(stdout, "User requested stop appstate is now %i\n", appstate); + fflush(stdout); + } + + if (appstate == 0) + { + slogi("Monocoque is exiting..."); + uv_timer_stop(&datachecktimer); + uv_poll_stop(handle); + } +} + + + +int monocoque_mainloop(MonocoqueSettings* ms) { - 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); @@ -265,64 +336,190 @@ int looper(SimDevice* devices, int numdevices, Parameters* p) char ch; 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"); - p->simon = false; - double update_rate = SIM_CHECK_RATE; - go = true; - while (go == true) + uv_timer_start(&datachecktimer, datacheckcallback, 1000, 1000); + + + if (0 != uv_poll_init(uv_default_loop(), poll, 0)) { - 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); + return 1; + }; + if (0 != uv_poll_start(poll, UV_READABLE, cb)) + { + return 2; + }; - 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; - } - } - } - } + uv_timer_init(uv_default_loop(), &datamaptimer); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); 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 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) { diff --git a/src/monocoque/gameloop/gameloop.h b/src/monocoque/gameloop/gameloop.h index 714ce22..ff93709 100644 --- a/src/monocoque/gameloop/gameloop.h +++ b/src/monocoque/gameloop/gameloop.h @@ -3,3 +3,5 @@ int tester(SimDevice* devices, int numdevices); int looper(SimDevice* devices, int numdevices, Parameters* p); + +int monocoque_mainloop(MonocoqueSettings* ms); diff --git a/src/monocoque/gameloop/loopdata.h b/src/monocoque/gameloop/loopdata.h new file mode 100644 index 0000000..7b4c8b8 --- /dev/null +++ b/src/monocoque/gameloop/loopdata.h @@ -0,0 +1,25 @@ +#ifndef _LOOPDATA_H +#define _LOOPDATA_H + +#include +#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 diff --git a/src/monocoque/helper/confighelper.c b/src/monocoque/helper/confighelper.c index 69ef359..22e636d 100644 --- a/src/monocoque/helper/confighelper.c +++ b/src/monocoque/helper/confighelper.c @@ -176,6 +176,55 @@ int strtodev(const char* device_type, const char* device_subtype, DeviceSettings 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) { @@ -312,6 +361,28 @@ int loadconfig(const char* config_file, DeviceSettings* ds) 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 error = MONOCOQUE_ERROR_NONE; @@ -442,6 +513,69 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co 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 +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* 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* dr = opendir(path); - - if (dr == NULL) + DIR* dir = opendir(path); + if (dir) { - printf("Could not open current directory"); + // Directory exists + closedir(dir); + return true; + } + else + { + // Directory does not exist or cannot be opened return false; } - - // Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html - bool answer = false; - while ((de = readdir(dr)) != NULL) - { - if (strcmp(dirname,de->d_name) == 0) - { - answer = true; - } - } - - closedir(dr); - return answer; } +bool does_file_exist(const char* file) +{ + if (file == NULL) + { + 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); + return (res != INVALID_FILE_ATTRIBUTES && + !(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 +} diff --git a/src/monocoque/helper/dirhelper.h b/src/monocoque/helper/dirhelper.h index a95ea4e..bed7901 100644 --- a/src/monocoque/helper/dirhelper.h +++ b/src/monocoque/helper/dirhelper.h @@ -3,10 +3,14 @@ #include +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* 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 delete_dir(char* path); +bool does_file_exist(const char* file); #endif diff --git a/src/monocoque/helper/parameters.c b/src/monocoque/helper/parameters.c index 7d3b82b..7edeb47 100644 --- a/src/monocoque/helper/parameters.c +++ b/src/monocoque/helper/parameters.c @@ -2,12 +2,39 @@ #include #include #include +#include #include #include #include +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) { @@ -18,6 +45,10 @@ ConfigError getParameters(int argc, char** argv, Parameters* p) p->max_revs = 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 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_rex* cmd1 = arg_rex1(NULL, NULL, "play", NULL, REG_ICASE, NULL); - struct arg_str* arg_sim = arg_strn("s", "sim", "", 0, 1, NULL); + struct arg_file* arg_conf = arg_filen(NULL, "uiconf", "", 0, 1, NULL); + struct arg_file* arg_log = arg_filen("l", "log", "", 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* vers = arg_litn(NULL,"version", 0, 1, "print version information and exit"); 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; 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) { p->program_action = A_PLAY; - p->sim_string = arg_sim->sval[0]; 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; } else diff --git a/src/monocoque/helper/parameters.h b/src/monocoque/helper/parameters.h index 2756425..dfe6faa 100644 --- a/src/monocoque/helper/parameters.h +++ b/src/monocoque/helper/parameters.h @@ -15,6 +15,16 @@ typedef struct Simulator sim; 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; @@ -35,6 +45,7 @@ typedef enum } ConfigError; +int freeparams(Parameters* p); ConfigError getParameters(int argc, char** argv, Parameters* p); struct _errordesc diff --git a/src/monocoque/monocoque.c b/src/monocoque/monocoque.c index 350d0fb..19bea56 100644 --- a/src/monocoque/monocoque.c +++ b/src/monocoque/monocoque.c @@ -2,8 +2,9 @@ #include #include #include - +#include #include + #include "gameloop/gameloop.h" #include "gameloop/tachconfig.h" #include "devices/simdevice.h" @@ -14,27 +15,7 @@ #include "simulatorapi/simapi/simapi/simdata.h" #include "slog/slog.h" - -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); -} +#define PROGRAM_NAME "monocoque" void display_banner() { @@ -45,10 +26,57 @@ void display_banner() 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) { 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)); MonocoqueSettings* ms = malloc(sizeof(MonocoqueSettings));; @@ -57,33 +85,47 @@ int main(int argc, char** argv) { goto cleanup_final; } - ms->program_action = p->program_action; - char* home_dir_str = gethome(); - create_user_dir("/.config/"); - create_user_dir("/.cache/"); - char* config_file_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen("/.config/") + strlen("monocoque/monocoque.config")); + xdgHandle xdg; + if(!xdgInitHandle(&xdg)) + { + 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); diameters_file_sz += 1; char* diameters_file_str = ( char* ) malloc(diameters_file_sz); 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_get(&slgCfg); slgCfg.eColorFormat = SLOG_COLORING_TAG; slgCfg.eDateControl = SLOG_TIME_ONLY; - strcpy(slgCfg.sFileName, "monocoque.log"); - strcpy(slgCfg.sFilePath, cache_dir_str); + strcpy(slgCfg.sFileName, ms->log_filename_str); + strcpy(slgCfg.sFilePath, ms->log_dirname_str); slgCfg.nTraceTid = 0; slgCfg.nToScreen = 1; slgCfg.nUseHeap = 0; @@ -105,24 +147,22 @@ int main(int argc, char** argv) ms->configcheck = 0; 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); config_t cfg; config_init(&cfg); 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)); + goto cleanup_final; } else { 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; SimDevice* tachdev = malloc(sizeof(SimDevice)); @@ -169,70 +209,25 @@ int main(int argc, char** argv) { 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; - while (iprogram_action == A_PLAY) + if (ms->program_action == A_PLAY) { 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.."); - //error = strtogame(p->sim_string, ms); - //if (error != MONOCOQUE_ERROR_NONE) - //{ - // goto cleanup_final; - //} #ifdef USE_PULSEAUDIO pa_threaded_mainloop_unlock(mainloop); pulseaudio = true; #endif - error = looper(devices, numdevices, p); + //error = looper(devices, numdevices, p); + error = monocoque_mainloop(ms); if (error == MONOCOQUE_ERROR_NONE) { slogi("Game loop exited succesfully with error code: %i", error); @@ -252,7 +247,23 @@ int main(int argc, char** argv) #endif 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) { 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); } - } - - - for (int x = 0; x < numdevices; x++) - { - if (devices[x].initialized == true) + for (int x = 0; x < numdevices; x++) { - devices[x].free(&devices[x]); + if (simdevices[x].initialized == true) + { + simdevices[x].free(&simdevices[x]); + } } } if(pulseaudio == true) { 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: if(ms->tyre_diameter_config != NULL) @@ -297,7 +295,6 @@ cleanup_final: free(ms->tyre_diameter_config); } free(ms); - free(p); exit(0); }