diff --git a/.vscode/settings.json b/.vscode/settings.json index 7874ce6..db8e3d0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,6 +24,8 @@ "cmake.generator": "Ninja", "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", "files.associations": { - "neopixel_led.h": "c" + "neopixel_led.h": "c", + "app.h": "c", + "queue.h": "c" } } diff --git a/src/and_scale.c b/src/and_scale.c index e136cd4..26b5897 100644 --- a/src/and_scale.c +++ b/src/and_scale.c @@ -1,4 +1,3 @@ - #include #include #include @@ -27,26 +26,29 @@ typedef union { } scale_standard_data_format_t; -// In this case we will only use eeprom data format to store information -eeprom_scale_data_t scale_data; +// Forward declaration +void scale_listener_task(void *p); +void scale_write(char * command, size_t len); +extern scale_config_t scale_config; +// Instance of the scale handle for A&D FXi series +scale_handle_t and_fxi_scale_handle = { + .read_loop_task = scale_listener_task, + .write = scale_write +}; -// Statics (to be shared between multiple tasks) -static float current_scale_measurement = NAN; -SemaphoreHandle_t scale_measurement_ready; -SemaphoreHandle_t scale_serial_write_access_mutex = NULL; static inline void _take_mutex(BaseType_t scheduler_state) { if (scheduler_state != taskSCHEDULER_NOT_STARTED){ - xSemaphoreTake(scale_serial_write_access_mutex, portMAX_DELAY); + xSemaphoreTake(scale_config.scale_serial_write_access_mutex, portMAX_DELAY); } } static inline void _give_mutex(BaseType_t scheduler_state) { if (scheduler_state != taskSCHEDULER_NOT_STARTED){ - xSemaphoreGive(scale_serial_write_access_mutex); + xSemaphoreGive(scale_config.scale_serial_write_access_mutex); } } @@ -72,50 +74,6 @@ float _decode_measurement_msg(scale_standard_data_format_t * msg) { return weight; } -bool scale_init() { - bool is_ok; - - uart_init(SCALE_UART, SCALE_UART_BAUDRATE); - - gpio_set_function(SCALE_UART_TX, GPIO_FUNC_UART); - gpio_set_function(SCALE_UART_RX, GPIO_FUNC_UART); - - // Read config from EEPROM - is_ok = eeprom_read(EEPROM_SCALE_CONFIG_BASE_ADDR, (uint8_t *) &scale_data, sizeof(eeprom_scale_data_t)); - if (!is_ok) { - printf("Unable to read from EEPROM at address %x\n", EEPROM_SCALE_CONFIG_BASE_ADDR); - return false; - } - - // If the revision doesn't match then re-initialize the config - if (scale_data.scale_data_rev != EEPROM_SCALE_DATA_REV) { - scale_data.scale_data_rev = EEPROM_SCALE_DATA_REV; - scale_data.scale_unit = SCALE_UNIT_GRAIN; - - // Write data back - is_ok = scale_config_save(); - if (!is_ok) { - printf("Unable to write to %x\n", EEPROM_SCALE_CONFIG_BASE_ADDR); - return false; - } - } - - // Create control variables - // Semaphore to indicate the availability of new measurement. - scale_measurement_ready = xSemaphoreCreateBinary(); - - // Mutex to control the access to the serial port write - scale_serial_write_access_mutex = xSemaphoreCreateMutex(); - - return is_ok; -} - - -bool scale_config_save() { - bool is_ok = eeprom_write(EEPROM_SCALE_CONFIG_BASE_ADDR, (uint8_t *) &scale_data, sizeof(eeprom_scale_data_t)); - return is_ok; -} - void scale_listener_task(void *p) { char string_buf[20]; @@ -131,11 +89,11 @@ void scale_listener_task(void *p) { // If we have received 17 bytes then we can decode the message if (string_buf_idx == 17) { // Data is ready, send to decode - current_scale_measurement = _decode_measurement_msg((scale_standard_data_format_t *) string_buf); + scale_config.current_scale_measurement = _decode_measurement_msg((scale_standard_data_format_t *) string_buf); // Signal the data is ready - if (scale_measurement_ready) { - xSemaphoreGive(scale_measurement_ready); + if (scale_config.scale_measurement_ready) { + xSemaphoreGive(scale_config.scale_measurement_ready); } // Reset @@ -153,17 +111,6 @@ void scale_listener_task(void *p) { } -float scale_get_current_measurement() { - return current_scale_measurement; -} - -float scale_block_wait_for_next_measurement() { - // You can only call this once the scheduler starts - xSemaphoreTake(scale_measurement_ready, portMAX_DELAY); - return scale_get_current_measurement(); -} - - void scale_press_re_zero_key() { char cmd[] = "Z\r\n"; scale_write(cmd, strlen(cmd)); @@ -209,89 +156,3 @@ void scale_display_on() { // AppState_t scale_enable_fast_report(AppState_t prev_state) { // // TODO: Finish this // } - - -const char * get_scale_unit_string(bool is_short_string) { - const char * scale_unit_string = NULL; - - switch (scale_data.scale_unit) { - case SCALE_UNIT_GRAIN: - if (is_short_string) { - scale_unit_string = "gn"; - } - else { - scale_unit_string = "grain"; - } - - break; - case SCALE_UNIT_GRAM: - if (is_short_string) { - scale_unit_string = "g"; - } - else { - scale_unit_string = "gram"; - } - - break; - default: - break; - } - - return scale_unit_string; -} - -void set_scale_unit(scale_unit_t scale_unit) { - scale_data.scale_unit = scale_unit; -} - - -bool http_rest_scale_weight(struct fs_file *file, int num_params, char *params[], char *values[]) { - static char scale_weight_to_json_buffer[32]; - - snprintf(scale_weight_to_json_buffer, - sizeof(scale_weight_to_json_buffer), - "{\"weight\":%0.3f}", - scale_get_current_measurement()); - - size_t data_length = strlen(scale_weight_to_json_buffer); - file->data = scale_weight_to_json_buffer; - file->len = data_length; - file->index = data_length; - file->flags = FS_FILE_FLAGS_HEADER_INCLUDED; - - return true; -} - - -bool http_rest_scale_config(struct fs_file *file, int num_params, char *params[], char *values[]) { - static char scale_config_to_json_buffer[32]; - - // Set value - for (int idx = 0; idx < num_params; idx += 1) { - if (strcmp(params[idx], "unit") == 0) { - if (strcmp(values[idx], "grain") == 0) { - set_scale_unit(SCALE_UNIT_GRAIN); - } - else if (strcmp(values[idx], "gram") == 0) { - set_scale_unit(SCALE_UNIT_GRAM); - scale_data.scale_unit = SCALE_UNIT_GRAM; - } - } - } - - // Convert config to string - const char * scale_unit_string = get_scale_unit_string(false); - - snprintf(scale_config_to_json_buffer, - sizeof(scale_config_to_json_buffer), - "{\"unit\":\"%s\"}", - scale_unit_string); - - size_t data_length = strlen(scale_config_to_json_buffer); - file->data = scale_config_to_json_buffer; - file->len = data_length; - file->index = data_length; - file->flags = FS_FILE_FLAGS_HEADER_INCLUDED; - - return true; -} diff --git a/src/app.cpp b/src/app.cpp index 42b5f48..94692cd 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -65,7 +65,6 @@ int main() #error "Unpported platform" #endif // RASPBERRYPI_PICO_W xTaskCreate(menu_task, "Menu Task", configMINIMAL_STACK_SIZE, NULL, 6, NULL); - xTaskCreate(scale_listener_task, "Scale Task", configMINIMAL_STACK_SIZE, NULL, 9, NULL); // xTaskCreate(motor_task, "Motor Task", configMINIMAL_STACK_SIZE, NULL, 8, NULL); vTaskStartScheduler(); diff --git a/src/mui_menu.c b/src/mui_menu.c index 396a57c..fefe98b 100644 --- a/src/mui_menu.c +++ b/src/mui_menu.c @@ -19,7 +19,7 @@ extern AppState_t exit_state; extern charge_mode_config_t charge_mode_config; // Imported from and_scale module -extern eeprom_scale_data_t scale_data; +extern scale_config_t scale_config; @@ -154,7 +154,7 @@ muif_t muif_list[] = { MUIF_VARIABLE("LV", &exit_state, mui_u8g2_btn_exit_wm_fi), // Unit selection - MUIF_VARIABLE("UN",&scale_data.scale_unit, mui_u8g2_u8_opt_line_wa_mud_pi), + MUIF_VARIABLE("UN",&scale_config.persistent_config.scale_unit, mui_u8g2_u8_opt_line_wa_mud_pi), // Render unit MUIF_RO("SU", render_scale_unit), diff --git a/src/scale.c b/src/scale.c new file mode 100644 index 0000000..d4786a2 --- /dev/null +++ b/src/scale.c @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include + +#include "configuration.h" +#include "scale.h" +#include "eeprom.h" +#include "app.h" +#include "scale.h" + +extern scale_handle_t and_fxi_scale_handle; +scale_config_t scale_config; + + +void set_scale_unit(scale_unit_t scale_unit) { + scale_config.persistent_config.scale_unit = scale_unit; +} + +void set_scale_driver(scale_driver_t scale_driver) { + switch (scale_driver) { + case SCALE_DRIVER_AND_FXI: + { + scale_config.scale_handle = &and_fxi_scale_handle; + break; + } + default: + assert(false); + break; + } +} + +bool scale_init() { + bool is_ok; + + // Read config from EEPROM + is_ok = eeprom_read(EEPROM_SCALE_CONFIG_BASE_ADDR, (uint8_t *) &scale_config.persistent_config, sizeof(eeprom_scale_data_t)); + if (!is_ok) { + printf("Unable to read from EEPROM at address %x\n", EEPROM_SCALE_CONFIG_BASE_ADDR); + return false; + } + + // If the revision doesn't match then re-initialize the config + if (scale_config.persistent_config.scale_data_rev != EEPROM_SCALE_DATA_REV) { + + scale_config.persistent_config.scale_data_rev = EEPROM_SCALE_DATA_REV; + scale_config.persistent_config.scale_unit = SCALE_UNIT_GRAIN; + scale_config.persistent_config.scale_driver = SCALE_DRIVER_AND_FXI; + scale_config.persistent_config.scale_serial_params.baudrate = SCALE_UART_BAUDRATE; + + // Write data back + is_ok = scale_config_save(); + if (!is_ok) { + printf("Unable to write to %x\n", EEPROM_SCALE_CONFIG_BASE_ADDR); + return false; + } + } + + // Initialize UART + uart_init(SCALE_UART, scale_config.persistent_config.scale_serial_params.baudrate); + + gpio_set_function(SCALE_UART_TX, GPIO_FUNC_UART); + gpio_set_function(SCALE_UART_RX, GPIO_FUNC_UART); + + // Create control variables + // Semaphore to indicate the availability of new measurement. + scale_config.scale_measurement_ready = xSemaphoreCreateBinary(); + + // Mutex to control the access to the serial port write + scale_config.scale_serial_write_access_mutex = xSemaphoreCreateMutex(); + + // Initialize the measurement variable + scale_config.current_scale_measurement = NAN; + + // Initialize the driver handle + set_scale_driver(scale_config.persistent_config.scale_driver); + + // Create the Task for the listener loop + xTaskCreate(scale_config.scale_handle->read_loop_task, "Scale Task", configMINIMAL_STACK_SIZE, NULL, 9, NULL); + + return is_ok; +} + + +bool scale_config_save() { + bool is_ok = eeprom_write(EEPROM_SCALE_CONFIG_BASE_ADDR, (uint8_t *) &scale_config.persistent_config, sizeof(eeprom_scale_data_t)); + return is_ok; +} + + +const char * get_scale_unit_string(bool is_short_string) { + const char * scale_unit_string = NULL; + + switch (scale_config.persistent_config.scale_unit) { + case SCALE_UNIT_GRAIN: + if (is_short_string) { + scale_unit_string = "gn"; + } + else { + scale_unit_string = "grain"; + } + + break; + case SCALE_UNIT_GRAM: + if (is_short_string) { + scale_unit_string = "g"; + } + else { + scale_unit_string = "gram"; + } + + break; + default: + break; + } + + return scale_unit_string; +} + + +bool http_rest_scale_config(struct fs_file *file, int num_params, char *params[], char *values[]) { + static char scale_config_to_json_buffer[32]; + + // Set value + for (int idx = 0; idx < num_params; idx += 1) { + if (strcmp(params[idx], "unit") == 0) { + if (strcmp(values[idx], "grain") == 0) { + set_scale_unit(SCALE_UNIT_GRAIN); + } + else if (strcmp(values[idx], "gram") == 0) { + set_scale_unit(SCALE_UNIT_GRAM); + scale_config.persistent_config.scale_unit = SCALE_UNIT_GRAM; + } + } + } + + // Convert config to string + const char * scale_unit_string = get_scale_unit_string(false); + + snprintf(scale_config_to_json_buffer, + sizeof(scale_config_to_json_buffer), + "{\"unit\":\"%s\"}", + scale_unit_string); + + size_t data_length = strlen(scale_config_to_json_buffer); + file->data = scale_config_to_json_buffer; + file->len = data_length; + file->index = data_length; + file->flags = FS_FILE_FLAGS_HEADER_INCLUDED; + + return true; +} + + +bool http_rest_scale_weight(struct fs_file *file, int num_params, char *params[], char *values[]) { + static char scale_weight_to_json_buffer[32]; + + snprintf(scale_weight_to_json_buffer, + sizeof(scale_weight_to_json_buffer), + "{\"weight\":%0.3f}", + scale_get_current_measurement()); + + size_t data_length = strlen(scale_weight_to_json_buffer); + file->data = scale_weight_to_json_buffer; + file->len = data_length; + file->index = data_length; + file->flags = FS_FILE_FLAGS_HEADER_INCLUDED; + + return true; +} + + +float scale_get_current_measurement() { + return scale_config.current_scale_measurement; +} + + +float scale_block_wait_for_next_measurement() { + // You can only call this once the scheduler starts + xSemaphoreTake(scale_config.scale_measurement_ready, portMAX_DELAY); + return scale_get_current_measurement(); +} + diff --git a/src/scale.h b/src/scale.h index 31ccde5..ad90661 100644 --- a/src/scale.h +++ b/src/scale.h @@ -1,12 +1,28 @@ #ifndef SCALE_H_ #define SCALE_H_ +#include #include #include "app.h" #include "http_rest.h" +#include + +#define EEPROM_SCALE_DATA_REV 2 // 16 byte + + +typedef struct { + uint32_t baudrate; +} scale_serial_params_t; + + +// Abstracted base class +typedef struct { + // Basic functions + void (*read_loop_task)(void *self); + void (*write)(char * cmd, size_t len); +} scale_handle_t; -#define EEPROM_SCALE_DATA_REV 1 // 16 byte typedef enum { @@ -14,27 +30,46 @@ typedef enum { SCALE_UNIT_GRAM = 1, } scale_unit_t; +typedef enum { + SCALE_DRIVER_AND_FXI = 0, +} scale_driver_t; + + typedef struct { uint16_t scale_data_rev; scale_unit_t scale_unit; -} __attribute__((packed)) eeprom_scale_data_t; + scale_driver_t scale_driver; + scale_serial_params_t scale_serial_params; +} eeprom_scale_data_t; +typedef struct { + eeprom_scale_data_t persistent_config; + scale_handle_t * scale_handle; + SemaphoreHandle_t scale_measurement_ready; + SemaphoreHandle_t scale_serial_write_access_mutex; + float current_scale_measurement; +} scale_config_t; + #ifdef __cplusplus extern "C" { #endif -// Measurement related calls +// Scale related calls bool scale_init(); -void scale_listener_task(void *p); float scale_get_current_measurement(); float scale_block_wait_for_next_measurement(); - +const char * get_scale_unit_string(bool); +void set_scale_unit(scale_unit_t scale_unit); bool scale_config_save(void); +// REST +bool http_rest_scale_weight(struct fs_file *file, int num_params, char *params[], char *values[]); +bool http_rest_scale_config(struct fs_file *file, int num_params, char *params[], char *values[]); +////////////////////////// A&D Scale Implementations ///////////////////////////// // Key bindings void scale_press_re_zero_key(); void scale_press_print_key(); @@ -45,17 +80,11 @@ void scale_press_on_off_key(); void scale_display_off(); void scale_display_on(); + // Features uint8_t scale_calibrate_with_external_weight(); AppState_t scale_enable_fast_report(AppState_t prev_state); -const char * get_scale_unit_string(bool); -void set_scale_unit(scale_unit_t scale_unit); - -// REST -bool http_rest_scale_weight(struct fs_file *file, int num_params, char *params[], char *values[]); -bool http_rest_scale_config(struct fs_file *file, int num_params, char *params[], char *values[]); - #ifdef __cplusplus }