2020-04-08 11:27:41 +00:00
|
|
|
// Copyright 2019, Collabora, Ltd.
|
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Code to manage the settings file.
|
|
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
|
|
|
* @ingroup st_prober
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "util/u_file.h"
|
|
|
|
#include "util/u_json.h"
|
|
|
|
#include "util/u_debug.h"
|
2020-10-15 16:58:52 +00:00
|
|
|
|
2020-04-08 11:27:41 +00:00
|
|
|
#include "p_prober.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2020-10-15 16:58:52 +00:00
|
|
|
DEBUG_GET_ONCE_OPTION(active_config, "P_OVERRIDE_ACTIVE_CONFIG", NULL)
|
|
|
|
|
2020-04-08 11:27:41 +00:00
|
|
|
|
|
|
|
char *
|
|
|
|
read_content(FILE *file)
|
|
|
|
{
|
|
|
|
// Go to the end of the file.
|
|
|
|
fseek(file, 0L, SEEK_END);
|
|
|
|
size_t file_size = ftell(file);
|
|
|
|
|
|
|
|
// Return back to the start of the file.
|
|
|
|
fseek(file, 0L, SEEK_SET);
|
|
|
|
|
|
|
|
char *buffer = (char *)calloc(file_size + 1, sizeof(char));
|
|
|
|
if (buffer == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the actual reading.
|
|
|
|
size_t ret = fread(buffer, sizeof(char), file_size, file);
|
|
|
|
if (ret != file_size) {
|
|
|
|
free(buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2020-05-01 17:11:27 +00:00
|
|
|
void
|
|
|
|
p_json_open_or_create_main_file(struct prober *p)
|
2020-04-08 11:27:41 +00:00
|
|
|
{
|
2020-07-16 03:11:31 +00:00
|
|
|
#ifdef XRT_OS_LINUX
|
2020-05-01 17:11:27 +00:00
|
|
|
char tmp[1024];
|
2021-01-14 14:13:48 +00:00
|
|
|
ssize_t ret = u_file_get_path_in_config_dir("config_v0.json", tmp, sizeof(tmp));
|
2020-05-01 17:11:27 +00:00
|
|
|
if (ret <= 0) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E(
|
|
|
|
"Could not load or create config file no $HOME "
|
|
|
|
"or $XDG_CONFIG_HOME env variables defined");
|
2020-05-01 17:11:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-08 11:27:41 +00:00
|
|
|
FILE *file = u_file_open_file_in_config_dir("config_v0.json", "r");
|
|
|
|
if (file == NULL) {
|
2020-05-01 17:11:27 +00:00
|
|
|
return;
|
2020-04-08 11:27:41 +00:00
|
|
|
}
|
|
|
|
|
2020-05-01 17:11:27 +00:00
|
|
|
p->json.file_loaded = true;
|
|
|
|
|
2020-04-08 11:27:41 +00:00
|
|
|
char *str = read_content(file);
|
|
|
|
fclose(file);
|
|
|
|
if (str == NULL) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Could not read the contents of '%s'!", tmp);
|
2020-05-01 17:11:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No config created, ignore.
|
|
|
|
if (strlen(str) == 0) {
|
|
|
|
free(str);
|
|
|
|
return;
|
2020-04-08 11:27:41 +00:00
|
|
|
}
|
|
|
|
|
2020-05-01 17:11:27 +00:00
|
|
|
p->json.root = cJSON_Parse(str);
|
|
|
|
if (p->json.root == NULL) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Failed to parse JSON in '%s':\n%s\n#######", tmp, str);
|
|
|
|
U_LOG_E("'%s'", cJSON_GetErrorPtr());
|
2020-04-08 11:27:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(str);
|
2020-07-16 03:11:31 +00:00
|
|
|
#else
|
|
|
|
//! @todo implement the underlying u_file_get_path_in_config_dir
|
|
|
|
return;
|
|
|
|
#endif
|
2020-04-08 11:27:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static cJSON *
|
|
|
|
get_obj(cJSON *json, const char *name)
|
|
|
|
{
|
|
|
|
cJSON *item = cJSON_GetObjectItemCaseSensitive(json, name);
|
|
|
|
if (item == NULL) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Failed to find node '%s'!", name);
|
2020-04-08 11:27:41 +00:00
|
|
|
}
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
XRT_MAYBE_UNUSED static bool
|
|
|
|
get_obj_bool(cJSON *json, const char *name, bool *out_bool)
|
|
|
|
{
|
|
|
|
cJSON *item = get_obj(json, name);
|
|
|
|
if (item == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!u_json_get_bool(item, out_bool)) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Failed to parse '%s'!", name);
|
2020-04-08 11:27:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
get_obj_int(cJSON *json, const char *name, int *out_int)
|
|
|
|
{
|
|
|
|
cJSON *item = get_obj(json, name);
|
|
|
|
if (item == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!u_json_get_int(item, out_int)) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Failed to parse '%s'!", name);
|
2020-04-08 11:27:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
get_obj_str(cJSON *json, const char *name, char *array, size_t array_size)
|
|
|
|
{
|
|
|
|
cJSON *item = get_obj(json, name);
|
|
|
|
if (item == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!u_json_get_string_into_array(item, array, array_size)) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Failed to parse '%s'!", name);
|
2020-04-08 11:27:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-10-15 16:58:52 +00:00
|
|
|
static bool
|
|
|
|
is_json_ok(struct prober *p)
|
|
|
|
{
|
|
|
|
if (p->json.root == NULL) {
|
|
|
|
if (p->json.file_loaded) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("JSON not parsed!");
|
2020-10-15 16:58:52 +00:00
|
|
|
} else {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_W("No config file!");
|
2020-10-15 16:58:52 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2021-01-14 14:13:48 +00:00
|
|
|
parse_active(const char *str, const char *from, enum p_active_config *out_active)
|
2020-10-15 16:58:52 +00:00
|
|
|
{
|
|
|
|
if (strcmp(str, "none") == 0) {
|
|
|
|
*out_active = P_ACTIVE_CONFIG_NONE;
|
|
|
|
} else if (strcmp(str, "tracking") == 0) {
|
|
|
|
*out_active = P_ACTIVE_CONFIG_TRACKING;
|
2020-10-15 17:11:25 +00:00
|
|
|
} else if (strcmp(str, "remote") == 0) {
|
|
|
|
*out_active = P_ACTIVE_CONFIG_REMOTE;
|
2020-10-15 16:58:52 +00:00
|
|
|
} else {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Unknown active config '%s' from %s.", str, from);
|
2020-10-15 16:58:52 +00:00
|
|
|
*out_active = P_ACTIVE_CONFIG_NONE;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
p_json_get_active(struct prober *p, enum p_active_config *out_active)
|
|
|
|
{
|
|
|
|
const char *str = debug_get_option_active_config();
|
|
|
|
if (str != NULL && parse_active(str, "environment", out_active)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char tmp[256];
|
2021-01-14 14:13:48 +00:00
|
|
|
if (!is_json_ok(p) || !get_obj_str(p->json.root, "active", tmp, sizeof(tmp))) {
|
2020-10-15 16:58:52 +00:00
|
|
|
*out_active = P_ACTIVE_CONFIG_NONE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_active(tmp, "json", out_active);
|
|
|
|
}
|
|
|
|
|
2020-10-15 17:11:25 +00:00
|
|
|
bool
|
|
|
|
p_json_get_remote_port(struct prober *p, int *out_port)
|
|
|
|
{
|
|
|
|
cJSON *t = cJSON_GetObjectItemCaseSensitive(p->json.root, "remote");
|
|
|
|
if (t == NULL) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("No remote node");
|
2020-10-15 17:11:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ver = -1;
|
|
|
|
if (!get_obj_int(t, "version", &ver)) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Missing version tag!");
|
2020-10-15 17:11:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (ver >= 1) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Unknown version tag '%i'!", ver);
|
2020-10-15 17:11:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int port = 0;
|
|
|
|
if (!get_obj_int(t, "port", &port)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_port = port;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-04-08 11:27:41 +00:00
|
|
|
bool
|
2020-05-01 17:11:27 +00:00
|
|
|
p_json_get_tracking_settings(struct prober *p, struct xrt_settings_tracking *s)
|
2020-04-08 11:27:41 +00:00
|
|
|
{
|
2020-05-01 17:11:27 +00:00
|
|
|
if (p->json.root == NULL) {
|
|
|
|
if (p->json.file_loaded) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("JSON not parsed!");
|
2020-05-01 17:11:27 +00:00
|
|
|
} else {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_W("No config file!");
|
2020-05-01 17:11:27 +00:00
|
|
|
}
|
2020-04-08 11:27:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-01 17:11:27 +00:00
|
|
|
cJSON *t = cJSON_GetObjectItemCaseSensitive(p->json.root, "tracking");
|
2020-04-08 11:27:41 +00:00
|
|
|
if (t == NULL) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("No tracking node");
|
2020-04-08 11:27:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char tmp[16];
|
|
|
|
|
|
|
|
int ver = -1;
|
|
|
|
bool bad = false;
|
|
|
|
|
|
|
|
bad |= !get_obj_int(t, "version", &ver);
|
|
|
|
if (bad || ver >= 1) {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_E("Missing or unknown version tag '%i'", ver);
|
2020-04-08 11:27:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
bad |= !get_obj_str(t, "camera_name", s->camera_name, sizeof(s->camera_name));
|
2020-04-08 11:27:41 +00:00
|
|
|
bad |= !get_obj_int(t, "camera_mode", &s->camera_mode);
|
|
|
|
bad |= !get_obj_str(t, "camera_type", tmp, sizeof(tmp));
|
2021-01-14 14:13:48 +00:00
|
|
|
bad |= !get_obj_str(t, "calibration_path", s->calibration_path, sizeof(s->calibration_path));
|
2020-04-08 11:27:41 +00:00
|
|
|
if (bad) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(tmp, "regular_mono") == 0) {
|
|
|
|
s->camera_type = XRT_SETTINGS_CAMERA_TYPE_REGULAR_MONO;
|
|
|
|
} else if (strcmp(tmp, "regular_sbs") == 0) {
|
|
|
|
s->camera_type = XRT_SETTINGS_CAMERA_TYPE_REGULAR_SBS;
|
|
|
|
} else if (strcmp(tmp, "ps4") == 0) {
|
|
|
|
s->camera_type = XRT_SETTINGS_CAMERA_TYPE_PS4;
|
|
|
|
} else if (strcmp(tmp, "leap_motion") == 0) {
|
|
|
|
s->camera_type = XRT_SETTINGS_CAMERA_TYPE_LEAP_MOTION;
|
|
|
|
} else {
|
2020-12-16 17:12:56 +00:00
|
|
|
U_LOG_W("Unknown camera type '%s'", tmp);
|
2020-04-08 11:27:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|