Skip to content

Commit f6e9631

Browse files
committed
Parse only once with cached values / Add value and range checks / Log all errors
1 parent 0aa2bfa commit f6e9631

File tree

3 files changed

+153
-78
lines changed

3 files changed

+153
-78
lines changed

main/display.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,18 @@ static void theme_apply(lv_theme_t *theme, lv_obj_t *obj) {
4949

5050
static esp_err_t read_display_config(GlobalState * GLOBAL_STATE)
5151
{
52-
char * display_config = nvs_config_get_string(NVS_CONFIG_DISPLAY, DEFAULT_DISPLAY);
52+
char * display_config_name = nvs_config_get_string(NVS_CONFIG_DISPLAY, DEFAULT_DISPLAY);
53+
const DisplayConfig * display_config = get_display_config(display_config_name);
5354

54-
for (int i = 0 ; i < ARRAY_SIZE(display_configs); i++) {
55-
if (strcmp(display_configs[i].name, display_config) == 0) {
56-
GLOBAL_STATE->DISPLAY_CONFIG = display_configs[i];
55+
if (display_config) {
56+
GLOBAL_STATE->DISPLAY_CONFIG = *display_config;
5757

58-
ESP_LOGI(TAG, "%s", GLOBAL_STATE->DISPLAY_CONFIG.name);
59-
free(display_config);
60-
return ESP_OK;
61-
}
58+
ESP_LOGI(TAG, "%s", GLOBAL_STATE->DISPLAY_CONFIG.name);
59+
free(display_config_name);
60+
return ESP_OK;
6261
}
6362

64-
free(display_config);
63+
free(display_config_name);
6564
return ESP_FAIL;
6665
}
6766

@@ -220,3 +219,13 @@ esp_err_t display_on(bool display_on)
220219

221220
return ESP_OK;
222221
}
222+
223+
const DisplayConfig * get_display_config(const char * name)
224+
{
225+
for (int i = 0 ; i < ARRAY_SIZE(display_configs); i++) {
226+
if (strcmp(display_configs[i].name, name) == 0) {
227+
return &display_configs[i];
228+
}
229+
}
230+
return NULL;
231+
}

main/display.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ static const DisplayConfig display_configs[] = {
2626

2727
esp_err_t display_init(void * pvParameters);
2828
esp_err_t display_on(bool display_on);
29+
const DisplayConfig * get_display_config(const char * name);
2930

3031
#endif /* DISPLAY_H_ */

main/http_server/http_server.c

Lines changed: 134 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,14 @@
4040
#include "statistics_task.h"
4141
#include "theme_api.h" // Add theme API include
4242
#include "axe-os/api/system/asic_settings.h"
43+
#include "display.h"
4344
#include "http_server.h"
4445

4546
#define JSON_ALL_STATS_ELEMENT_SIZE 120
4647
#define JSON_DASHBOARD_STATS_ELEMENT_SIZE 60
4748

49+
#define NVS_STR_LIMIT (4000 - 1)
50+
4851
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
4952

5053
static const char * TAG = "http_server";
@@ -54,8 +57,13 @@ typedef struct {
5457
const char * name;
5558
int json_type;
5659
nvs_type_t nvs_type;
60+
int min;
61+
int max;
5762
const char * nvs_name;
58-
} SettingsFormat;
63+
bool updated;
64+
int int_value;
65+
char * str_value;
66+
} Settings;
5967

6068
/* Handler for WiFi scan endpoint */
6169
static esp_err_t GET_wifi_scan(httpd_req_t *req)
@@ -462,113 +470,171 @@ bool check_json_type(int expected_type, const cJSON * const item)
462470
return false;
463471
}
464472

465-
bool check_settings_and_update(const cJSON * const root, bool update)
473+
bool check_settings_and_update(const cJSON * const root)
466474
{
475+
bool result = true;
467476
const int cJSON_Option = (cJSON_Number | cJSON_True | cJSON_False);
468477

469-
const SettingsFormat settings_format[] = {
470-
{ .name = "stratumURL", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_STRATUM_URL },
471-
{ .name = "fallbackStratumURL", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_URL },
472-
{ .name = "stratumUser", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_STRATUM_USER },
473-
{ .name = "stratumPassword", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_STRATUM_PASS },
474-
{ .name = "fallbackStratumUser", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_USER },
475-
{ .name = "fallbackStratumPassword", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PASS },
476-
{ .name = "stratumPort", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_STRATUM_PORT },
477-
{ .name = "fallbackStratumPort", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PORT },
478-
{ .name = "ssid", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_WIFI_SSID },
479-
{ .name = "wifiPass", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_WIFI_PASS },
480-
{ .name = "hostname", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_HOSTNAME },
481-
{ .name = "coreVoltage", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_ASIC_VOLTAGE },
482-
{ .name = "frequency", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_ASIC_FREQ },
483-
{ .name = "overheat_mode", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_OVERHEAT_MODE },
484-
{ .name = "display", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .nvs_name = NVS_CONFIG_DISPLAY },
485-
{ .name = "flipscreen", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_FLIP_SCREEN },
486-
{ .name = "invertscreen", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_INVERT_SCREEN },
487-
{ .name = "displayTimeout", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_I32, .nvs_name = NVS_CONFIG_DISPLAY_TIMEOUT },
488-
{ .name = "autofanspeed", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_AUTO_FAN_SPEED },
489-
{ .name = "fanspeed", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_FAN_SPEED },
490-
{ .name = "temptarget", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_TEMP_TARGET },
491-
{ .name = "statsFrequency", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_STATISTICS_FREQUENCY },
492-
{ .name = "overclockEnabled", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_OVERCLOCK_ENABLED }
478+
Settings settings[] = {
479+
{ .name = "stratumURL", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_STRATUM_URL },
480+
{ .name = "fallbackStratumURL", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_URL },
481+
{ .name = "stratumUser", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_STRATUM_USER },
482+
{ .name = "stratumPassword", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_STRATUM_PASS },
483+
{ .name = "fallbackStratumUser", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_USER },
484+
{ .name = "fallbackStratumPassword", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PASS },
485+
{ .name = "stratumPort", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_STRATUM_PORT },
486+
{ .name = "fallbackStratumPort", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PORT },
487+
{ .name = "ssid", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 1, .max = 32, .nvs_name = NVS_CONFIG_WIFI_SSID },
488+
{ .name = "wifiPass", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 1, .max = 63, .nvs_name = NVS_CONFIG_WIFI_PASS },
489+
{ .name = "hostname", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 1, .max = 32, .nvs_name = NVS_CONFIG_HOSTNAME },
490+
{ .name = "coreVoltage", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 1, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_ASIC_VOLTAGE },
491+
{ .name = "frequency", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 1, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_ASIC_FREQ },
492+
{ .name = "overheat_mode", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 0, .nvs_name = NVS_CONFIG_OVERHEAT_MODE },
493+
{ .name = "display", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_DISPLAY },
494+
{ .name = "flipscreen", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 1, .nvs_name = NVS_CONFIG_FLIP_SCREEN },
495+
{ .name = "invertscreen", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 1, .nvs_name = NVS_CONFIG_INVERT_SCREEN },
496+
{ .name = "displayTimeout", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_I32, .min = -1, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_DISPLAY_TIMEOUT },
497+
{ .name = "autofanspeed", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 1, .nvs_name = NVS_CONFIG_AUTO_FAN_SPEED },
498+
{ .name = "fanspeed", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 100, .nvs_name = NVS_CONFIG_FAN_SPEED },
499+
{ .name = "temptarget", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 35, .max = 66, .nvs_name = NVS_CONFIG_TEMP_TARGET },
500+
{ .name = "statsFrequency", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_STATISTICS_FREQUENCY },
501+
{ .name = "overclockEnabled", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 1, .nvs_name = NVS_CONFIG_OVERCLOCK_ENABLED }
493502
};
494503

495-
for (int i = 0; i < ARRAY_SIZE(settings_format); i++) {
496-
cJSON * item = cJSON_GetObjectItem(root, settings_format[i].name);
504+
// check for data type and data type range
505+
for (int i = 0; i < ARRAY_SIZE(settings); i++) {
506+
cJSON * item = cJSON_GetObjectItem(root, settings[i].name);
497507
if (item) {
498-
if (check_json_type(settings_format[i].json_type, item)) {
499-
switch (settings_format[i].nvs_type) {
508+
// check data type
509+
if (check_json_type(settings[i].json_type, item)) {
510+
// check data type range
511+
switch (settings[i].nvs_type) {
500512
case NVS_TYPE_U8:
501513
if ((0 > item->valueint) || (UCHAR_MAX < item->valueint)) {
502-
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_U8", item->valueint, settings_format[i].name);
503-
return false;
504-
}
505-
if (update) {
506-
nvs_config_set_u16(settings_format[i].nvs_name, item->valueint); // nvs u8 is not used
514+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_U8", item->valueint, settings[i].name);
515+
result = false;
507516
}
508517
break;
509518
case NVS_TYPE_U16:
510519
if ((0 > item->valueint) || (USHRT_MAX < item->valueint)) {
511-
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_U16", item->valueint, settings_format[i].name);
512-
return false;
513-
}
514-
if (update) {
515-
nvs_config_set_u16(settings_format[i].nvs_name, item->valueint);
520+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_U16", item->valueint, settings[i].name);
521+
result = false;
516522
}
517523
break;
518524
case NVS_TYPE_U32:
519525
if (0 > item->valueint) {
520-
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_U32", item->valueint, settings_format[i].name);
521-
return false;
522-
}
523-
if (update) {
524-
nvs_config_set_u64(settings_format[i].nvs_name, item->valueint); // nvs u32 is not used
526+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_U32", item->valueint, settings[i].name);
527+
result = false;
525528
}
526529
break;
527530
case NVS_TYPE_I8:
528531
if ((CHAR_MIN > item->valueint) || (CHAR_MAX < item->valueint)) {
529-
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_I8", item->valueint, settings_format[i].name);
530-
return false;
531-
}
532-
if (update) {
533-
nvs_config_set_i32(settings_format[i].nvs_name, item->valueint); // nvs i8 is not used
532+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_I8", item->valueint, settings[i].name);
533+
result = false;
534534
}
535535
break;
536536
case NVS_TYPE_I16:
537537
if ((SHRT_MIN > item->valueint) || (SHRT_MAX < item->valueint)) {
538-
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_I16", item->valueint, settings_format[i].name);
539-
return false;
540-
}
541-
if (update) {
542-
nvs_config_set_i32(settings_format[i].nvs_name, item->valueint); // nvs i16 is not used
538+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_I16", item->valueint, settings[i].name);
539+
result = false;
543540
}
544541
break;
545542
case NVS_TYPE_I32:
546-
if (update) {
547-
nvs_config_set_i32(settings_format[i].nvs_name, item->valueint);
548-
}
549543
break;
550544
case NVS_TYPE_STR:
551-
if (update) {
552-
nvs_config_set_string(settings_format[i].nvs_name, item->valuestring);
545+
const size_t str_value_len = strlen(item->valuestring);
546+
settings[i].str_value = strdup(item->valuestring);
547+
548+
if (0 > settings[i].min) {
549+
settings[i].min = 0;
550+
}
551+
552+
if ((str_value_len < settings[i].min) || (str_value_len > settings[i].max)) {
553+
ESP_LOGW(TAG, "Value '%s' for '%s' is out of length (%d-%d)", item->valuestring, settings[i].name, settings[i].min, settings[i].max);
554+
result = false;
553555
}
554556
break;
555557
default:
556-
ESP_LOGW(TAG, "NVS type (%d) for '%s' not supported", settings_format[i].nvs_type, settings_format[i].name);
557-
return false;
558+
ESP_LOGW(TAG, "NVS type (%d) for '%s' not supported", settings[i].nvs_type, settings[i].name);
559+
result = false;
560+
break;
558561
}
562+
563+
// check value range
564+
if (NVS_TYPE_STR != settings[i].nvs_type) {
565+
if ((settings[i].min > item->valueint) || (settings[i].max < item->valueint)) {
566+
ESP_LOGW(TAG, "Value '%d' for '%s' is out of range (%d-%d)", item->valueint, settings[i].name, settings[i].min, settings[i].max);
567+
result = false;
568+
}
569+
}
570+
571+
// mark for update
572+
settings[i].int_value = item->valueint;
573+
settings[i].updated = true;
559574
} else {
560-
ESP_LOGW(TAG, "Expected JSON type (%d) for setting '%s'", settings_format[i].json_type, settings_format[i].name);
561-
return false;
575+
ESP_LOGW(TAG, "Expected JSON type (%d) for setting '%s'", settings[i].json_type, settings[i].name);
576+
result = false;
577+
}
578+
}
579+
}
580+
581+
// check individual values
582+
if (result) {
583+
for (int i = 0; i < ARRAY_SIZE(settings); i++) {
584+
if (settings[i].updated) {
585+
if (strcmp(settings[i].name, "display") == 0) {
586+
if (NULL == get_display_config(settings[i].str_value)) {
587+
ESP_LOGW(TAG, "Display config '%s' for '%s' is not available", settings[i].str_value, settings[i].name);
588+
result = false;
589+
}
590+
break;
591+
}
592+
}
593+
}
594+
}
595+
596+
// update NVS (if result is okay) clean up
597+
for (int i = 0; i < ARRAY_SIZE(settings); i++) {
598+
if (settings[i].updated) {
599+
if (result) {
600+
switch (settings[i].nvs_type) {
601+
case NVS_TYPE_U8:
602+
nvs_config_set_u16(settings[i].nvs_name, (uint16_t)settings[i].int_value); // nvs u8 is not used
603+
break;
604+
case NVS_TYPE_U16:
605+
nvs_config_set_u16(settings[i].nvs_name, (uint16_t)settings[i].int_value);
606+
break;
607+
case NVS_TYPE_U32:
608+
nvs_config_set_u64(settings[i].nvs_name, (uint64_t)settings[i].int_value); // nvs u32 is not used
609+
break;
610+
case NVS_TYPE_I8:
611+
nvs_config_set_i32(settings[i].nvs_name, settings[i].int_value); // nvs i8 is not used
612+
break;
613+
case NVS_TYPE_I16:
614+
nvs_config_set_i32(settings[i].nvs_name, settings[i].int_value); // nvs i16 is not used
615+
break;
616+
case NVS_TYPE_I32:
617+
nvs_config_set_i32(settings[i].nvs_name, settings[i].int_value);
618+
break;
619+
case NVS_TYPE_STR:
620+
nvs_config_set_string(settings[i].nvs_name, settings[i].str_value);
621+
break;
622+
default:
623+
break;
624+
}
625+
}
626+
627+
if (NVS_TYPE_STR == settings[i].nvs_type) {
628+
free(settings[i].str_value);
562629
}
563630
}
564631
}
565632

566-
return true;
633+
return result;
567634
}
568635

569636
static esp_err_t PATCH_update_settings(httpd_req_t * req)
570637
{
571-
572638
if (is_network_allowed(req) != ESP_OK) {
573639
return httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Unauthorized");
574640
}
@@ -605,9 +671,8 @@ static esp_err_t PATCH_update_settings(httpd_req_t * req)
605671
return ESP_OK;
606672
}
607673

608-
if (check_settings_and_update(root, false)) {
609-
check_settings_and_update(root, true);
610-
} else {
674+
if (!check_settings_and_update(root)) {
675+
cJSON_Delete(root);
611676
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Wrong API input");
612677
return ESP_OK;
613678
}

0 commit comments

Comments
 (0)