Skip to content

Commit 27f430c

Browse files
committed
Parse only once with cached values / Add value and range checks / Log all errors
1 parent 8a19510 commit 27f430c

File tree

3 files changed

+172
-78
lines changed

3 files changed

+172
-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

@@ -226,3 +225,13 @@ esp_err_t display_on(bool display_on)
226225

227226
return ESP_OK;
228227
}
228+
229+
const DisplayConfig * get_display_config(const char * name)
230+
{
231+
for (int i = 0 ; i < ARRAY_SIZE(display_configs); i++) {
232+
if (strcmp(display_configs[i].name, name) == 0) {
233+
return &display_configs[i];
234+
}
235+
}
236+
return NULL;
237+
}

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: 153 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,191 @@ 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+
Settings * getUpdatedSettings(const char * name, Settings settings[], uint32_t length)
474+
{
475+
if (name) {
476+
for (int i = 0; i < length; i++) {
477+
if (settings[i].updated && (strcmp(settings[i].name, name) == 0)) {
478+
return &settings[i];
479+
}
480+
}
481+
}
482+
return NULL;
483+
}
484+
485+
bool check_settings_and_update(const cJSON * const root)
466486
{
487+
bool result = true;
467488
const int cJSON_Option = (cJSON_Number | cJSON_True | cJSON_False);
468489

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 = "rotation", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .nvs_name = NVS_CONFIG_ROTATION },
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 }
490+
Settings settings[] = {
491+
{ .name = "stratumURL", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_STRATUM_URL },
492+
{ .name = "fallbackStratumURL", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_URL },
493+
{ .name = "stratumUser", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_STRATUM_USER },
494+
{ .name = "stratumPassword", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_STRATUM_PASS },
495+
{ .name = "fallbackStratumUser", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_USER },
496+
{ .name = "fallbackStratumPassword", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PASS },
497+
{ .name = "stratumPort", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_STRATUM_PORT },
498+
{ .name = "fallbackStratumPort", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_FALLBACK_STRATUM_PORT },
499+
{ .name = "ssid", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 1, .max = 32, .nvs_name = NVS_CONFIG_WIFI_SSID },
500+
{ .name = "wifiPass", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 1, .max = 63, .nvs_name = NVS_CONFIG_WIFI_PASS },
501+
{ .name = "hostname", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 1, .max = 32, .nvs_name = NVS_CONFIG_HOSTNAME },
502+
{ .name = "coreVoltage", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 1, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_ASIC_VOLTAGE },
503+
{ .name = "frequency", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 1, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_ASIC_FREQ },
504+
{ .name = "overheat_mode", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 0, .nvs_name = NVS_CONFIG_OVERHEAT_MODE },
505+
{ .name = "display", .json_type = cJSON_String, .nvs_type = NVS_TYPE_STR, .min = 0, .max = NVS_STR_LIMIT, .nvs_name = NVS_CONFIG_DISPLAY },
506+
{ .name = "rotation", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 270, .nvs_name = NVS_CONFIG_ROTATION },
507+
{ .name = "invertscreen", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 1, .nvs_name = NVS_CONFIG_INVERT_SCREEN },
508+
{ .name = "displayTimeout", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_I32, .min = -1, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_DISPLAY_TIMEOUT },
509+
{ .name = "autofanspeed", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 1, .nvs_name = NVS_CONFIG_AUTO_FAN_SPEED },
510+
{ .name = "fanspeed", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 100, .nvs_name = NVS_CONFIG_FAN_SPEED },
511+
{ .name = "temptarget", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 35, .max = 66, .nvs_name = NVS_CONFIG_TEMP_TARGET },
512+
{ .name = "statsFrequency", .json_type = cJSON_Number, .nvs_type = NVS_TYPE_U16, .min = 0, .max = USHRT_MAX, .nvs_name = NVS_CONFIG_STATISTICS_FREQUENCY },
513+
{ .name = "overclockEnabled", .json_type = cJSON_Option, .nvs_type = NVS_TYPE_U16, .min = 0, .max = 1, .nvs_name = NVS_CONFIG_OVERCLOCK_ENABLED }
493514
};
494515

495-
for (int i = 0; i < ARRAY_SIZE(settings_format); i++) {
496-
cJSON * item = cJSON_GetObjectItem(root, settings_format[i].name);
516+
// check for data type and data type range
517+
for (int i = 0; i < ARRAY_SIZE(settings); i++) {
518+
cJSON * item = cJSON_GetObjectItem(root, settings[i].name);
497519
if (item) {
498-
if (check_json_type(settings_format[i].json_type, item)) {
499-
switch (settings_format[i].nvs_type) {
520+
// check data type
521+
if (check_json_type(settings[i].json_type, item)) {
522+
// check data type range
523+
switch (settings[i].nvs_type) {
500524
case NVS_TYPE_U8:
501525
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
526+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_U8", item->valueint, settings[i].name);
527+
result = false;
507528
}
508529
break;
509530
case NVS_TYPE_U16:
510531
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);
532+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_U16", item->valueint, settings[i].name);
533+
result = false;
516534
}
517535
break;
518536
case NVS_TYPE_U32:
519537
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
538+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_U32", item->valueint, settings[i].name);
539+
result = false;
525540
}
526541
break;
527542
case NVS_TYPE_I8:
528543
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
544+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_I8", item->valueint, settings[i].name);
545+
result = false;
534546
}
535547
break;
536548
case NVS_TYPE_I16:
537549
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
550+
ESP_LOGW(TAG, "Value '%d' for '%s' is not compatible with NVS_TYPE_I16", item->valueint, settings[i].name);
551+
result = false;
543552
}
544553
break;
545554
case NVS_TYPE_I32:
546-
if (update) {
547-
nvs_config_set_i32(settings_format[i].nvs_name, item->valueint);
548-
}
549555
break;
550556
case NVS_TYPE_STR:
551-
if (update) {
552-
nvs_config_set_string(settings_format[i].nvs_name, item->valuestring);
557+
const size_t str_value_len = strlen(item->valuestring);
558+
settings[i].str_value = strdup(item->valuestring);
559+
560+
if (0 > settings[i].min) {
561+
settings[i].min = 0;
562+
}
563+
564+
if ((str_value_len < settings[i].min) || (str_value_len > settings[i].max)) {
565+
ESP_LOGW(TAG, "Value '%s' for '%s' is out of length (%d-%d)", item->valuestring, settings[i].name, settings[i].min, settings[i].max);
566+
result = false;
553567
}
554568
break;
555569
default:
556-
ESP_LOGW(TAG, "NVS type (%d) for '%s' not supported", settings_format[i].nvs_type, settings_format[i].name);
557-
return false;
570+
ESP_LOGW(TAG, "NVS type (%d) for '%s' not supported", settings[i].nvs_type, settings[i].name);
571+
result = false;
572+
break;
558573
}
574+
575+
// check value range
576+
if (NVS_TYPE_STR != settings[i].nvs_type) {
577+
if ((settings[i].min > item->valueint) || (settings[i].max < item->valueint)) {
578+
ESP_LOGW(TAG, "Value '%d' for '%s' is out of range (%d-%d)", item->valueint, settings[i].name, settings[i].min, settings[i].max);
579+
result = false;
580+
}
581+
}
582+
583+
// mark for update
584+
settings[i].int_value = item->valueint;
585+
settings[i].updated = true;
559586
} else {
560-
ESP_LOGW(TAG, "Expected JSON type (%d) for setting '%s'", settings_format[i].json_type, settings_format[i].name);
561-
return false;
587+
ESP_LOGW(TAG, "Expected JSON type (%d) for setting '%s'", settings[i].json_type, settings[i].name);
588+
result = false;
589+
}
590+
}
591+
}
592+
593+
// check individual values
594+
if (result) {
595+
Settings * updatedSettings = getUpdatedSettings("display", settings, ARRAY_SIZE(settings));
596+
if (updatedSettings) {
597+
if (NULL == get_display_config(updatedSettings->str_value)) {
598+
ESP_LOGW(TAG, "Display config '%s' for '%s' is not available", updatedSettings->str_value, updatedSettings->name);
599+
result = false;
600+
}
601+
}
602+
603+
updatedSettings = getUpdatedSettings("rotation", settings, ARRAY_SIZE(settings));
604+
if (updatedSettings) {
605+
switch (updatedSettings->int_value) {
606+
case 0: case 90: case 180: case 270:
607+
break;
608+
default:
609+
ESP_LOGW(TAG, "Value '%d' for '%s' is not possible", updatedSettings->int_value, updatedSettings->name);
610+
result = false;
611+
break;
612+
}
613+
}
614+
}
615+
616+
// update NVS (if result is okay) and clean up
617+
for (int i = 0; i < ARRAY_SIZE(settings); i++) {
618+
if (settings[i].updated) {
619+
if (result) {
620+
switch (settings[i].nvs_type) {
621+
case NVS_TYPE_U8:
622+
nvs_config_set_u16(settings[i].nvs_name, (uint16_t)settings[i].int_value); // nvs u8 is not used
623+
break;
624+
case NVS_TYPE_U16:
625+
nvs_config_set_u16(settings[i].nvs_name, (uint16_t)settings[i].int_value);
626+
break;
627+
case NVS_TYPE_U32:
628+
nvs_config_set_u64(settings[i].nvs_name, (uint64_t)settings[i].int_value); // nvs u32 is not used
629+
break;
630+
case NVS_TYPE_I8:
631+
nvs_config_set_i32(settings[i].nvs_name, settings[i].int_value); // nvs i8 is not used
632+
break;
633+
case NVS_TYPE_I16:
634+
nvs_config_set_i32(settings[i].nvs_name, settings[i].int_value); // nvs i16 is not used
635+
break;
636+
case NVS_TYPE_I32:
637+
nvs_config_set_i32(settings[i].nvs_name, settings[i].int_value);
638+
break;
639+
case NVS_TYPE_STR:
640+
nvs_config_set_string(settings[i].nvs_name, settings[i].str_value);
641+
break;
642+
default:
643+
break;
644+
}
645+
}
646+
647+
if (NVS_TYPE_STR == settings[i].nvs_type) {
648+
free(settings[i].str_value);
562649
}
563650
}
564651
}
565652

566-
return true;
653+
return result;
567654
}
568655

569656
static esp_err_t PATCH_update_settings(httpd_req_t * req)
570657
{
571-
572658
if (is_network_allowed(req) != ESP_OK) {
573659
return httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Unauthorized");
574660
}
@@ -605,9 +691,7 @@ static esp_err_t PATCH_update_settings(httpd_req_t * req)
605691
return ESP_OK;
606692
}
607693

608-
if (check_settings_and_update(root, false)) {
609-
check_settings_and_update(root, true);
610-
} else {
694+
if (!check_settings_and_update(root)) {
611695
cJSON_Delete(root);
612696
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Wrong API input");
613697
return ESP_OK;

0 commit comments

Comments
 (0)