Files
monocoque/src/monocoque/helper/confighelper.c
T
2026-08-18 16:39:24 -04:00

1545 lines
44 KiB
C

#include <dirent.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <libxml/parser.h>
#include <libxml/xmlreader.h>
#include <libxml/tree.h>
#include "confighelper.h"
#include "dirhelper.h"
#include "../slog/slog.h"
#include "parameters.h"
#include "../simulatorapi/simapi/simapi/simmapper.h"
#include <pulse/pulseaudio.h>
int strcicmp(char const *a, char const *b)
{
for (;; a++, b++) {
int d = tolower((unsigned char)*a) - tolower((unsigned char)*b);
if (d != 0 || !*a)
return d;
}
}
int strtoeffecttype(const char* effect, DeviceSettings* ds)
{
ds->is_valid = false;
if (strcicmp(effect, "Engine") == 0)
{
ds->is_valid = true;
ds->hapticsettings.effect_type = EFFECT_ENGINERPM;
}
if (strcicmp(effect, "Gear") == 0)
{
ds->is_valid = true;
ds->hapticsettings.effect_type = EFFECT_GEARSHIFT;
}
if (strcicmp(effect, "Suspension") == 0)
{
ds->is_valid = true;
ds->hapticsettings.effect_type = EFFECT_SUSPENSION;
}
if (strcicmp(effect, "ABS") == 0)
{
ds->is_valid = true;
slogt("found abas effect set");
ds->hapticsettings.effect_type = EFFECT_ABSBRAKES;
}
if ((strcicmp(effect, "SLIP") == 0) || (strcicmp(effect, "TYRESLIP") == 0) || (strcicmp(effect, "TIRESLIP") == 0))
{
ds->is_valid = true;
slogt("found tyreslip effect set");
ds->hapticsettings.effect_type = EFFECT_TYRESLIP;
}
if ((strcicmp(effect, "LOCK") == 0) || (strcicmp(effect, "TYRELOCK") == 0) || (strcicmp(effect, "TIRELOCK") == 0))
{
ds->is_valid = true;
slogt("found tyreslock effect set");
ds->hapticsettings.effect_type = EFFECT_TYRELOCK;
}
if (ds->is_valid == false)
{
slogw("effect %s is not a valid effect", effect);
}
ds->is_valid = true;
return MONOCOQUE_ERROR_NONE;
}
int strtodevsubsubtype(const char* device_subsubtype, DeviceSettings* ds)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_UNKNOWN;
bool devfound = false;
if (strcicmp(device_subsubtype, "CammusC5") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_CAMMUSC5;
devfound = true;
}
if (strcicmp(device_subsubtype, "CammusC12") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_CAMMUSC12;
devfound = true;
}
if (strcicmp(device_subsubtype, "MozaNew") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_MOZA_NEW;
devfound = true;
}
if (strcicmp(device_subsubtype, "MozaR5") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_MOZAR5;
devfound = true;
}
if (strcicmp(device_subsubtype, "LogitechG29") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_LOGITECH_G29;
devfound = true;
}
if (strcicmp(device_subsubtype, "MozaR8") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_MOZAR5;
devfound = true;
}
if (strcicmp(device_subsubtype, "MozaR3") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_MOZAR5;
devfound = true;
}
if (strcicmp(device_subsubtype, "MozaKSProWheel") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_MOZA_KS_PRO_WHEEL;
devfound = true;
}
if (strcicmp(device_subsubtype, "CSLELITEV3PEDALS") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_CSLELITEV3PEDALS;
devfound = true;
}
if (strcicmp(device_subsubtype, "SIMNETPEDALS") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_SIMNETPEDALS;
devfound = true;
}
if (strcicmp(device_subsubtype, "SIMAGICP1000PEDALS") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_SIMAGICP1000PEDALS;
devfound = true;
}
if (strcicmp(device_subsubtype, "SIMAGICGTNEO") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_SIMAGICGTNEO;
devfound = true;
}
if (strcicmp(device_subsubtype, "REVBURNER") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_REVBURNERTACHOMETER;
devfound = true;
}
if(devfound == false)
{
slogw("%s does not appear to be a valid device sub sub type, but attempting to continue with other devices", device_subsubtype);
return MONOCOQUE_ERROR_INVALID_DEV;
}
return MONOCOQUE_ERROR_NONE;
}
int strtodevsubtype(const char* device_subtype, DeviceSettings* ds, int simdev)
{
ds->is_valid = false;
ds->dev_subtype = SIMDEVTYPE_UNKNOWN;
switch (simdev) {
case SIMDEV_USB:
if (strcicmp(device_subtype, "Tachometer") == 0)
{
ds->dev_subtype = SIMDEVTYPE_TACHOMETER;
break;
}
if (strcicmp(device_subtype, "Wheel") == 0 || strcicmp(device_subtype, "UsbWheel") == 0)
{
ds->dev_subtype = SIMDEVTYPE_USBWHEEL;
break;
}
if (strcicmp(device_subtype, "UsbHaptic") == 0 || strcicmp(device_subtype, "Haptic") == 0)
{
ds->dev_subtype = SIMDEVTYPE_USBHAPTIC;
break;
}
case SIMDEV_SERIAL:
if (strcicmp(device_subtype, "ShiftLights") == 0)
{
ds->dev_subtype = SIMDEVTYPE_SHIFTLIGHTS;
break;
}
if (strcicmp(device_subtype, "Simleds") == 0)
{
ds->dev_subtype = SIMDEVTYPE_SIMLED;
break;
}
if (strcicmp(device_subtype, "ArduinoCustom") == 0 || strcicmp(device_subtype, "Custom") == 0)
{
ds->dev_subtype = SIMDEVTYPE_ARDUINOCUSTOM;
break;
}
if (strcicmp(device_subtype, "SimWind") == 0)
{
ds->dev_subtype = SIMDEVTYPE_SIMWIND;
break;
}
if (strcicmp(device_subtype, "SerialHaptic") == 0 || strcicmp(device_subtype, "Haptic") == 0)
{
slogt("found serial haptic device settings");
ds->dev_subtype = SIMDEVTYPE_SERIALHAPTIC;
break;
}
if (strcicmp(device_subtype, "Wheel") == 0)
{
ds->dev_subtype = SIMDEVTYPE_SERIALWHEEL;
break;
}
case SIMDEV_SOUND:
ds->is_valid = true;
break;
default:
ds->is_valid = false;
slogw("%s does not appear to be a valid device sub type, but attempting to continue with other devices", device_subtype);
return MONOCOQUE_ERROR_INVALID_DEV;
}
ds->is_valid = true;
return MONOCOQUE_ERROR_NONE;
}
int strtodev(const char* device_type, const char* device_subtype, DeviceSettings* ds)
{
ds->is_valid = false;
if (strcicmp(device_type, "USB") == 0)
{
ds->dev_type = SIMDEV_USB;
strtodevsubtype(device_subtype, ds, SIMDEV_USB);
}
else
if (strcicmp(device_type, "Sound") == 0)
{
ds->dev_type = SIMDEV_SOUND;
strtodevsubtype(device_subtype, ds, SIMDEV_SOUND);
}
else
if (strcicmp(device_type, "Serial") == 0)
{
ds->dev_type = SIMDEV_SERIAL;
strtodevsubtype(device_subtype, ds, SIMDEV_SERIAL);
}
else
{
ds->is_valid = false;
slogi("%s does not appear to be a valid device type, but attempting to continue with other devices", device_type);
return MONOCOQUE_ERROR_INVALID_DEV;
}
ds->is_valid = true;
return MONOCOQUE_ERROR_NONE;
}
int getsimfromconfig(config_setting_t* c)
{
int sim = 0;
const char* simstr = NULL;
int found = config_setting_lookup_string(c, "sim", &simstr);
if(found == 0)
{
int found = config_setting_lookup_int(c, "sim", &sim);
}
else
{
sim = simapi_strtogame(simstr);
}
return sim;
}
int getNumberOfConfigs(const char* config_file_str)
{
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);
config_destroy(&cfg);
return configs;
}
int getconfigtouse2(const char* config_file_str, char* car, int sim)
{
slogt("inside first pass");
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
sloge("config read error on pass 1");
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
config_destroy(&cfg);
return -1;
}
slogt("config validates");
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 )
{
config_destroy(&cfg);
return -1;
}
int confignum = -1;
slogt("Multiple configs found");
for (j = 0; j < configs; j++)
{
config_config = config_setting_get_elem(config, j);
int found = 0;
int csim = 0;
slogt("sim is %i", sim);
csim = getsimfromconfig(config_config);
if (csim != sim)
{
slogt("rejected config %i", j);
continue;
}
slogt("checking if car is matched %i", j);
temp = NULL;
found = config_setting_lookup_string(config_config, "car", &temp);
slogt("config car is %s found is %i", temp, found);
if(temp != NULL && found > 0 && car > 0 && car != NULL)
{
slogt("checking against sim car of %s", car);
if(strcicmp(temp, car) == 0)
{
confignum = j;
}
}
if(confignum>=0)
{
break;
}
}
config_destroy(&cfg);
return confignum;
}
int getconfigtouse1(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));
config_destroy(&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 )
{
config_destroy(&cfg);
return -1;
}
int confignum = -1;
slogt("Multiple configs found");
for (j = 0; j < configs; j++)
{
config_config = config_setting_get_elem(config, j);
int found = 0;
int csim = 0;
slogt("sim is %i", sim);
csim = getsimfromconfig(config_config);
if (csim != sim)
{
slogt("rejected config %i", j);
continue;
}
slogt("checking if car is matched %i", j);
temp = NULL;
found = config_setting_lookup_string(config_config, "car", &temp);
slogt("config car is %s found is %i", temp, found);
if(temp != NULL && found > 0 && car > 0 && car != NULL)
{
slogt("checking against sim car of %s", car);
if(strcicmp(temp, car) == 0)
{
confignum = j;
}
if(strcicmp("default", temp) == 0)
{
slogt("matched default car");
confignum = j;
}
}
else
{
slogt("assuming default car");
confignum = j;
}
slogt("bomb");
if(confignum>=0)
{
break;
}
}
config_destroy(&cfg);
return confignum;
}
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));
config_destroy(&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 )
{
config_destroy(&cfg);
return 0;
}
int confignum = 0;
slogt("Multiple configs found");
for (j = 0; j < configs; j++)
{
config_config = config_setting_get_elem(config, j);
int found = 0;
int csim = 0;
slogt("sim is %i", sim);
csim = getsimfromconfig(config_config);
if (csim != sim && csim != 0)
{
slogt("rejected config %i", j);
continue;
}
slogt("checking if car is matched %i", j);
temp = NULL;
found = config_setting_lookup_string(config_config, "car", &temp);
slogt("config car is %s found is %i", temp, found);
if(temp != NULL && found > 0 && car > 0 && car != NULL)
{
slogt("checking against sim car of %s", car);
if(strcicmp(temp, car) == 0)
{
confignum = j;
}
if(strcicmp("default", temp) == 0)
{
slogt("matched default car");
confignum = j;
}
}
else
{
slogt("assuming default car");
confignum = j;
}
slogt("bomb");
if(confignum<configs-1)
{
break;
}
}
config_destroy(&cfg);
return confignum;
}
int loadtachconfig(char* config_file, DeviceSettings* ds)
{
xmlNode* rootnode = NULL;
xmlNode* curnode = NULL;
xmlNode* cursubnode = NULL;
xmlNode* cursubsubnode = NULL;
xmlNode* cursubsubsubnode = NULL;
xmlDoc* doc = NULL;
char* buf;
doc = xmlParseFile(config_file);
if (doc == NULL)
{
sloge("Could not read revburner xml config file %s", config_file);
return 1;
}
rootnode = xmlDocGetRootElement(doc);
if (rootnode == NULL)
{
xmlFreeDoc(doc);
xmlCleanupParser();
sloge("Invalid rev burner xml");
return 1;
}
int arraysize = 0;
for (curnode = rootnode; curnode; curnode = curnode->next)
{
for (cursubnode = curnode->children; cursubnode; cursubnode = cursubnode->next)
{
for (cursubsubnode = cursubnode->children; cursubsubnode; cursubsubnode = cursubsubnode->next)
{
if (cursubsubnode->type == XML_ELEMENT_NODE)
{
slogt("Xml Element name %s", cursubsubnode->name);
}
if (strcicmp(cursubsubnode->name, "SettingsItem") == 0)
{
arraysize++;
}
}
}
}
uint32_t pulses_array[arraysize];
uint32_t rpms_array[arraysize];
slogt("rev burner settings array size %i", arraysize);
int i = 0;
for (curnode = rootnode; curnode; curnode = curnode->next)
{
if (curnode->type == XML_ELEMENT_NODE)
for (cursubnode = curnode->children; cursubnode; cursubnode = cursubnode->next)
{
for (cursubsubnode = cursubnode->children; cursubsubnode; cursubsubnode = cursubsubnode->next)
{
for (cursubsubsubnode = cursubsubnode->children; cursubsubsubnode; cursubsubsubnode = cursubsubsubnode->next)
{
if (strcicmp(cursubsubsubnode->name, "Value") == 0)
{
xmlChar* a = xmlNodeGetContent(cursubsubsubnode);
rpms_array[i] = strtol((char*) a, &buf, 10);
xmlFree(a);
}
if (strcicmp(cursubsubsubnode->name, "TimeValue") == 0)
{
xmlChar* a = xmlNodeGetContent(cursubsubsubnode);
pulses_array[i] = strtol((char*) a, &buf, 10);
xmlFree(a);
i++;
}
}
}
}
}
ds->tachsettings.pulses_array = malloc(sizeof(pulses_array));
ds->tachsettings.rpms_array = malloc(sizeof(rpms_array));
ds->tachsettings.size = arraysize;
memcpy(ds->tachsettings.pulses_array, pulses_array, sizeof(pulses_array));
memcpy(ds->tachsettings.rpms_array, rpms_array, sizeof(rpms_array));
xmlFreeDoc(doc);
xmlCleanupParser();
return 0;
}
int gettyre(config_setting_t* device_settings, DeviceSettings* ds) {
const char* temp;
int found = config_setting_lookup_string(device_settings, "tyre", &temp);
ds->hapticsettings.tyre = ALLFOUR;
if (strcicmp(temp, "FRONTS") == 0)
{
ds->hapticsettings.tyre = FRONTS;
}
if (strcicmp(temp, "REARS") == 0)
{
ds->hapticsettings.tyre = REARS;
}
if (strcicmp(temp, "FRONTLEFT") == 0)
{
ds->hapticsettings.tyre = FRONTLEFT;
}
if (strcicmp(temp, "FRONTRIGHT") == 0)
{
ds->hapticsettings.tyre = FRONTRIGHT;
}
if (strcicmp(temp, "REARLEFT") == 0)
{
ds->hapticsettings.tyre = REARLEFT;
}
if (strcicmp(temp, "REARRIGHT") == 0)
{
ds->hapticsettings.tyre = REARRIGHT;
}
}
static int load_device_specific_config(const char* config_file, DeviceSettings* ds)
{
ds->has_config = false;
if(config_file == NULL)
{
slogt("config set to none");
}
else
{
ds->has_config = true;
if(strcicmp(config_file, "none") == 0)
{
ds->has_config = false;
ds->specific_config_file = NULL;
}
else
{
ds->specific_config_file = strdup(config_file);
ds->specific_config_file = expand_tilde(ds->specific_config_file);
slogt("will try to load config file at %s", ds->specific_config_file);
}
}
// in the case of the revburner tachometer, we can parse once and store
if (ds->dev_subtype == SIMDEVTYPE_TACHOMETER)
{
if(ds->has_config == false)
{
slogw("Tachometer must have a device specific config file!");
return 1;
}
loadtachconfig(ds->specific_config_file, 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;
}
static int config_get_device(const config_setting_t *entry, DeviceSettings *ds)
{
const char *value = NULL;
if (config_setting_lookup_string(entry, "devid", &value))
{
ds->dev = strdup(value);
return ds->dev != NULL;
}
if (config_setting_lookup_string(entry, "devpath", &value))
{
ds->dev = strdup(value);
return ds->dev != NULL;
}
ds->dev = NULL;
return 0;
}
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;
//slogt("Called device setup with %s %s %s", device_type, device_subtype, config_file);
ds->dev_type = SIMDEV_UNKNOWN;
error = strtodev(device_type, device_subtype, ds);
if (error != MONOCOQUE_ERROR_NONE)
{
return error;
}
if (ms->program_action == A_PLAY || ms->program_action == A_TEST)
{
error = load_device_specific_config(config_file, ds);
}
if (error != MONOCOQUE_ERROR_NONE)
{
return error;
}
ds->fps = 60;
config_setting_lookup_int(device_settings, "fps", &ds->fps);
config_get_device(device_settings, ds);
if (ds->dev_subtype == SIMDEVTYPE_TACHOMETER)
{
if (device_settings != NULL)
{
config_setting_lookup_int(device_settings, "granularity", &ds->tachsettings.granularity);
if (ds->tachsettings.granularity < 0 || ds->tachsettings.granularity > 4 || ds->tachsettings.granularity == 3)
{
slogd("No or invalid valid set for tachometer granularity, setting to 1");
ds->tachsettings.granularity = 1;
}
slogi("Tachometer granularity set to %i", ds->tachsettings.granularity);
}
ds->tachsettings.use_pulses = true;
if (ms->program_action == A_PLAY || ms->program_action == A_TEST)
{
ds->tachsettings.use_pulses = false;
}
}
if (ds->dev_type == SIMDEV_USB)
{
if (device_settings != NULL)
{
const char* temp;
int found = config_setting_lookup_string(device_settings, "subtype", &temp);
if(temp != NULL && found > 0)
{
strtodevsubsubtype(temp, ds);
}
}
}
if (ds->dev_type == SIMDEV_SERIAL)
{
if (device_settings != NULL)
{
const char* temp = NULL;
int found = config_setting_lookup_string(device_settings, "subtype", &temp);
if(temp != NULL && found > 0)
{
strtodevsubsubtype(temp, ds);
}
int motorposition = 8;
config_setting_lookup_int(device_settings, "motors", &motorposition);
ds->serialdevsettings.motorsposition = motorposition;
int numlights = 6;
config_setting_lookup_int(device_settings, "numlights", &numlights);
ds->serialdevsettings.numlights = numlights;
int numleds = 6;
config_setting_lookup_int(device_settings, "numleds", &numleds);
ds->serialdevsettings.numleds = numleds;
int startled = 1;
config_setting_lookup_int(device_settings, "startled", &startled);
ds->serialdevsettings.startled = startled;
int endled = 1;
config_setting_lookup_int(device_settings, "endled", &endled);
ds->serialdevsettings.endled = endled;
int baud = 9600;
config_setting_lookup_int(device_settings, "baud", &baud);
ds->serialdevsettings.baud = baud;
double ampfactor = 1.0;
ds->serialdevsettings.ampfactor = 1.0;
found = config_setting_lookup_float(device_settings, "ampfactor", &ampfactor);
ds->serialdevsettings.ampfactor = ampfactor;
double fanpower = 0.6;
config_setting_lookup_float(device_settings, "fanpower", &fanpower);
ds->serialdevsettings.fanpower = fanpower;
slogt("set port baud rate to %i, ampfactor %f, fanpower %f", baud, ampfactor, fanpower);
}
}
ds->has_haptic_effects = false;
if (ds->dev_subtype == SIMDEVTYPE_USBHAPTIC || ds->dev_subtype == SIMDEVTYPE_USBWHEEL || ds->dev_type == SIMDEV_SOUND || ds->dev_subtype == SIMDEVTYPE_SERIALHAPTIC)
{
slogt("analysing haptic effect settings");
ds->has_haptic_effects = true;
const char* effect;
config_setting_lookup_string(device_settings, "effect", &effect);
strtoeffecttype(effect, ds);
if (ds->hapticsettings.effect_type == EFFECT_TYRESLIP || ds->hapticsettings.effect_type == EFFECT_TYRELOCK || ds->hapticsettings.effect_type == EFFECT_ABSBRAKES || ds->hapticsettings.effect_type == EFFECT_SUSPENSION )
{
gettyre(device_settings, ds);
ds->hapticsettings.threshold = 0;
int found = config_setting_lookup_float(device_settings, "threshold", &ds->hapticsettings.threshold);
}
slogi("reading configured haptic effect settings");
ds->hapticsettings.frequency = 0;
ds->hapticsettings.frequencyMax = 0;
ds->hapticsettings.amplitude = 50;
ds->hapticsettings.amplitudeMax = 50;
if (ds->hapticsettings.effect_type == EFFECT_GEARSHIFT)
{
ds->hapticsettings.duration = .125;
}
if (device_settings != NULL)
{
config_setting_lookup_int(device_settings, "frequency", &ds->hapticsettings.frequency);
config_setting_lookup_int(device_settings, "frequencyMax", &ds->hapticsettings.frequencyMax);
config_setting_lookup_int(device_settings, "amplitude", &ds->hapticsettings.amplitude);
config_setting_lookup_float(device_settings, "duration", &ds->hapticsettings.duration);
config_setting_lookup_int(device_settings, "amplitudeMax", &ds->hapticsettings.amplitudeMax);
const char* temp = NULL;
int found = 0;
found = config_setting_lookup_string(device_settings, "modulation", &temp);
ds->hapticsettings.modulation = EFFECT_MODULATION_NONE;
if (found == 0)
{
ds->hapticsettings.modulation = EFFECT_MODULATION_NONE;
slogd("Effect modulation not found, set to none");
}
else
{
if(strcicmp(temp, "FREQUENCY") == 0)
{
ds->hapticsettings.modulation = EFFECT_MODULATION_FREQUENCY;
if(ds->hapticsettings.frequencyMax == 0 || ds->hapticsettings.frequencyMax < ds->hapticsettings.frequency)
{
ds->hapticsettings.modulation = EFFECT_MODULATION_NONE;
slogw("Falling back to no frequency modulation since frequencyMax is either not set or set below target frequency");
}
else
{
slogi("Effect modulation found, set to FREQUENCY");
}
}
else if(strcicmp(temp, "AMPLIFY") == 0)
{
ds->hapticsettings.modulation = EFFECT_MODULATION_AMPLIFY;
slogi("Effect modulation found, set to AMPLIFY");
}
else
{
slogw("%s is not a valid modulation type, falling back to no effect modulation");
ds->hapticsettings.modulation = EFFECT_MODULATION_NONE;
}
}
ds->hapticsettings.motorposition = 0;
int motorposition = 1;
config_setting_lookup_int(device_settings, "motors", &motorposition);
ds->hapticsettings.motorposition = motorposition;
}
if (ds->dev_type == SIMDEV_SOUND)
{
slogi("reading configured sound device settings");
ds->sounddevsettings.volume = 0;
ds->sounddevsettings.pan = 0;
ds->sounddevsettings.channels = 1;
ds->sounddevsettings.noise = 0;
if (ds->hapticsettings.effect_type == EFFECT_GEARSHIFT)
{
ds->hapticsettings.duration = .125;
}
if (device_settings != NULL)
{
config_setting_lookup_int(device_settings, "volume", &ds->sounddevsettings.volume);
config_setting_lookup_int(device_settings, "pan", &ds->sounddevsettings.pan);
config_setting_lookup_int(device_settings, "channels", &ds->sounddevsettings.channels);
config_setting_lookup_int(device_settings, "noise", &ds->sounddevsettings.noise);
const char* temp = NULL;
int found = 0;
found = config_setting_lookup_string(device_settings, "devid", &temp);
if (found == CONFIG_FALSE)
{
ds->dev = NULL;
}
else
{
if(temp != NULL)
{
ds->dev = strdup(temp);
}
}
}
}
}
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 = NULL;
const char* device_subtype = NULL;
const char* device_config_file = NULL;
int found = 0;
config_setting_lookup_string(config_device, "device", &device_type);
config_setting_lookup_string(config_device, "type", &device_subtype);
found = config_setting_lookup_string(config_device, "config", &device_config_file);
slogt("device type: %s", device_type);
slogt("device sub type: %s", device_subtype);
if(found == CONFIG_FALSE)
{
device_config_file = NULL;
}
else
{
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 getsingledevice(const char* config_file_str, int confignum, int devicenum, 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 num_devices = config_setting_length(config_devices);
int i = 0;
int error = MONOCOQUE_ERROR_NONE;
while (i<num_devices)
{
if(i!=devicenum)
{
i++;
continue;
}
error = MONOCOQUE_ERROR_NONE;
config_setting_t* config_device = config_setting_get_elem(config_devices, i);
const char* device_type = NULL;
const char* device_subtype = NULL;
const char* device_config_file = NULL;
int found = 0;
config_setting_lookup_string(config_device, "device", &device_type);
config_setting_lookup_string(config_device, "type", &device_subtype);
found = config_setting_lookup_string(config_device, "config", &device_config_file);
slogt("device type: %s", device_type);
slogt("device sub type: %s", device_subtype);
if(found == CONFIG_FALSE)
{
device_config_file = NULL;
}
else
{
slogt("device config file: %s", device_config_file);
}
if (error == MONOCOQUE_ERROR_NONE)
{
error = devsetup(device_type, device_subtype, device_config_file, ms, ds, config_device);
}
if (error == MONOCOQUE_ERROR_NONE)
{
numdevices++;
}
i++;
}
}
config_destroy(&cfg);
return numdevices;
}
static const char *haptic_effect_type_to_string(VibrationEffectType effect)
{
switch (effect)
{
case EFFECT_ENGINERPM:
return "EngineRPM";
case EFFECT_GEARSHIFT:
return "GearShift";
case EFFECT_ABSBRAKES:
return "ABS";
case EFFECT_TYRESLIP:
return "TyreSlip";
case EFFECT_TYRELOCK:
return "TyreLock";
case EFFECT_SUSPENSION:
return "Suspension";
default:
return NULL;
}
}
static const char *tyre_identifier_to_string(MonocoqueTyreIdentifier tyre)
{
switch (tyre)
{
case FRONTLEFT:
return "FrontLeft";
case FRONTRIGHT:
return "FrontRight";
case REARLEFT:
return "RearLeft";
case REARRIGHT:
return "RearRight";
case FRONTS:
return "Front";
case REARS:
return "Rear";
case ALLFOUR:
return "ALL";
default:
return NULL;
}
}
static const char *modulation_type_to_string(EffectModulationType modulation)
{
switch (modulation)
{
case EFFECT_MODULATION_NONE:
return "none";
case EFFECT_MODULATION_FREQUENCY:
return "frequency";
case EFFECT_MODULATION_AMPLIFY:
return "amplify";
default:
return NULL;
}
}
static int set_string(config_setting_t *parent, const char *name, const char *value)
{
config_setting_t *setting;
if (value == NULL)
return 1;
setting = config_setting_lookup(parent, name);
if (setting == NULL)
setting = config_setting_add(parent, name, CONFIG_TYPE_STRING);
if (setting == NULL)
return 0;
return config_setting_set_string(setting, value);
}
static int set_int(config_setting_t *parent, const char *name, int value)
{
config_setting_t *setting;
setting = config_setting_lookup(parent, name);
if (setting == NULL)
setting = config_setting_add(parent, name, CONFIG_TYPE_INT);
if (setting == NULL)
return 0;
return config_setting_set_int(setting, value);
}
int set_float(config_setting_t *parent, const char *name, double value)
{
config_setting_t *setting;
setting = config_setting_lookup(parent, name);
if (setting == NULL)
setting = config_setting_add(parent, name, CONFIG_TYPE_FLOAT);
if (setting == NULL)
return 0;
return config_setting_set_float(setting, value);
}
int delete_device_config(config_t *cfg, const char *configfile, int confignum, int devicenum)
{
config_setting_t *configs;
config_setting_t *config;
config_setting_t *devices;
configs = config_lookup(cfg, "configs");
if (configs == NULL)
return -1;
config = config_setting_get_elem(configs, confignum);
if (config == NULL)
return -1;
devices = config_setting_lookup(config, "devices");
if (devices == NULL)
return -1;
if (devicenum < 0 || devicenum >= config_setting_length(devices))
return -1;
if (!config_setting_remove_elem(devices, devicenum))
return -1;
if (!config_write_file(cfg, configfile))
return -1;
return 0;
}
static const char *device_type_to_string(DeviceType device_type)
{
switch (device_type)
{
case SIMDEV_USB:
return "USB";
case SIMDEV_SOUND:
return "Sound";
case SIMDEV_SERIAL:
return "Serial";
case SIMDEV_UNKNOWN:
return "Unknown";
default:
return "Unknown";
}
}
static const char *device_subtype_to_string(DeviceSubType device_subtype)
{
switch (device_subtype)
{
case SIMDEVTYPE_SOUNDHAPTIC:
return "SoundHaptic";
case SIMDEVTYPE_TACHOMETER:
return "Tachometer";
case SIMDEVTYPE_USBHAPTIC:
return "UsbHaptic";
case SIMDEVTYPE_USBWHEEL:
return "UsbWheel";
case SIMDEVTYPE_SHIFTLIGHTS:
return "ShiftLights";
case SIMDEVTYPE_SIMWIND:
return "SimWind";
case SIMDEVTYPE_SERIALHAPTIC:
return "SerialHaptic";
case SIMDEVTYPE_SERIALWHEEL:
return "Wheel";
case SIMDEVTYPE_SIMLED:
return "Simleds";
case SIMDEVTYPE_ARDUINOCUSTOM:
return "ArduinoCustom";
case SIMDEVTYPE_UNKNOWN:
default:
return "Unknown";
}
}
static const char *haptic_effect_to_string(VibrationEffectType effect)
{
switch (effect)
{
case EFFECT_ENGINERPM:
return "Engine";
case EFFECT_GEARSHIFT:
return "Gear";
case EFFECT_ABSBRAKES:
return "ABS";
case EFFECT_TYRESLIP:
return "TyreSlip";
case EFFECT_TYRELOCK:
return "TyreLock";
case EFFECT_SUSPENSION:
return "Suspension";
default:
return "Unknown";
}
}
static const char *modulation_to_string(EffectModulationType modulation)
{
switch (modulation)
{
case EFFECT_MODULATION_NONE:
return "None";
case EFFECT_MODULATION_FREQUENCY:
return "Frequency";
case EFFECT_MODULATION_AMPLIFY:
return "Amplitude";
default:
return "Unknown";
}
}
static const char *tyre_to_string(MonocoqueTyreIdentifier tyre)
{
switch (tyre)
{
case FRONTLEFT:
return "FrontLeft";
case FRONTRIGHT:
return "FrontRight";
case REARLEFT:
return "RearLeft";
case REARRIGHT:
return "RearRight";
case FRONTS:
return "Fronts";
case REARS:
return "Rears";
case ALLFOUR:
return "All";
default:
return "Unknown";
}
}
int save_device_config(config_t *cfg, const char* configfile, int confignum, int devicenum, const DeviceSettings *ds)
{
config_setting_t *configs;
config_setting_t *config_entry;
config_setting_t *devices;
config_setting_t *device_entry;
if (cfg == NULL || ds == NULL)
return 0;
slogd("Saving device with device num %i and confignum %i", devicenum, confignum);
configs = config_lookup(cfg, "configs");
if (configs == NULL)
return 0;
config_entry = config_setting_get_elem(configs, confignum);
if (config_entry == NULL)
return 0;
devices = config_setting_lookup(config_entry, "devices");
if (devices == NULL)
return 0;
device_entry = config_setting_get_elem(devices, devicenum);
if (device_entry == NULL)
{
device_entry = config_setting_add(devices, NULL, CONFIG_TYPE_GROUP);
if (device_entry == NULL)
return 0;
if (config_setting_index(device_entry) != devicenum)
return 0;
}
if (device_entry == NULL)
return 0;
set_string(device_entry, "device", device_type_to_string(ds->dev_type));
set_int(device_entry, "fps", ds->fps);
if (ds->specific_config_file != NULL)
{
set_string(device_entry, "config", ds->specific_config_file);
}
if (ds->dev != NULL)
{
set_string(device_entry, "devid", ds->dev);
}
switch (ds->dev_type)
{
case SIMDEV_SERIAL:
{
set_string(device_entry, "type", device_subtype_to_string(ds->dev_type + SerialDevicesOffset));
const SerialDeviceSettings *ss = &ds->serialdevsettings;
set_int(device_entry, "baud", ss->baud);
set_float(device_entry, "ampfactor", ss->ampfactor);
set_float(device_entry, "fanpower", ss->fanpower);
break;
}
case SIMDEV_SOUND:
{
set_string(device_entry, "type", device_subtype_to_string(ds->dev_type));
const SoundDeviceSettings *ss = &ds->sounddevsettings;
set_int(device_entry, "volume", ss->volume);
set_int(device_entry, "pan", ss->pan);
set_int(device_entry, "channels", ss->channels);
set_int(device_entry, "noise", ss->noise);
break;
}
case SIMDEV_USB:
{
set_string(device_entry, "type", device_subtype_to_string(ds->dev_type + USBDevicesOffset));
const USBDeviceSettings *us = &ds->usbdevsettings;
break;
}
default:
break;
}
if(ds->has_haptic_effects == true)
{
slogt("Saving haptic effect settings");
const HapticEffectSettings *hs = &ds->hapticsettings;
set_int(device_entry, "frequency", hs->frequency);
set_int(device_entry, "amplitude", hs->amplitude);
set_int(device_entry, "frequencyMax", hs->frequencyMax);
set_int(device_entry, "amplitudeMax", hs->amplitudeMax);
set_float(device_entry, "threshold", hs->threshold);
set_float(device_entry, "duration", hs->duration);
set_string(device_entry, "effect", haptic_effect_to_string(hs->effect_type));
set_string(device_entry, "tyre", tyre_to_string(hs->tyre));
set_string(device_entry, "modulation", modulation_to_string(hs->modulation));
}
if(ds->has_led_effects == true)
{
slogt("Saving led effect settings");
const SerialDeviceSettings *ss = &ds->serialdevsettings;
set_int(device_entry, "numleds", ss->numleds);
set_int(device_entry, "startled", ss->startled);
set_int(device_entry, "endled", ss->endled);
}
if(!config_write_file(cfg, configfile))
{
return 1;
}
return 0;
}
config_t *open_monocoque_config(const char *filename)
{
config_t *cfg;
if (filename == NULL)
return NULL;
cfg = malloc(sizeof(*cfg));
if (cfg == NULL)
return NULL;
config_init(cfg);
if (!config_read_file(cfg, filename))
{
fprintf(stderr,
"Failed to read config file '%s' (line %d): %s\n",
filename,
config_error_line(cfg),
config_error_text(cfg));
config_destroy(cfg);
free(cfg);
return NULL;
}
return cfg;
}
void close_monocoque_config(config_t* cfg)
{
if (cfg == NULL)
return;
config_destroy(cfg);
}
int settingsfree(DeviceSettings ds)
{
if (ds.dev != NULL)
{
free(ds.dev);
}
if(ds.has_config && ds.specific_config_file != NULL)
{
free(ds.specific_config_file);
}
return 0;
}
int monocoquesettingsfree(MonocoqueSettings* ms)
{
if(ms->tyre_diameter_config != NULL)
{
free(ms->tyre_diameter_config);
ms->tyre_diameter_config = NULL;
}
if(ms->config_str != NULL)
{
free(ms->config_str);
ms->config_str = NULL;
}
if(ms->log_filename_str != NULL)
{
free(ms->log_filename_str);
ms->log_filename_str = NULL;
}
if(ms->log_dirname_str != NULL)
{
free(ms->log_dirname_str);
ms->log_dirname_str = NULL;
}
}