diff --git a/src/charge_mode.cpp b/src/charge_mode.cpp index 1764da0..4ecc842 100644 --- a/src/charge_mode.cpp +++ b/src/charge_mode.cpp @@ -19,6 +19,7 @@ #include "eeprom.h" #include "neopixel_led.h" #include "profile.h" +#include "common.h" uint8_t charge_weight_digits[] = {0, 0, 0, 0, 0}; @@ -476,6 +477,9 @@ bool charge_mode_config_init(void) { } } + // Register to eeprom save all + eeprom_register_handler(charge_mode_config_save); + return true; } @@ -488,20 +492,34 @@ bool charge_mode_config_save(void) { bool http_rest_charge_mode_config(struct fs_file *file, int num_params, char *params[], char *values[]) { + // Mappings + // c1 (str): neopixel_normal_charge_colour + // c2 (str): neopixel_under_charge_colour + // c3 (str): neopixel_over_charge_colour + // c4 (str): neopixel_not_ready_colour + + // c5 (float): coarse_stop_threshold + // c6 (float): fine_stop_threshold + // c7 (float): set_point_sd_margin + // c8 (float): set_point_mean_margin + + // ee (bool): save to eeprom + static char charge_mode_json_buffer[256]; + bool save_to_eeprom = false; // Control for (int idx = 0; idx < num_params; idx += 1) { - if (strcmp(params[idx], "c_stop") == 0) { + if (strcmp(params[idx], "c5") == 0) { charge_mode_config.eeprom_charge_mode_data.coarse_stop_threshold = strtof(values[idx], NULL); } - else if (strcmp(params[idx], "f_stop") == 0) { + else if (strcmp(params[idx], "c6") == 0) { charge_mode_config.eeprom_charge_mode_data.fine_stop_threshold = strtof(values[idx], NULL); } - else if (strcmp(params[idx], "sp_sd") == 0) { + else if (strcmp(params[idx], "c7") == 0) { charge_mode_config.eeprom_charge_mode_data.set_point_sd_margin = strtof(values[idx], NULL); } - else if (strcmp(params[idx], "sp_avg") == 0) { + else if (strcmp(params[idx], "c8") == 0) { charge_mode_config.eeprom_charge_mode_data.set_point_mean_margin = strtof(values[idx], NULL); } @@ -518,22 +536,30 @@ bool http_rest_charge_mode_config(struct fs_file *file, int num_params, char *pa else if (strcmp(params[idx], "c4") == 0) { charge_mode_config.eeprom_charge_mode_data.neopixel_not_ready_colour = hex_string_to_decimal(values[idx]); } + else if (strcmp(params[idx], "ee") == 0) { + save_to_eeprom = string_to_boolean(values[idx]); + } + } + + // Perform action + if (save_to_eeprom) { + charge_mode_config_save(); } // Response snprintf(charge_mode_json_buffer, sizeof(charge_mode_json_buffer), - "{\"c_stop\":%.3f,\"f_stop\":%.3f,\"sp_sd\":%.3f,\"sp_avg\":%.3f," - "\"c1\":\"#%06x\",\"c2\":\"#%06x\",\"c3\":\"#%06x\",\"c4\":\"#%06x\"}", - charge_mode_config.eeprom_charge_mode_data.coarse_stop_threshold, - charge_mode_config.eeprom_charge_mode_data.fine_stop_threshold, - charge_mode_config.eeprom_charge_mode_data.set_point_sd_margin, - charge_mode_config.eeprom_charge_mode_data.set_point_mean_margin, - + "{\"c1\":\"#%06x\",\"c2\":\"#%06x\",\"c3\":\"#%06x\",\"c4\":\"#%06x\"," + "\"c5\":%.3f,\"c6\":%.3f,\"c7\":%.3f,\"c8\":%.3f}", charge_mode_config.eeprom_charge_mode_data.neopixel_normal_charge_colour, charge_mode_config.eeprom_charge_mode_data.neopixel_under_charge_colour, charge_mode_config.eeprom_charge_mode_data.neopixel_over_charge_colour, - charge_mode_config.eeprom_charge_mode_data.neopixel_not_ready_colour); + charge_mode_config.eeprom_charge_mode_data.neopixel_not_ready_colour, + + charge_mode_config.eeprom_charge_mode_data.coarse_stop_threshold, + charge_mode_config.eeprom_charge_mode_data.fine_stop_threshold, + charge_mode_config.eeprom_charge_mode_data.set_point_sd_margin, + charge_mode_config.eeprom_charge_mode_data.set_point_mean_margin); size_t data_length = strlen(charge_mode_json_buffer); file->data = charge_mode_json_buffer; diff --git a/src/common.c b/src/common.c index b08718b..19f1d46 100644 --- a/src/common.c +++ b/src/common.c @@ -1,5 +1,6 @@ #include #include +#include #include "common.h" #include "pico/time.h" @@ -16,6 +17,16 @@ void delay_ms(uint32_t ms, BaseType_t scheduler_state) { const char * true_string = "true"; const char * false_string = "false"; -const char * boolean_string(bool var) { +const char * boolean_to_string(bool var) { return var ? true_string : false_string; +} + +bool string_to_boolean(char * s) { + bool var = false; + + if (strcmp(s, true_string) == 0) { + var = true; + } + + return var; } \ No newline at end of file diff --git a/src/common.h b/src/common.h index 7e4d992..ca30693 100644 --- a/src/common.h +++ b/src/common.h @@ -15,7 +15,8 @@ extern "C" { */ void delay_ms(uint32_t ms, BaseType_t scheduler_state); -const char * boolean_string(bool var); +const char * boolean_to_string(bool var); +bool string_to_boolean(char * s); #ifdef __cplusplus diff --git a/src/eeprom.c b/src/eeprom.c index 81fa679..efd3f66 100644 --- a/src/eeprom.c +++ b/src/eeprom.c @@ -28,8 +28,16 @@ extern void cat24c256_eeprom_init(); extern bool cat24c256_write(uint16_t data_addr, uint8_t * data, size_t len); extern bool cat24c256_read(uint16_t data_addr, uint8_t * data, size_t len); +// Linked list implementation +typedef struct _eeprom_save_handler_node { + eeprom_save_handler_t function_handler; + struct _eeprom_save_handler_node * next; +} _eeprom_save_handler_node_t; + +// Singleton variables SemaphoreHandle_t eeprom_access_mutex = NULL; eeprom_metadata_t metadata; +static _eeprom_save_handler_node_t * eeprom_save_handler_head = NULL; uint32_t rnd(void){ @@ -39,23 +47,29 @@ uint32_t rnd(void){ for(k=0;k<32;k++){ random = random << 1; - random=random + (0x00000001 & (*rnd_reg)); + random = random + (0x00000001 & (*rnd_reg)); } return random; } +void eeprom_register_handler(eeprom_save_handler_t handler) { + _eeprom_save_handler_node_t * new_node = malloc(sizeof(_eeprom_save_handler_node_t)); + new_node->function_handler = handler; + + // Append to the head + new_node->next = eeprom_save_handler_head; + eeprom_save_handler_head = new_node; +} + uint8_t eeprom_save_all() { - eeprom_config_save(); - scale_config_save(); - motor_config_save(); - charge_mode_config_save(); - wireless_config_save(); - neopixel_led_config_save(); - button_config_save(); - profile_data_save(); + // Iterate over all registered handlers and run the save functions + for (_eeprom_save_handler_node_t * node = eeprom_save_handler_head; node != NULL; node = node->next) { + // Run the save handler + node->function_handler(); + } return 37; // Configuration Menu ID } @@ -107,6 +121,9 @@ bool eeprom_init(void) { } } + // Register to eeprom save all + eeprom_register_handler(eeprom_config_save); + return is_ok; } @@ -169,59 +186,55 @@ bool eeprom_get_board_id(char ** board_id_buffer, size_t bytes_to_copy) { bool http_rest_system_control(struct fs_file *file, int num_params, char *params[], char *values[]) { + // Mappings + // s0 (str): unique_id + // s1 (str): version_string + // s2 (str): vcs_hash + // s3 (str): build_type + // s4 (bool): save_to_eeprom + // s5 (bool): software_reset + // s6 (bool): erase_eeprom static char eeprom_config_json_buffer[256]; - const char * save_to_eeprom_string; const char * software_reset_string; - const char * erase_eeprom_string; bool save_to_eeprom_flag = false; bool software_reset_flag = false; bool erase_eeprom_flag = false; + // Control for (int idx = 0; idx < num_params; idx += 1) { - if (strcmp(params[idx], "save_to_eeprom") == 0 && strcmp(values[idx], "true") == 0) { - save_to_eeprom_flag = true; + if (strcmp(params[idx], "s4") == 0) { + save_to_eeprom_flag = string_to_boolean(values[idx]); } - else if (strcmp(params[idx], "software_reset") == 0 && strcmp(values[idx], "true") == 0) { - software_reset_flag = true; + else if (strcmp(params[idx], "s5") == 0) { + software_reset_flag = string_to_boolean(values[idx]); } - else if (strcmp(params[idx], "erase_eeprom") == 0 && strcmp(values[idx], "true") == 0) { - erase_eeprom_flag = true; + else if (strcmp(params[idx], "s6") == 0) { + erase_eeprom_flag = string_to_boolean(values[idx]); } } if (save_to_eeprom_flag) { eeprom_save_all(); - save_to_eeprom_string = "true"; - } - else { - save_to_eeprom_string = "false"; } if (erase_eeprom_flag) { eeprom_erase(software_reset_flag); - erase_eeprom_string = "true"; - } - else { - erase_eeprom_string = "false"; } if (software_reset_flag) { software_reboot(); - software_reset_string = "true"; - } - else { - software_reset_string = "false"; } - - + // Response snprintf(eeprom_config_json_buffer, sizeof(eeprom_config_json_buffer), - "{\"unique_id\":\"%s\",\"save_to_eeprom\":%s,\"software_reset\":%s,\"erase_eeprom\":%s,\"ver\":\"%s\",\"hash\":\"%s\",\"build_type\":\"%s\"}", - metadata.unique_id, save_to_eeprom_string, software_reset_string, erase_eeprom_string, - version_string, vcs_hash, build_type); + "{\"s0\":\"%s\",\"s1\":\"%s\",\"s2\":\"%s\",\"s3\":\"%s\",\"s4\":%s,\"s5\":%s,\"s6\":%s}", + metadata.unique_id, version_string, vcs_hash, build_type, + boolean_to_string(save_to_eeprom_flag), + boolean_to_string(erase_eeprom_flag), + boolean_to_string(software_reset_flag)); size_t data_length = strlen(eeprom_config_json_buffer); file->data = eeprom_config_json_buffer; diff --git a/src/eeprom.h b/src/eeprom.h index 22f97d6..8bd5f09 100644 --- a/src/eeprom.h +++ b/src/eeprom.h @@ -24,6 +24,9 @@ typedef struct { char unique_id[8]; } __attribute__((packed)) eeprom_metadata_t; +// EEPROM save handler function +typedef bool (*eeprom_save_handler_t)(void); + #ifdef __cplusplus extern "C" { @@ -41,6 +44,7 @@ bool eeprom_get_board_id(char ** board_id_buffer, size_t bytes_to_copy); */ uint8_t eeprom_erase(bool); uint8_t eeprom_save_all(void); +void eeprom_register_handler(eeprom_save_handler_t handler); bool http_rest_system_control(struct fs_file *file, int num_params, char *params[], char *values[]); diff --git a/src/html/dashboard.html b/src/html/dashboard.html index 0e0c193..27df216 100644 --- a/src/html/dashboard.html +++ b/src/html/dashboard.html @@ -46,15 +46,15 @@

OpenTrickler

@@ -192,23 +192,23 @@

Control

- - + +
- - + + +
- +
@@ -220,7 +220,7 @@

Control

- + Coarse Trickler Stop Threshold: +
- - Fine Trickler Stop Threshold: +
- - + +
- - + +
@@ -398,7 +398,7 @@

Profile Database

- +
@@ -410,34 +410,40 @@

Profile Database

- - + +
- - + +
- - + + + +
- - +
+ +
+ +
- +
@@ -518,7 +524,8 @@

Profile Database

- + + @@ -599,7 +606,7 @@

Profile Database

- + @@ -626,7 +633,7 @@

Profile Database

- + @@ -639,14 +646,14 @@

Profile Database

- -
- +
@@ -658,44 +665,45 @@

Profile Database

- + - +
- + - +
- + - +
- + - +
- -
- - @@ -703,17 +711,35 @@

Profile Database

Warning - -
- - +
+ + +
@@ -753,31 +779,6 @@

Profile Database

}); }); - const configForms = document.querySelectorAll('.config-form'); - configForms.forEach(form => { - form.addEventListener('submit', (event) => { - event.preventDefault(); - const targetForm = event.currentTarget; - const paramData = new FormData(targetForm); - - // Remove empty param - for (const [key, value] of paramData.entries()) { - if (value == "") { - paramData.delete(key); - } - } - - const queryString = new URLSearchParams(paramData).toString(); - const url = new URL(targetForm.action + '?'); - url.search = queryString; - - // Post the new param with GET method - getRestJson(url.toString()).then( - // TODO: Check for error - ); - }); - }); - async function getRestJson(url) { const response = await fetch(url); const jsonData = await response.json(); @@ -833,6 +834,92 @@

Profile Database

); } + function putForm(targetForm, save_to_eeprom) { + const paramData = new FormData(targetForm); + + // Remove empty param + for (const [key, value] of paramData.entries()) { + if (value == "") { + paramData.delete(key); + } + } + + if (save_to_eeprom) { + paramData.append('ee', true) + } + + const queryString = new URLSearchParams(paramData).toString(); + const url = new URL(targetForm.action + '?'); + url.search = queryString; + + // // Post the new param with GET method + getRestJson(url.toString()).then( + // TODO: Check for error + ); + } + + const saveToEepromDialogModal = document.getElementById('saveToEepromDialog') + saveToEepromDialogModal.addEventListener('show.bs.modal', event => { + // Example: https://getbootstrap.com/docs/5.2/components/modal/#varying-modal-content + // Button that triggered the modal + const button = event.relatedTarget; + + // Update title + const modalTitle = saveToEepromDialogModal.querySelector('.modal-title'); + modalTitle.innerHTML = button.innerText; + + // Trigger push + const targetForm = button.closest('form'); + + // Find function to the button + const apply_button = saveToEepromDialogModal.querySelector('#apply'); + const save_to_eeprom_button = saveToEepromDialogModal.querySelector('#save_to_eeprom'); + + apply_button.onclick = function() { + putForm(targetForm, false); + } + + save_to_eeprom_button.onclick = function() { + putForm(targetForm, true); + } + + }) + + + const systemControlDialogModal = document.getElementById('systemControlDialog') + systemControlDialogModal.addEventListener('show.bs.modal', event => { + // Example: https://getbootstrap.com/docs/5.2/components/modal/#varying-modal-content + // Button that triggered the modal + const button = event.relatedTarget; + const targetForm = button.closest('form'); + const modalBody = systemControlDialogModal.querySelector('.modal-body'); + + var formData = new FormData(targetForm); + + // Form the content string + let bodyText = '

Pending Actions

    '; + if (formData.get("s4") == 'true') { + bodyText += "
  • Save all settings to EEPROM
  • "; + } + if (formData.get("s5") == 'true') { + bodyText += "
  • Reboot the OpenTrickler
  • "; + } + if (formData.get("s6") == 'true') { + bodyText += "
  • Erase the EEPROM. You cannot undo this action!
  • "; + } + + bodyText += "
" + + modalBody.innerHTML = bodyText; + + // Find function to the button + const confirm_button = systemControlDialogModal.querySelector('#confirm'); + + confirm_button.onclick = function() { + putForm(targetForm, false); + } + }) + diff --git a/src/motors.c b/src/motors.c index ae58d35..2b3060e 100644 --- a/src/motors.c +++ b/src/motors.c @@ -337,6 +337,9 @@ bool motor_config_init(void) { coarse_trickler_motor_config.step_direction = coarse_trickler_motor_config.persistent_config.inverted_direction ? true : false; fine_trickler_motor_config.step_direction = fine_trickler_motor_config.persistent_config.inverted_direction ? true : false; + // Register to eeprom save all + eeprom_register_handler(motor_config_save); + return is_ok; } @@ -616,16 +619,17 @@ const char * get_motor_select_string(motor_select_t selected_motor) { void populate_rest_motor_config(motor_config_t * motor_config, char * buf, size_t max_len) { // Mappings: - // m0: angular_acceleration - // m1: full_steps_per_rotation - // m2: current_ma - // m3: microsteps - // m4: max_speed_rps - // m5: r_sense - // m6: min_speed_rps - // m7: gear_ratio - // m8: inverted_enable - // m9: inverted_direction + // m0 (float): angular_acceleration + // m1 (int): full_steps_per_rotation + // m2 (int): current_ma + // m3 (int): microsteps + // m4 (int): max_speed_rps + // m5 (int): r_sense + // m6 (float): min_speed_rps + // m7 (float): gear_ratio + // m8 (bool): inverted_enable + // m9 (bool): inverted_direction + // ee (bool): save to eeprom // Build response snprintf(buf, @@ -639,11 +643,13 @@ void populate_rest_motor_config(motor_config_t * motor_config, char * buf, size_ motor_config->persistent_config.r_sense, motor_config->persistent_config.min_speed_rps, motor_config->persistent_config.gear_ratio, - boolean_string(motor_config->persistent_config.inverted_enable), - boolean_string(motor_config->persistent_config.inverted_direction)); + boolean_to_string(motor_config->persistent_config.inverted_enable), + boolean_to_string(motor_config->persistent_config.inverted_direction)); } void apply_rest_motor_config(motor_config_t * motor_config, int num_params, char *params[], char *values[]) { + bool save_to_eeprom = false; + for (int idx = 0; idx < num_params; idx += 1) { if (strcmp(params[idx], "m0") == 0) { float angular_acceleration = strtof(values[idx], NULL); @@ -678,22 +684,22 @@ void apply_rest_motor_config(motor_config_t * motor_config, int num_params, char motor_config->persistent_config.gear_ratio = gear_ratio; } else if (strcmp(params[idx], "m8") == 0) { - if (strcmp(values[idx], "true") == 0) { - motor_config->persistent_config.inverted_enable = true; - } - else if (strcmp(values[idx], "false") == 0) { - motor_config->persistent_config.inverted_enable = false; - } + bool inverted_enable = string_to_boolean(values[idx]); + motor_config->persistent_config.inverted_enable = inverted_enable; } else if (strcmp(params[idx], "m9") == 0) { - if (strcmp(values[idx], "true") == 0) { - motor_config->persistent_config.inverted_direction = true; - } - else if (strcmp(values[idx], "false") == 0) { - motor_config->persistent_config.inverted_direction = false; - } + bool inverted_direction = string_to_boolean(values[idx]); + motor_config->persistent_config.inverted_direction = inverted_direction; + } + else if (strcmp(params[idx], "ee") == 0) { + save_to_eeprom = string_to_boolean(values[idx]); } } + + // Perform action + if (save_to_eeprom) { + motor_config_save(); // Note: this will save settings for both + } } diff --git a/src/neopixel_led.c b/src/neopixel_led.c index 3f4f3c1..90c4c3b 100644 --- a/src/neopixel_led.c +++ b/src/neopixel_led.c @@ -29,7 +29,7 @@ #include "generated/ws2812.pio.h" #include "configuration.h" #include "eeprom.h" - +#include "common.h" typedef struct { @@ -177,6 +177,9 @@ bool neopixel_led_init(void) { 2, &neopixel_led_config.neopixel_control_task_handler); + // Register to eeprom save all + eeprom_register_handler(neopixel_led_config_save); + return true; } @@ -201,7 +204,14 @@ uint32_t hex_string_to_decimal(char * string) { bool http_rest_neopixel_led_config(struct fs_file *file, int num_params, char *params[], char *values[]) { + // Mappings: + // bl (str): mini12864_backlight_colour + // l1 (str): led1_colour + // l2 (str): led2_colour + // ee (bool): save to eeprom + static char neopixel_config_json_buffer[128]; + bool save_to_eeprom = false; // Control for (int idx = 0; idx < num_params; idx += 1) { @@ -215,6 +225,14 @@ bool http_rest_neopixel_led_config(struct fs_file *file, int num_params, char *p else if (strcmp(params[idx], "l2") == 0) { neopixel_led_config.eeprom_neopixel_led_metadata.default_led_colours.led2_colour = hex_string_to_decimal(values[idx]); } + else if (strcmp(params[idx], "ee") == 0) { + save_to_eeprom = string_to_boolean(values[idx]); + } + } + + // Perform action + if (save_to_eeprom) { + neopixel_led_config_save(); } // Response diff --git a/src/profile.c b/src/profile.c index c6bb0bd..c7f35ca 100644 --- a/src/profile.c +++ b/src/profile.c @@ -2,6 +2,7 @@ #include "profile.h" #include "eeprom.h" +#include "common.h" eeprom_profile_data_t profile_data; @@ -103,6 +104,9 @@ bool profile_data_init() { profile_data_save(); } + // Register to eeprom save all + eeprom_register_handler(profile_data_save); + return true; } @@ -144,6 +148,7 @@ bool http_rest_profile_config(struct fs_file *file, int num_params, char *params // p10 (float): fine_kd // p11 (float): fine_min_flow_speed_rps // p12 (float): fine_max_flow_speed_rps + // ee (bool): save to eeprom static char buf[256]; // Read the current loaded profile index @@ -162,6 +167,7 @@ bool http_rest_profile_config(struct fs_file *file, int num_params, char *params else { profile_t * current_profile = profile_select(profile_idx); + bool save_to_eeprom = false; // Control for (int idx = 0; idx < num_params; idx += 1) { @@ -204,6 +210,14 @@ bool http_rest_profile_config(struct fs_file *file, int num_params, char *params else if (strcmp(params[idx], "p12") == 0) { current_profile->fine_max_flow_speed_rps = strtof(values[idx], NULL); } + else if (strcmp(params[idx], "ee") == 0) { + save_to_eeprom = string_to_boolean(values[idx]); + } + } + + // Perform action + if (save_to_eeprom) { + profile_data_save(); } // Response diff --git a/src/rotary_button.cpp b/src/rotary_button.cpp index a152c42..4cc284d 100644 --- a/src/rotary_button.cpp +++ b/src/rotary_button.cpp @@ -213,6 +213,9 @@ bool button_init() { assert(false); } + // Register to eeprom save all + eeprom_register_handler(button_config_save); + printf("done\n"); return true; @@ -290,24 +293,32 @@ bool http_rest_button_control(struct fs_file *file, int num_params, char *params bool http_rest_button_config(struct fs_file *file, int num_params, char *params[], char *values[]) { + // Mappings: + // b0 (bool): inverted_encoder_direction + // ee (bool): save to eeprom static char buf[128]; + bool save_to_eeprom = false; // Control for (int idx = 0; idx < num_params; idx += 1) { - if (strcmp(params[idx], "inv_dir") == 0) { - if (strcmp(values[idx], "true") == 0){ - rotary_button_config.inverted_encoder_direction = true; - } - else if (strcmp(values[idx], "false") == 0) { - rotary_button_config.inverted_encoder_direction = false; - } + if (strcmp(params[idx], "b0") == 0) { + bool inverted_encoder_direction = string_to_boolean(values[idx]); + rotary_button_config.inverted_encoder_direction = inverted_encoder_direction; } + else if (strcmp(params[idx], "ee") == 0) { + save_to_eeprom = string_to_boolean(values[idx]); + } + } + + // Perform action + if (save_to_eeprom) { + button_config_save(); } // Response snprintf(buf, sizeof(buf), - "{\"inv_dir\":%s}", - boolean_string(rotary_button_config.inverted_encoder_direction)); + "{\"b0\":%s}", + boolean_to_string(rotary_button_config.inverted_encoder_direction)); size_t response_len = strlen(buf); file->data = buf; diff --git a/src/scale.c b/src/scale.c index 056dd4e..dae605c 100644 --- a/src/scale.c +++ b/src/scale.c @@ -10,6 +10,7 @@ #include "eeprom.h" #include "app.h" #include "scale.h" +#include "common.h" extern scale_handle_t and_fxi_scale_handle; extern scale_handle_t steinberg_scale_handle; @@ -124,6 +125,9 @@ bool scale_init() { // Create the Task for the listener loop xTaskCreate(scale_config.scale_handle->read_loop_task, "Scale Task", configMINIMAL_STACK_SIZE, NULL, 9, NULL); + // Register to eeprom save all + eeprom_register_handler(scale_config_save); + return is_ok; } @@ -160,39 +164,39 @@ void scale_write(char * command, size_t len) { bool http_rest_scale_config(struct fs_file *file, int num_params, char *params[], char *values[]) { + // Mappings: + // s0 (int): driver index + // s1 (int): baud rate index + // ee (bool): save to eeprom + static char scale_config_to_json_buffer[256]; + bool save_to_eeprom = false; // Set value for (int idx = 0; idx < num_params; idx += 1) { - if (strcmp(params[idx], "driver") == 0) { - if (strcmp(values[idx], "AND FX-i Std") == 0) { - set_scale_driver(SCALE_DRIVER_AND_FXI); - } - else if (strcmp(values[idx], "Steinberg SBS") == 0) { - set_scale_driver(SCALE_DRIVER_STEINBERG_SBS); - } + if (strcmp(params[idx], "s0") == 0) { + scale_driver_t driver_idx = (scale_driver_t) atoi(values[idx]); + set_scale_driver(driver_idx); } - else if (strcmp(params[idx], "baudrate") == 0) { - if (strcmp(values[idx], "4800") == 0) { - scale_config.persistent_config.scale_baudrate = BAUDRATE_4800; - } - else if (strcmp(values[idx], "9600") == 0) { - scale_config.persistent_config.scale_baudrate = BAUDRATE_9600; - } - else if (strcmp(values[idx], "19200") == 0) { - scale_config.persistent_config.scale_baudrate = BAUDRATE_19200; - } + else if (strcmp(params[idx], "s1") == 0) { + scale_baudrate_t baudrate_idx = (scale_baudrate_t) atoi(values[idx]); + scale_config.persistent_config.scale_baudrate = baudrate_idx; + } + else if (strcmp(params[idx], "ee") == 0) { + save_to_eeprom = string_to_boolean(values[idx]); } } - // Convert config to string - const char * scale_driver_string = get_scale_driver_string(); + // Perform action + if (save_to_eeprom) { + scale_config_save(); + } snprintf(scale_config_to_json_buffer, sizeof(scale_config_to_json_buffer), - "{\"driver\":\"%s\",\"baudrate\":%"PRId32"}", - scale_driver_string, - get_scale_baudrate(scale_config.persistent_config.scale_baudrate)); + "{\"s0\":\"%d\",\"s1\":%d}", + scale_config.persistent_config.scale_driver, + scale_config.persistent_config.scale_baudrate); size_t data_length = strlen(scale_config_to_json_buffer); file->data = scale_config_to_json_buffer; diff --git a/src/scale.h b/src/scale.h index a78f619..40c29ed 100644 --- a/src/scale.h +++ b/src/scale.h @@ -20,15 +20,15 @@ typedef struct { typedef enum { - BAUDRATE_4800, - BAUDRATE_9600, - BAUDRATE_19200, + BAUDRATE_4800 = 0, + BAUDRATE_9600 = 1, + BAUDRATE_19200 = 2, } scale_baudrate_t; typedef enum { SCALE_DRIVER_AND_FXI = 0, - SCALE_DRIVER_STEINBERG_SBS, + SCALE_DRIVER_STEINBERG_SBS = 1, } scale_driver_t; diff --git a/src/wireless.c b/src/wireless.c index 7800265..8e417dd 100644 --- a/src/wireless.c +++ b/src/wireless.c @@ -18,6 +18,7 @@ #undef CYW43_HOST_NAME #endif +// Overwrite the host name #define CYW43_HOST_NAME "OpenTrickler" #define LED_INTERFACE_MINIMUM_POLL_PERIOD_MS 20 @@ -155,7 +156,7 @@ bool wireless_init() { // If the revision doesn't match then re-initialize the config if (wireless_config.eeprom_wireless_metadata.wireless_data_rev != EEPROM_WIRELESS_CONFIG_METADATA_REV) { wireless_config.eeprom_wireless_metadata.wireless_data_rev = EEPROM_WIRELESS_CONFIG_METADATA_REV; - wireless_config.eeprom_wireless_metadata.configured = false; + wireless_config.eeprom_wireless_metadata.enable = false; wireless_config.eeprom_wireless_metadata.timeout_ms = 30000; // 30s // Write data back @@ -169,6 +170,9 @@ bool wireless_init() { // Create Wireless handler task xTaskCreate(wireless_task, "Wireless Task", 512, NULL, 3, NULL); + // Register to eeprom save all + eeprom_register_handler(wireless_config_save); + return is_ok; } @@ -178,6 +182,31 @@ bool wireless_config_save() { return is_ok; } + +uint32_t get_cyw43_auth(cyw43_auth_t auth) { + uint32_t cyw43_auth = 0; + + switch (auth) { + case AUTH_OPEN: + cyw43_auth = CYW43_AUTH_OPEN; + break; + case AUTH_WPA_TKIP_PSK: + cyw43_auth = CYW43_AUTH_WPA_TKIP_PSK; + break; + case AUTH_WPA2_AES_PSK: + cyw43_auth = CYW43_AUTH_WPA2_AES_PSK; + break; + case AUTH_WPA2_MIXED_PSK: + cyw43_auth = CYW43_AUTH_WPA2_MIXED_PSK; + break; + default: + break; + } + + return cyw43_auth; +} + + void led_interface_task(void *p) { wireless_ctrl_t wireless_ctrl; uint32_t blink_interval_ms = 0; @@ -255,7 +284,7 @@ void wireless_task(void *p) { } // Start default initialize pattern - if (wireless_config.eeprom_wireless_metadata.configured) { + if (wireless_config.eeprom_wireless_metadata.enable) { wireless_config.current_wireless_state = WIRELESS_STATE_STA_MODE_INIT; cyw43_arch_enable_sta_mode(); @@ -268,7 +297,7 @@ void wireless_task(void *p) { int resp; resp = cyw43_arch_wifi_connect_timeout_ms(wireless_config.eeprom_wireless_metadata.ssid, wireless_config.eeprom_wireless_metadata.pw, - wireless_config.eeprom_wireless_metadata.auth, + get_cyw43_auth(wireless_config.eeprom_wireless_metadata.auth), wireless_config.eeprom_wireless_metadata.timeout_ms); if (resp == PICO_OK) { wireless_config.current_wireless_state = WIRELESS_STATE_STA_MODE_LISTEN; @@ -351,71 +380,56 @@ uint8_t wireless_view_wifi_info(void) { bool http_rest_wireless_config(struct fs_file *file, int num_params, char *params[], char *values[]) { + // Mapping + // w0 (str): ssid + // w1 (str): pw + // w2 (int): auth + // w3 (int): timeout_ms + // w4 (bool): enable + // ee (bool): save to eeprom + static char wireless_config_json_buffer[256]; + bool save_to_eeprom = false; // If the argument includes control, then update the settings for (int idx = 0; idx < num_params; idx += 1) { - if (strcmp(params[idx], "ssid") == 0) { + if (strcmp(params[idx], "w0") == 0) { strncpy(wireless_config.eeprom_wireless_metadata.ssid, values[idx], sizeof(wireless_config.eeprom_wireless_metadata.ssid)); } - - if (strcmp(params[idx], "pw") == 0) { + else if (strcmp(params[idx], "w1") == 0) { strncpy(wireless_config.eeprom_wireless_metadata.pw, values[idx], sizeof(wireless_config.eeprom_wireless_metadata.pw)); } - - if (strcmp(params[idx], "auth") == 0) { - if (strcmp(values[idx], "CYW43_AUTH_OPEN") == 0) { - wireless_config.eeprom_wireless_metadata.auth = CYW43_AUTH_OPEN; - } - else if (strcmp(values[idx], "CYW43_AUTH_WPA_TKIP_PSK") == 0) { - wireless_config.eeprom_wireless_metadata.auth = CYW43_AUTH_WPA_TKIP_PSK; - } - else if (strcmp(values[idx], "CYW43_AUTH_WPA2_AES_PSK") == 0) { - wireless_config.eeprom_wireless_metadata.auth = CYW43_AUTH_WPA2_AES_PSK; - } - else if (strcmp(values[idx], "CYW43_AUTH_WPA2_MIXED_PSK") == 0) { - wireless_config.eeprom_wireless_metadata.auth = CYW43_AUTH_WPA2_MIXED_PSK; - } + else if (strcmp(params[idx], "w2") == 0) { + cyw43_auth_t auth = (cyw43_auth_t) atoi(values[idx]); + wireless_config.eeprom_wireless_metadata.auth = auth; } - - if (strcmp(params[idx], "timeout_ms") == 0) { + else if (strcmp(params[idx], "w3") == 0) { int timeout_ms = (uint16_t) atoi(values[idx]); wireless_config.eeprom_wireless_metadata.timeout_ms = timeout_ms; } - - if (strcmp(params[idx], "configured") == 0 && strcmp(values[idx], "true") == 0) { - wireless_config.eeprom_wireless_metadata.configured = true; + else if (strcmp(params[idx], "w4") == 0) { + bool enable = string_to_boolean(values[idx]); + wireless_config.eeprom_wireless_metadata.enable = enable; + } + else if (strcmp(params[idx], "ee") == 0) { + save_to_eeprom = string_to_boolean(values[idx]); } } - // Response - const char * auth_string; - switch (wireless_config.eeprom_wireless_metadata.auth) { - case CYW43_AUTH_OPEN: - auth_string = "CYW43_AUTH_OPEN"; - break; - case CYW43_AUTH_WPA_TKIP_PSK: - auth_string = "CYW43_AUTH_WPA_TKIP_PSK"; - break; - case CYW43_AUTH_WPA2_AES_PSK: - auth_string = "CYW43_AUTH_WPA2_AES_PSK"; - break; - case CYW43_AUTH_WPA2_MIXED_PSK: - auth_string = "CYW43_AUTH_WPA2_MIXED_PSK"; - break; - default: - auth_string = "error"; - break; + // Perform action + if (save_to_eeprom) { + wireless_config_save(); } + // Response snprintf(wireless_config_json_buffer, sizeof(wireless_config_json_buffer), - "{\"ssid\":\"%s\",\"pw\":\"%s\",\"auth\":\"%s\",\"timeout_ms\":%d,\"configured\":%s}", + "{\"w0\":\"%s\",\"w1\":\"%s\",\"w2\":\"%d\",\"w3\":%"PRId32",\"w4\":%s}", wireless_config.eeprom_wireless_metadata.ssid, wireless_config.eeprom_wireless_metadata.pw, - auth_string, + wireless_config.eeprom_wireless_metadata.auth, wireless_config.eeprom_wireless_metadata.timeout_ms, - boolean_string(wireless_config.eeprom_wireless_metadata.configured)); + boolean_to_string(wireless_config.eeprom_wireless_metadata.enable)); size_t data_length = strlen(wireless_config_json_buffer); file->data = wireless_config_json_buffer; diff --git a/src/wireless.h b/src/wireless.h index be4bb4b..00a4608 100644 --- a/src/wireless.h +++ b/src/wireless.h @@ -4,17 +4,28 @@ #include #include "http_rest.h" -#define EEPROM_WIRELESS_CONFIG_METADATA_REV 1 // 16 byte +#define EEPROM_WIRELESS_CONFIG_METADATA_REV 2 // 16 byte + + +typedef enum { + AUTH_OPEN = 0, + AUTH_WPA_TKIP_PSK = 1, + AUTH_WPA2_AES_PSK = 2, + AUTH_WPA2_MIXED_PSK = 3, +} cyw43_auth_t; typedef struct { uint16_t wireless_data_rev; char ssid[32]; char pw[64]; - uint32_t auth; + cyw43_auth_t auth; uint32_t timeout_ms; - bool configured; -} __attribute__((packed)) eeprom_wireless_metadata_t; + bool enable; +} eeprom_wireless_metadata_t; + + + #ifdef __cplusplus diff --git a/tests/config_html_rest_test.py b/tests/config_html_rest_test.py index f602367..88cf432 100644 --- a/tests/config_html_rest_test.py +++ b/tests/config_html_rest_test.py @@ -26,17 +26,17 @@ @app.route('/rest/scale_config') def rest_scale_config(): - return """{"driver":"AND FX-i Std","baudrate":19200}""" + return """{"s0":"0","s1":2}""" @app.route('/rest/charge_mode_config') def rest_charge_mode_config(): - return """{"c_kp":0.020,"c_ki":0.000,"c_kd":0.200,"f_kp":1.000,"f_ki":0.000,"f_kd":5.000,"c_stop":5.000,"f_stop":0.030,"sp_sd":0.020,"sp_avg":0.020}""" + return """{"c1":"#00ff00","c2":"#ffff00","c3":"#ff0000","c4":"#0000ff","c5":3.000,"c6":0.030,"c7":0.020,"c8":0.020}""" @app.route('/rest/wireless_config') def rest_wireless_config(): - return """{"ssid":"YYYY","pw":"xxx","auth":"CYW43_AUTH_WPA2_AES_PSK","timeout_ms":30000,"configured":true}""" + return """{"w0":"YYYY","w1":"xxx","w2":"3","w3":30000,"w4":true}""" @app.route('/rest/eeprom_config') def rest_eeprom_config(): @@ -55,7 +55,7 @@ def rest_coarse_motor_config(): @app.route('/rest/system_control') def rest_system_control(): - return """{"unique_id":"8381FFF","save_to_eeprom":false,"software_reset":false,"erase_eeprom":false,"ver":"0.1.36-dirty","hash":"18111a5","build_type":"Debug"}""" + return """{"s0":"8381FFF","s1":"0.1.99-dirty","s2":"a10466c","s3":"Debug","s4":false,"s5":false,"s6":false}""" @app.route('/rest/neopixel_led_config') @@ -65,7 +65,7 @@ def rest_neopixel_led_config(): @app.route('/rest/button_config') def rest_button_config(): - return """{"inv_dir":true}""" + return """{"b0":true}""" @app.route('/rest/profile_config') def rest_profile_config():