diff --git a/CMakeLists.txt b/CMakeLists.txt index 9eeee4c..7bc33f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,8 @@ add_subdirectory(src/gilles/helper) add_subdirectory(src/gilles/slog) add_executable(gilles src/gilles/gilles.c) -target_link_libraries(gilles m ncursesw argtable2 config gameloop helper slog simulatorapi eclipse-paho-mqtt-c::paho-mqtt3c pthread json-c) +target_link_libraries(gilles xdg-basedir m ncursesw argtable2 config gameloop helper slog simulatorapi eclipse-paho-mqtt-c::paho-mqtt3c pthread hoel jansson) +add_compile_definitions(gilles SIMMAP_ALL) # used for enabling additional compiler options if supported include(CheckCXXCompilerFlag) diff --git a/src/gilles/gameloop/CMakeLists.txt b/src/gilles/gameloop/CMakeLists.txt index d645471..aeb7bd9 100644 --- a/src/gilles/gameloop/CMakeLists.txt +++ b/src/gilles/gameloop/CMakeLists.txt @@ -3,9 +3,6 @@ set(gameloop_source_files gameloop.h ) -set(LIBXML_INCLUDE_DIR /usr/include/libxml2) -include_directories("." ${LIBXML_INCLUDE_DIR}) - add_library(gameloop STATIC ${gameloop_source_files}) diff --git a/src/gilles/gameloop/gameloop.c b/src/gilles/gameloop/gameloop.c index aabd8de..78350d6 100644 --- a/src/gilles/gameloop/gameloop.c +++ b/src/gilles/gameloop/gameloop.c @@ -1,21 +1,26 @@ +#include #include #include #include +#include #include #include #include #include #include +#include +#include +#include +#include #include "gameloop.h" #include "../helper/parameters.h" #include "../helper/confighelper.h" +#include "../helper/dirhelper.h" #include "../simulatorapi/simapi/simapi/simdata.h" #include "../simulatorapi/simapi/simapi/simmapper.h" #include "../slog/slog.h" -#include - #define DEFAULT_UPDATE_RATE 100 #define ADDRESS "tcp://localhost:1883" @@ -125,19 +130,184 @@ void update_date() sprintf(datestring, "%.24s", asctime (timeinfo)); } -void* looper(void* thargs) + +int mainloop(Parameters* p) { - Parameters* p = (Parameters*) thargs; + pthread_t ui_thread; + pthread_t mqtt_thread; + pthread_t mysql_thread; + SimData* simdata = malloc(sizeof(SimData)); SimMap* simmap = malloc(sizeof(SimMap)); - int error = siminit(simdata, simmap, 1); - if (error != GILLES_ERROR_NONE) + 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 }; + + p->simdata = simdata; + p->simmap = simmap; + fprintf(stdout, "Searching for sim data... Press q to quit...\n"); + + double update_rate = 1; + int go = true; + char lastsimstatus = false; + while (go == true) { - slogf("Fatal error getting simulator data"); - //return error; + + + + + + // check for running sims + if (file_exists("/dev/shm/acpmf_physics")) + { + if (file_exists("/dev/shm/acpmf_static")) + { + p->sim = SIMULATOR_ASSETTO_CORSA; + int error = siminit(simdata, simmap, 1); + if (error == 0) + { + slogi("found Assetto Corsa, starting application..."); + p->simon = true; + } + } + } + + if (p->simon == true) + { + if (p->cli == true) + { + if (pthread_create(&ui_thread, NULL, &clilooper, p) != 0) + { + printf("Uh-oh!\n"); + return -1; + } + } + else + { + if (pthread_create(&ui_thread, NULL, &looper, p) != 0) + { + printf("Uh-oh!\n"); + return -1; + } + } + //if (p->mqtt == true) + //{ + // if (pthread_create(&mqtt_thread, NULL, &b4madmqtt, p) != 0) + // { + // printf("Uh-oh!\n"); + // return -1; + // } + //} + if (p->mysql == true) + { + if (pthread_create(&mysql_thread, NULL, &simviewmysql, p) != 0) + { + printf("Uh-oh!\n"); + return -1; + } + } + + pthread_join(ui_thread, NULL); + p->program_state = -1; + //if (p->mqtt == true) + //{ + // pthread_join(mqtt_thread, NULL); + //} + if (p->mysql == true) + { + pthread_join(mysql_thread, NULL); + } + } + + 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) ) + { + scanf("%c", &ch); + if(ch == 'q') + { + go = false; + } + } } - + + fprintf(stdout, "\n"); + fflush(stdout); + tcsetattr(0, TCSANOW, &canonicalmode); + + free(simdata); + free(simmap); + + return 0; +} + +void* clilooper(void* thargs) +{ + Parameters* p = (Parameters*) thargs; + SimData* simdata = p->simdata; + SimMap* simmap = p->simmap; + + 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, "Press q to quit...\n"); + fprintf(stdout, "Press c for a useful readout of car telemetry...\n"); + fprintf(stdout, "Press s for basic sesion information...\n"); + fprintf(stdout, "Press l for basic lap / stint information...\n"); + + double update_rate = DEFAULT_UPDATE_RATE; + int go = true; + char lastsimstatus = false; + while (go == true) + { + simdatamap(simdata, simmap, p->sim); + + if( poll(&mypoll, 1, 1000.0/update_rate) ) + { + scanf("%c", &ch); + if(ch == 'q') + { + go = false; + } + if(ch == 'c') + { + slogi("speed: %i gear: %i", simdata->velocity, simdata->gear); + } + } + } + + fprintf(stdout, "\n"); + fflush(stdout); + tcsetattr(0, TCSANOW, &canonicalmode); + + return 0; +} + +void* looper(void* thargs) +{ + Parameters* p = (Parameters*) thargs; + SimData* simdata = p->simdata; + SimMap* simmap = p->simmap; + curses_init(); timeout(DEFAULT_UPDATE_RATE); @@ -146,7 +316,7 @@ void* looper(void* thargs) char lastsimstatus = false; while (go == true) { - simdatamap(simdata, simmap, 1); + simdatamap(simdata, simmap, p->sim); wclear(win1); wclear(win2); @@ -553,159 +723,273 @@ void* looper(void* thargs) delwin(win1); endwin(); - free(simdata); - free(simmap); //return 0; } -void* b4madmqtt(void* thargs) +int getLastInsertID(struct _h_connection* conn) +{ + json_t* last_id = (h_last_insert_id(conn)); + int id = json_integer_value(last_id); + json_decref(last_id); + return id; +} + +int adddriver(struct _h_connection* conn, int driverid, const char* drivername) +{ + if (driverid > 0) + { + return driverid; + } + json_t *root = json_object(); + json_t *json_arr = json_array(); + + json_object_set_new( root, "table", json_string("drivers") ); + json_object_set_new( root, "values", json_arr ); + + json_t* values = json_object(); + json_object_set_new(values, "driver_name", json_string(drivername)); + json_object_set_new(values, "prev_name", json_string(drivername)); + json_object_set_new(values, "steam64_id", json_integer(17)); + json_object_set_new(values, "country", json_string("USA")); + json_array_append(json_arr, values); + int res = h_insert(conn, root, NULL); + json_decref(root); + json_decref(values); + + driverid = getLastInsertID(conn); + return driverid; +} + +int addtrackconfig(struct _h_connection* conn, int trackconfigid, const char* track, int length) +{ + //track_config_id | track_name | config_name | display_name | country | city | length + if (trackconfigid > 0) + { + return trackconfigid; + } + json_t *root = json_object(); + json_t *json_arr = json_array(); + + json_object_set_new( root, "table", json_string(track) ); + json_object_set_new( root, "values", json_arr ); + + json_t* values = json_object(); + json_object_set_new(values, "track_name", json_string(track)); + json_object_set_new(values, "config_name", json_string("default")); + json_object_set_new(values, "display_name", json_string(track)); + json_object_set_new(values, "country", json_string("USA")); + json_object_set_new(values, "city", json_string("USA")); + json_object_set_new(values, "length", json_integer(length)); + + json_array_append(json_arr, values); + int res = h_insert(conn, root, NULL); + trackconfigid = getLastInsertID(conn); + json_decref(root); + json_decref(values); + + return trackconfigid; +} + +int addevent(struct _h_connection* conn, int track_config) +{ + + json_t *root = json_object(); + json_t *json_arr = json_array(); + + json_object_set_new( root, "table", json_string("events") ); + json_object_set_new( root, "values", json_arr ); + + json_t* values = json_object(); + json_object_set_new(values, "track_config_id", json_integer(track_config)); + json_object_set_new(values, "event_name", json_string("default")); + //event_id | server_name | track_config_id | event_name | team_event | active | livery_preview | use_number | practice_duration | quali_duration | race_duration | race_duration_type | race_wait_time | race_extra_laps | reverse_grid_positions + json_array_append(json_arr, values); + int res = h_insert(conn, root, NULL); + json_decref(root); + json_decref(values); + return getLastInsertID(conn); +} + +int addcar(struct _h_connection* conn, int carid, const char* carname) +{ + + // car_id | display_name | car_name | manufacturer | car_class + + if (carid > 0) + { + return carid; + } + json_t *root = json_object(); + json_t *json_arr = json_array(); + + json_object_set_new( root, "table", json_string("cars") ); + json_object_set_new( root, "values", json_arr ); + + json_t* values = json_object(); + json_object_set_new(values, "display_name", json_string(carname)); + json_object_set_new(values, "car_name", json_string(carname)); + json_object_set_new(values, "manufacturer", json_string("Unknown")); + json_object_set_new(values, "car_class", json_string("Unknown")); + json_array_append(json_arr, values); + int res = h_insert(conn, root, NULL); + json_decref(root); + json_decref(values); + + carid = getLastInsertID(conn); + return carid; + +} + +int gettrack(struct _h_connection* conn, const char* trackname) +{ + + json_t *j_result; + char* where_clause = h_build_where_clause(conn, "config_name=%s AND track_name=%s", "default", trackname); + json_t* j_query = json_pack("{sss[s]s{s{ssss}}}", "table", "track_config", "columns", "track_config_id", "where", " ", "operator", "raw", + "value", where_clause); + + //char* qq; + int res = h_select(conn, j_query, &j_result, NULL); + //slogi("here your query: %s", qq); + // Deallocate j_query since it won't be needed anymore + json_decref(j_query); + h_free(where_clause); + int track_config = -1; + // Test query execution result + if (res == H_OK) { + // Print result + char* dump = json_dumps(j_result, JSON_INDENT(2)); + slogi("json select result is\n%s", dump); + int index1 = json_array_size(j_result); + if (index1 == 0) + { + slogw("no config for this track"); + } + else { + json_t* jj = json_array_get(j_result, index1-1); + track_config = json_integer_value(json_object_get(jj, "track_config_id")); + } + // Deallocate data result + json_decref(j_result); + free(dump); + } else { + sloge("Error executing select query: %d", res); + } + return track_config; +} + +int getdriver(struct _h_connection* conn, const char* driver_name) +{ + json_t *j_result; + char* where_clause = h_build_where_clause(conn, "driver_name=%s", driver_name); + json_t* j_query = json_pack("{sss[s]s{s{ssss}}}","table", "drivers", "columns", "driver_id", "where", " ", "operator", "raw", + "value", where_clause); + + slogi("Looking for driver named %s", driver_name); + //char* qq; + int res = h_select(conn, j_query, &j_result, NULL); + //slogi("here your query: %s", qq); + // Deallocate j_query since it won't be needed anymore + json_decref(j_query); + h_free(where_clause); + int driver_id = -1; + // Test query execution result + if (res == H_OK) { + // Print result + char* dump = json_dumps(j_result, JSON_INDENT(2)); + slogi("json select result is\n%s", dump); + int index1 = json_array_size(j_result); + if (index1 == 0) + { + slogw("no driver by this name"); + } + else { + json_t* jj = json_array_get(j_result, index1-1); + driver_id = json_integer_value(json_object_get(jj, "driver_id")); + } + // Deallocate data result + json_decref(j_result); + free(dump); + } else { + sloge("Error executing select query: %d", res); + } + return driver_id; +} + +int getcar(struct _h_connection* conn, const char* carname) +{ + json_t *j_result; + char* where_clause = h_build_where_clause(conn, "car_name=%s", carname); + json_t* j_query = json_pack("{sss[s]s{s{ssss}}}","table", "cars", "columns", "car_id", "where", " ", "operator", "raw", + "value", where_clause); + + slogi("Looking for car named %s", carname); + //char* qq; + int res = h_select(conn, j_query, &j_result, NULL); + //slogi("here your query: %s", qq); + // Deallocate j_query since it won't be needed anymore + json_decref(j_query); + h_free(where_clause); + int car_id = -1; + // Test query execution result + if (res == H_OK) { + // Print result + char* dump = json_dumps(j_result, JSON_INDENT(2)); + slogi("json select result is\n%s", dump); + int index1 = json_array_size(j_result); + if (index1 == 0) + { + slogw("no car by this name"); + } + else { + json_t* jj = json_array_get(j_result, index1-1); + car_id = json_integer_value(json_object_get(jj, "car_id")); + } + // Deallocate data result + json_decref(j_result); + free(dump); + } else { + sloge("Error executing select query: %d", res); + } + return car_id; +} + + + +void* simviewmysql(void* thargs) { Parameters* p = (Parameters*) thargs; - SimData* simdata = malloc(sizeof(SimData)); - SimMap* simmap = malloc(sizeof(SimMap)); - long unix_time_start; - char time_buff[11]; + SimData* simdata = p->simdata; + SimMap* simmap = p->simmap; - int error = siminit(simdata, simmap, 1); - if (error != GILLES_ERROR_NONE) - { - slogf("Fatal error getting simulator data"); - //return error; - } + struct _h_result result; + struct _h_connection * conn; + char* connectionstring = "host=zorak.brak dbname=gilles user=test password=thisisatest"; + conn = h_connect_pgsql(connectionstring); - bool mqtt = p->mqtt; - bool mqtt_connected = false; + int trackconfig = gettrack(conn, simdata->track); + trackconfig = addtrackconfig(conn, trackconfig, simdata->track, simdata->trackdistancearound); + int eventid = addevent(conn, trackconfig); + int driverid = getdriver(conn, simdata->driver); + driverid = adddriver(conn, driverid, simdata->driver); + int carid = getcar(conn, simdata->car); + carid = addcar(conn, carid, simdata->car); - MQTTClient client; - MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; - MQTTClient_message pubmsg = MQTTClient_message_initializer; - MQTTClient_deliveryToken token; - int rc; +// sessions +// session_id | event_id | event_type | track_time | session_name | start_time | duration_min | elapsed_ms | laps | weather | air_temp | road_temp | start_grip | current_grip | is_finished | finish_time | last_activity | http_port - // Create a new MQTT client - MQTTClient_create(&client, ADDRESS, CLIENTID, - MQTTCLIENT_PERSISTENCE_NONE, NULL); +// stints +// session_stint_id | driver_id | team_member_id | session_id | car_id | game_car_id | laps | valid_laps | best_lap_id | is_finished | started_at | finished_at - // Connect to the MQTT server - if (mqtt == true) - { - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { - MQTTClient_disconnect(client, 10000); - sloge("Failed to connect, return code %d", rc); - return NULL; - //exit(-1); - } - mqtt_connected = true; - } +// stint laps +// stint_lap_id | stint_id | sector_1 | sector_2 | sector_3 | grip | tyre | time | cuts | crashes | car_crashes | max_speed | avg_speed | finished_at - int go = false; - if (mqtt_connected == true) - { - go = true; - } - char lastsimstatus = false; - while (go == true && p->program_state == 1) - { +// telemetry +// lap_id | telemetry - char simstatus = (simdata->simstatus > 0) ? true : false; - if (simdata->simstatus > 0 && simstatus != lastsimstatus) - { - //update_date(); - unix_time_start = (unsigned long) time(NULL); - sprintf(time_buff, "%lu", unix_time_start); - //sprintf(time_buff, "%lu", (unsigned long)time(NULL)); - //newdatestring = removeSpacesFromStr(datestring); - } - lastsimstatus = simstatus; - simdatamap(simdata, simmap, 1); - if (mqtt_connected == true && simdata->simstatus > 0) - { - json_object *root = json_object_new_object(); - //if (!root) - // return; - - json_object *child = json_object_new_object(); - - struct timeval tv; - gettimeofday(&tv, NULL); - unsigned long long millisecondsSinceEpoch = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000; - - json_object_object_add(root, "time", json_object_new_int64(millisecondsSinceEpoch)); //unix time milliseconds - - const char* topic_root = "racing/gilles/TuxRacerX"; - //const char* game_name = "Assetto Corsa (64 bit)"; - const char* game_name = "assetto_64_bit"; - const char* session_type = "Practice"; - - json_object_object_add(child, "CarModel", json_object_new_string(simdata->car)); - json_object_object_add(child, "GameName", json_object_new_string(game_name)); - json_object_object_add(child, "SessionId", json_object_new_int(unix_time_start)); - json_object_object_add(child, "SessionTypeName", json_object_new_string("Practice")); - json_object_object_add(child, "TrackCode", json_object_new_string(simdata->track)); - - json_object_object_add(child, "Clutch", json_object_new_double(simdata->clutch)); - json_object_object_add(child, "Brake", json_object_new_double(simdata->brake)); - json_object_object_add(child, "Throtte", json_object_new_double(simdata->gas)); - json_object_object_add(child, "HandBrake", json_object_new_double(simdata->handbrake)); - json_object_object_add(child, "SteeringAngle", json_object_new_double(simdata->steer)); - json_object_object_add(child, "Rpms", json_object_new_int(simdata->rpms)); - json_object_object_add(child, "Gear", json_object_new_int(simdata->gear)); - json_object_object_add(child, "SpeedMs", json_object_new_double(simdata->velocity * 0.2777778)); - json_object_object_add(child, "DistanceRoundTrack", json_object_new_double(simdata->trackdistancearound)); - json_object_object_add(child, "WorldPosition_x", json_object_new_double(simdata->worldposx)); - json_object_object_add(child, "WorldPosition_y", json_object_new_double(simdata->worldposy)); - json_object_object_add(child, "WorldPosition_z", json_object_new_double(simdata->worldposz)); - json_object_object_add(child, "CurrentLap", json_object_new_int(simdata->playerlaps)); - json_object_object_add(child, "CurrentLapTime", json_object_new_int(simdata->currentlapinseconds)); - json_object_object_add(child, "LapTimePrevious", json_object_new_int(simdata->lastlapinseconds)); - json_object_object_add(child, "CurrentLapIsValid", json_object_new_int(simdata->lapisvalid)); - json_object_object_add(child, "PreviousLapWasValid", json_object_new_int(1)); - - json_object_object_add(root, "telemetry", child); - - slogi(json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); - - // TODO: generate this topic string only once - char* topic = ( char* ) malloc(1 + strlen(topic_root) + strlen("/") + strlen(game_name) + strlen("/") + strlen(session_type) - + strlen("/") + strlen(simdata->car) + strlen("/") + strlen(simdata->track) + strlen("/") + 11); - strcpy(topic, topic_root); - strcat(topic, "/"); - strcat(topic, time_buff); - strcat(topic, "/"); - strcat(topic, game_name); - strcat(topic, "/"); - strcat(topic, simdata->track); - strcat(topic, "/"); - strcat(topic, simdata->car); - strcat(topic, "/"); - strcat(topic, session_type); - - char* payload1; - sprintf(payload1, json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); - pubmsg.payload = payload1; - //pubmsg.payload = json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY); - //pubmsg.payloadlen = strlen(json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); - pubmsg.payloadlen = strlen(payload1); - pubmsg.qos= QOS; - pubmsg.retained = 0; - - MQTTClient_publishMessage(client, topic, &pubmsg, &token); - } - - } - if (mqtt_connected == true) - { - MQTTClient_disconnect(client, 10000); - } - MQTTClient_destroy(&client); - - free(simdata); - free(simmap); - return NULL; - //return 0; + h_close_db(conn); + h_clean_connection(conn); } diff --git a/src/gilles/gameloop/gameloop.h b/src/gilles/gameloop/gameloop.h index 4910300..6fd1b3f 100644 --- a/src/gilles/gameloop/gameloop.h +++ b/src/gilles/gameloop/gameloop.h @@ -1,5 +1,8 @@ #include "../helper/parameters.h" #include "../helper/confighelper.h" +int mainloop(Parameters* p); +void* clilooper(void* params); void* looper(void* params); void* b4madmqtt(void* params); +void* simviewmysql(void* params); diff --git a/src/gilles/gilles.c b/src/gilles/gilles.c index 9aff526..f784bcd 100644 --- a/src/gilles/gilles.c +++ b/src/gilles/gilles.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,6 +6,7 @@ #include #include #include +#include #include "gameloop/gameloop.h" #include "helper/parameters.h" @@ -12,7 +14,6 @@ #include "helper/confighelper.h" #include "slog/slog.h" - int create_dir(char* dir) { struct stat st = {0}; @@ -22,25 +23,37 @@ int create_dir(char* dir) } } -char* create_user_dir(char* dirtype) +char* create_user_dir(const char* dirtype) { - char* home_dir_str = gethome(); - char* config_dir_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen(dirtype) + strlen("gilles/")); - strcpy(config_dir_str, home_dir_str); - strcat(config_dir_str, dirtype); - strcat(config_dir_str, "gilles/"); + char* config_dir_str = ( char* ) malloc(1 + strlen(dirtype) + strlen("/gilles")); + strcpy(config_dir_str, dirtype); + strcat(config_dir_str, "/gilles"); create_dir(config_dir_str); free(config_dir_str); } +char* get_config_file(const char* confpath, xdgHandle* xdg) +{ + if(strcmp(confpath, "") != 0) + { + fprintf(stderr, "no config path specified"); + return strdup(confpath); + } + + const char* relpath = "gilles/gilles.config"; + const char* confpath1 = xdgConfigFind(relpath, xdg); + slogi("path is %s", confpath1); + return strdup(confpath1); +} + + int main(int argc, char** argv) { Parameters* p = malloc(sizeof(Parameters)); GillesSettings* gs = malloc(sizeof(GillesSettings));; - ConfigError ppe = getParameters(argc, argv, p); if (ppe == E_SUCCESS_AND_EXIT) { @@ -52,13 +65,9 @@ int main(int argc, char** argv) 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("gilles/gilles.config")); char* cache_dir_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen("/.cache/gilles/")); - strcpy(config_file_str, home_dir_str); - strcat(config_file_str, "/.config/"); strcpy(cache_dir_str, home_dir_str); strcat(cache_dir_str, "/.cache/gilles/"); - strcat(config_file_str, "gilles/gilles.config"); slog_config_t slgCfg; slog_config_get(&slgCfg); @@ -82,39 +91,32 @@ int main(int argc, char** argv) slog_disable(SLOG_DEBUG); } - pthread_t ui_thread; - pthread_t mqtt_thread; + xdgHandle xdg; + if(!xdgInitHandle(&xdg)) + { + slogf("Function xdgInitHandle() failed, is $HOME unset?"); + } + char* config_file_str = get_config_file("/home/paul/.config/gilles/gilles.config", &xdg); - if (pthread_create(&ui_thread, NULL, &looper, p) != 0) - { - printf("Uh-oh!\n"); - return -1; - } - if (p->mqtt == true) - { - if (pthread_create(&mqtt_thread, NULL, &b4madmqtt, p) != 0) - { - printf("Uh-oh!\n"); - return -1; - } - } - - pthread_join(ui_thread, NULL); - p->program_state = -1; - if (p->mqtt == true) - { - pthread_join(mqtt_thread, NULL); - } + loadconfig(config_file_str, p); + //slogi("mysql user is %s", p->mysql_user); free(config_file_str); free(cache_dir_str); + xdgWipeHandle(&xdg); + mainloop(p); + //free(config_file_str); + //free(cache_dir_str); + //free(simmap); + //free(simdata); configcleanup: //config_destroy(&cfg); cleanup_final: + freeparams(p); free(gs); free(p); exit(0); diff --git a/src/gilles/helper/confighelper.c b/src/gilles/helper/confighelper.c index 8c63c82..6cab60d 100644 --- a/src/gilles/helper/confighelper.c +++ b/src/gilles/helper/confighelper.c @@ -2,37 +2,70 @@ #include #include #include - +#include #include "confighelper.h" #include "../slog/slog.h" -int strtogame(const char* game, GillesSettings* gs) +//int strtogame(const char* game, GillesSettings* gs) +//{ +// slogd("Checking for %s in list of supported simulators.", game); +// if (strcmp(game, "ac") == 0) +// { +// slogd("Setting simulator to Assetto Corsa"); +// gs->sim_name = SIMULATOR_ASSETTO_CORSA; +// } +// else +// if (strcmp(game, "test") == 0) +// { +// slogd("Setting simulator to Test Data"); +// gs->sim_name = SIMULATOR_GILLES_TEST; +// } +// else +// { +// slogi("%s does not appear to be a supported simulator.", game); +// return GILLES_ERROR_INVALID_SIM; +// } +// return GILLES_ERROR_NONE; +//} + +int loadmysql(config_t* cfg, Parameters* p) { - slogd("Checking for %s in list of supported simulators.", game); - if (strcmp(game, "ac") == 0) - { - slogd("Setting simulator to Assetto Corsa"); - gs->sim_name = SIMULATOR_ASSETTO_CORSA; + config_setting_t* config_mysql_array = NULL; + config_mysql_array = config_lookup(cfg, "mysql"); + + config_setting_t* config_mysql = NULL; + config_mysql = config_setting_get_elem(config_mysql_array, 0); + + if (config_mysql == NULL) { + slogi("found no mysql settings"); } - else - if (strcmp(game, "test") == 0) - { - slogd("Setting simulator to Test Data"); - gs->sim_name = SIMULATOR_GILLES_TEST; - } - else - { - slogi("%s does not appear to be a supported simulator.", game); - return GILLES_ERROR_INVALID_SIM; - } - return GILLES_ERROR_NONE; -} - - -int loadconfig(const char* config_file) -{ + const char* temp; + config_setting_lookup_string(config_mysql, "user", &temp); + p->mysql_user = strdup(temp); + return 0; +} + +int loadconfig(const char* config_file_str, Parameters* p) +{ + 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"); + if (p->mysql == true) + { + loadmysql(&cfg, p); + } + } + + config_destroy(&cfg); + return 0; } diff --git a/src/gilles/helper/confighelper.h b/src/gilles/helper/confighelper.h index f3cc24b..a76ff7c 100644 --- a/src/gilles/helper/confighelper.h +++ b/src/gilles/helper/confighelper.h @@ -8,13 +8,6 @@ #include "parameters.h" -typedef enum -{ - SIMULATOR_GILLES_TEST = 0, - SIMULATOR_ASSETTO_CORSA = 1 -} -Simulator; - typedef enum { SIMULATOR_UPDATE_DEFAULT = 0, @@ -41,6 +34,8 @@ typedef struct } GillesSettings; +int loadconfig(const char* config_file_str, Parameters* p); + int strtogame(const char* game, GillesSettings* gs); #endif diff --git a/src/gilles/helper/dirhelper.c b/src/gilles/helper/dirhelper.c index 49b9ade..93faec1 100644 --- a/src/gilles/helper/dirhelper.c +++ b/src/gilles/helper/dirhelper.c @@ -3,16 +3,23 @@ #include #include #include -#include - #include -#include -#include -#include #include #include + +#include +#include +#if defined(OS_WIN) + #include +#else + #include // for *Nix directory access + #include +#endif + + + char* gethome() { char* homedir = getenv("HOME"); @@ -200,3 +207,47 @@ bool does_directory_exist(char* path, char* dirname) return answer; } + + +bool file_exists(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/gilles/helper/dirhelper.h b/src/gilles/helper/dirhelper.h index a95ea4e..40de8d2 100644 --- a/src/gilles/helper/dirhelper.h +++ b/src/gilles/helper/dirhelper.h @@ -8,5 +8,6 @@ char* str2md5(const char* str, int length); bool does_directory_exist(char* path, char* dirname); void restrict_folders_to_cache(char* path, int cachesize); void delete_dir(char* path); +bool file_exists(const char* file); #endif diff --git a/src/gilles/helper/parameters.c b/src/gilles/helper/parameters.c index 2a5aff3..77ed66d 100644 --- a/src/gilles/helper/parameters.c +++ b/src/gilles/helper/parameters.c @@ -8,6 +8,22 @@ #include #include +int freeparams(Parameters* p) +{ + if(p->sim_string != NULL) + { + free(p->sim_string); + } + if (p->mysql == true) + { + if(p->mysql_user != NULL) + { + free(p->mysql_user); + } + } + return 0; +} + ConfigError getParameters(int argc, char** argv, Parameters* p) { @@ -15,21 +31,26 @@ ConfigError getParameters(int argc, char** argv, Parameters* p) // set return structure defaults p->program_action = 0; + p->cli = false; p->mqtt = false; + p->mysql = false; + p->simon = false; p->verbosity_count = 0; // setup argument handling structures - const char* progname = "gilles"; + const char* progname = "Gilles"; struct arg_lit* arg_verbosity = 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_lit* arg_mqtt = arg_lit0("S", NULL, "send data to local mqtt server"); + struct arg_lit* arg_cli = arg_lit0("c", "textui", "text only ui"); + struct arg_lit* arg_mqtt = arg_lit0("Q", "mqtt", "send data to local mqtt server with connection settings speciifed in config"); + struct arg_lit* arg_mysql = arg_lit0("M", "mysql", "send data to local mysql server with connection settings specified in config"); 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* end = arg_end(20); - void* argtable[] = {cmd1,arg_sim,arg_verbosity,arg_mqtt,help,vers,end}; + void* argtable[] = {cmd1,arg_sim,arg_verbosity,arg_cli,arg_mqtt,arg_mysql,help,vers,end}; int nerrors; @@ -45,12 +66,20 @@ ConfigError getParameters(int argc, char** argv, Parameters* p) if (nerrors==0) { p->program_action = A_PLAY; - p->sim_string = arg_sim->sval[0]; + p->sim_string = strdup(arg_sim->sval[0]); p->verbosity_count = arg_verbosity->count; + if (arg_cli->count > 0) + { + p->cli = true; + } if (arg_mqtt->count > 0) { p->mqtt = true; } + if (arg_mysql->count > 0) + { + p->mysql = true; + } exitcode = E_SUCCESS_AND_DO; } @@ -58,14 +87,15 @@ ConfigError getParameters(int argc, char** argv, Parameters* p) if (help->count > 0) { printf("Usage: %s\n", progname); - printf("\nReport bugs on the github github.com/spacefreak18/csimtelem.\n"); + arg_print_syntax(stdout,argtable,"\n"); + printf("\nReport bugs on the github github.com/spacefreak18/gilles.\n"); exitcode = E_SUCCESS_AND_EXIT; goto cleanup; } if (vers->count > 0) { - printf("%s Simulator Hardware Manager\n",progname); + printf("%s Simulator Monitor\n",progname); printf("October 2022, Paul Dino Jones\n"); exitcode = E_SUCCESS_AND_EXIT; goto cleanup; diff --git a/src/gilles/helper/parameters.h b/src/gilles/helper/parameters.h index 3cf9304..9543e00 100644 --- a/src/gilles/helper/parameters.h +++ b/src/gilles/helper/parameters.h @@ -3,13 +3,30 @@ #include +#include "../simulatorapi/simapi/simapi/simapi.h" +#include "../simulatorapi/simapi/simapi/simdata.h" +#include "../simulatorapi/simapi/simapi/simmapper.h" + typedef struct { + char* sim_string; int program_action; int program_state; - const char* sim_string; - bool mqtt; - int verbosity_count; + + bool cli; + bool mqtt; + bool mysql; + bool simon; + int verbosity_count; + + char* mysql_user; + char* mysql_serv; + char* mysql_dbnm; + char* mysql_pass; + + Simulator sim; + SimData* simdata; + SimMap* simmap; } Parameters; @@ -28,6 +45,7 @@ typedef enum ConfigError; ConfigError getParameters(int argc, char** argv, Parameters* p); +int freeparams(Parameters* p); struct _errordesc {