From e9fb27ca88e3422e27550da637c5c927dba3e380 Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov Date: Tue, 3 Nov 2026 09:32:19 +0300 Subject: [PATCH] wip: --- main/ate0005.c | 471 ++++++++++++++--------------------------- main/ate0005.h | 16 +- main/idf_component.yml | 6 +- 3 files changed, 172 insertions(+), 321 deletions(-) diff --git a/main/ate0005.c b/main/ate0005.c index 7901ffd..c5d2a5d 100644 --- a/main/ate0005.c +++ b/main/ate0005.c @@ -1,39 +1,19 @@ #include "ate0005.h" -/** @brief Global structure holding minimum free stack sizes for processing tasks. */ -static task_stats_t _task_stats = {A_INCLINOMETER_TASK_STACK_SIZE, B_INCLINOMETER_TASK_STACK_SIZE, A_TACHOMETER_TASK_STACK_SIZE, B_TACHOMETER_TASK_STACK_SIZE}; - -/** @brief HTTP server handle for OTA and web interface. */ static httpd_handle_t _http_server_handle = NULL; - -/** @brief PCF8574 handle for LCD I2C expander. */ static zh_pcf8574_handle_t *_lcd_handle = NULL; -/** @brief LCD 16x2 display handle wrapper. */ static zh_160x_i2c_handle_t *_lcd_160x_handle = NULL; -/** @brief Mode encoder handle for menu navigation. */ static zh_encoder_handle_t *_mode_encoder_handle = NULL; -/** @brief Inclinometer handle for channel A. */ static zh_inclinometer_handle_t *_a_inclinometer_handle = NULL; -/** @brief Inclinometer handle for channel B. */ static zh_inclinometer_handle_t *_b_inclinometer_handle = NULL; -/** @brief Tachometer handle for channel A. */ static zh_tachometer_handle_t *_a_tachometer_handle = NULL; -/** @brief Tachometer handle for channel B. */ static zh_tachometer_handle_t *_b_tachometer_handle = NULL; -/** @brief ESP timer handle for inclinometer reset timeout. */ static esp_timer_handle_t _inclinometer_reset_timer_handle = {0}; - -/** @brief Mutex for protecting LCD access from multiple tasks. */ static SemaphoreHandle_t _lcd_mutex = NULL; -/** @brief Task handle for the A inclinometer processing task. */ static TaskHandle_t _a_inclinometer_task_handle = NULL; -/** @brief Task handle for the B inclinometer processing task. */ static TaskHandle_t _b_inclinometer_task_handle = NULL; -/** @brief Task handle for the A tachometer processing task. */ static TaskHandle_t _a_tachometer_task_handle = NULL; -/** @brief Task handle for the B tachometer processing task. */ static TaskHandle_t _b_tachometer_task_handle = NULL; -/** @brief Task handle for the statistics logging task. */ static TaskHandle_t _zh_stats_task_handle = NULL; static void _zh_wifi_init(void); @@ -51,27 +31,13 @@ static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, in static void _zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); static void _zh_wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); static void _zh_inclinometer_reset_timer_on_alarm_cb(void *arg); - static void _zh_a_inclinometer_processing_task(void *pvParameter); static void _zh_b_inclinometer_processing_task(void *pvParameter); static void _zh_a_tachometer_processing_task(void *pvParameter); static void _zh_b_tachometer_processing_task(void *pvParameter); static void _zh_stats_processing_task(void *pvParameter); -static const char *_main_menu[] = {MAIN_MENU_ANGLE_ANGLE_NAME, MAIN_MENU_TACHO_TACHO_NAME, MAIN_MENU_ANGLE_TACHO_NAME, MAIN_MENU_REMOTE_NAME}; -/** @brief Flag indicating whether the menu selection mode is active. */ -volatile static bool _is_menu_mode = false; -/** @brief Flag indicating whether a long button press (reset mode) is detected. */ -volatile static bool _is_reset_mode = false; -/** @brief Flag indicating that a reset event has occurred and must be cleared. */ -volatile static bool _is_reset_occurred = false; -/** @brief Index of the currently selected menu mode. */ -volatile static uint8_t _current_menu_value = 0; -/** @brief Counter for WiFi STA reconnection retry attempts. */ -volatile static uint8_t _wifi_reconnect_retry_num = 0; -/** @brief Flag indicating whether WiFi STA is connected. */ -volatile static bool _is_wifi_connected = false; - +volatile static task_stats_t _task_stats = {A_INCLINOMETER_TASK_STACK_SIZE, B_INCLINOMETER_TASK_STACK_SIZE, A_TACHOMETER_TASK_STACK_SIZE, B_TACHOMETER_TASK_STACK_SIZE}; static const char *_main_menu[] = {MAIN_MENU_ANGLE_ANGLE_NAME, MAIN_MENU_TACHO_TACHO_NAME, MAIN_MENU_ANGLE_TACHO_NAME, MAIN_MENU_REMOTE_NAME}; volatile static bool _is_menu_mode = false; volatile static bool _is_reset_mode = false; @@ -80,51 +46,41 @@ volatile static uint8_t _current_menu_value = 0; volatile static uint8_t _wifi_reconnect_retry_num = 0; volatile static bool _is_wifi_connected = false; -/** - * @brief Application entry point. - * - * Initializes all system components: LCD, encoder, timers, inclinometers, - * WiFi, web server, and ESP-NOW. Checks OTA state and marks firmware - * as valid if a pending verification is detected. - */ void app_main(void) { - _lcd_mutex = xSemaphoreCreateMutex(); /*!< Create mutex for LCD access protection. */ - nvs_flash_init(); /*!< Initialize NVS flash storage. */ - esp_event_loop_create_default(); /*!< Create default event loop. */ - _zh_pcf8574_init(); /*!< Initialize I2C bus and PCF8574 expander for LCD. */ - _zh_system_load(); /*!< Display boot animation on LCD. */ - _zh_encoder_init(); /*!< Initialize mode encoder for menu navigation. */ - _zh_timer_init(); /*!< Initialize inclinometer reset timer. */ - _zh_a_inclinometer_init(); /*!< Initialize inclinometer for channel A and its task. */ - _zh_b_inclinometer_init(); /*!< Initialize inclinometer for channel B and its task. */ - _zh_wifi_init(); /*!< Initialize WiFi in AP+STA mode. */ - _zh_webserver_init(); /*!< Start HTTP server with OTA endpoint. */ - _zh_espnow_init(); /*!< Initialize ESP-NOW communication. */ - const esp_partition_t *running = esp_ota_get_running_partition(); /*!< Get current OTA partition. */ - esp_ota_img_states_t ota_state = {0}; - esp_ota_get_state_partition(running, &ota_state); /*!< Read OTA image state. */ - if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) /*!< Check if firmware update is pending verification. */ + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { - vTaskDelay(60000 / portTICK_PERIOD_MS); /*!< Wait 60 seconds before confirming. */ - esp_ota_mark_app_valid_cancel_rollback(); /*!< Mark firmware as valid and cancel rollback. */ + ESP_ERROR_CHECK(nvs_flash_erase()); + ESP_ERROR_CHECK(nvs_flash_init()); + } + esp_event_loop_create_default(); + _zh_pcf8574_init(); + _zh_system_load(); + _zh_encoder_init(); + _zh_timer_init(); + _zh_a_inclinometer_init(); + _zh_b_inclinometer_init(); + _zh_wifi_init(); + _zh_webserver_init(); + _zh_espnow_init(); + const esp_partition_t *running = esp_ota_get_running_partition(); + esp_ota_img_states_t ota_state = {0}; + esp_ota_get_state_partition(running, &ota_state); + if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) + { + vTaskDelay(60000 / portTICK_PERIOD_MS); + esp_ota_mark_app_valid_cancel_rollback(); } } -/** - * @brief Initialize WiFi in AP+STA mode. - * - * Configures and starts WiFi with both AP and STA interfaces. - * AP provides local access for device configuration. - * STA connects to the configured network for remote logging. - */ static void _zh_wifi_init(void) { - esp_netif_init(); /*!< Initialize networking stack. */ - esp_netif_create_default_wifi_ap(); /*!< Create default network interface for AP. */ - esp_netif_create_default_wifi_sta(); /*!< Create default network interface for STA. */ + esp_netif_init(); + esp_netif_create_default_wifi_ap(); + esp_netif_create_default_wifi_sta(); wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT(); - esp_wifi_init(&wifi_init_config); /*!< Initialize WiFi driver with default config. */ + esp_wifi_init(&wifi_init_config); wifi_config_t wifi_ap_config = { .ap.ssid = WIFI_AP_SSID, .ap.password = WIFI_AP_PASS, @@ -136,180 +92,127 @@ static void _zh_wifi_init(void) .sta.ssid = WIFI_STA_SSID, .sta.password = WIFI_STA_PASS, }; - esp_wifi_set_mode(WIFI_MODE_APSTA); /*!< Set WiFi mode to AP+STA. */ - esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config); /*!< Apply AP configuration. */ - esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config); /*!< Apply STA configuration. */ - esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &_zh_wifi_event_handler, NULL, NULL); /*!< Register WiFi event handler. */ - esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &_zh_wifi_event_handler, NULL, NULL); /*!< Register IP event handler. */ - esp_wifi_start(); /*!< Start WiFi. */ + esp_wifi_set_mode(WIFI_MODE_APSTA); + esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config); + esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config); + esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &_zh_wifi_event_handler, NULL, NULL); + esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &_zh_wifi_event_handler, NULL, NULL); + esp_wifi_start(); } -/** - * @brief Initialize the HTTP server with OTA support. - * - * Starts the ESP HTTP server and registers the OTA server - * endpoint for over-the-air firmware updates. - */ static void _zh_webserver_init(void) { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); - httpd_start(&_http_server_handle, &config); /*!< Start HTTP server. */ - zh_ota_server_init(_http_server_handle, "/"); /*!< Register OTA endpoint. */ + httpd_start(&_http_server_handle, &config); + zh_ota_server_init(_http_server_handle, "/"); } -/** - * @brief Initialize ESP-NOW communication. - * - * Currently a placeholder. ESP-NOW initialization is not yet implemented. - */ static void _zh_espnow_init(void) { // To Do. } -/** - * @brief Initialize the mode encoder for menu navigation. - * - * Configures the rotary encoder with GPIO pins, task parameters, - * and event handler. Sets encoder range to cover all menu modes. - */ static void _zh_encoder_init(void) { - esp_event_handler_instance_register(ZH_ENCODER, ESP_EVENT_ANY_ID, &_zh_encoder_event_handler, NULL, NULL); /*!< Register encoder event handler. */ + esp_event_handler_instance_register(ZH_ENCODER, ESP_EVENT_ANY_ID, &_zh_encoder_event_handler, NULL, NULL); zh_encoder_init_config_t config = ZH_ENCODER_INIT_CONFIG_DEFAULT(); - config.task_priority = ENCODER_TASK_PRIORITY; /*!< Set encoder task priority. */ - config.stack_size = ENCODER_TASK_STACK_SIZE; /*!< Set encoder task stack size. */ - config.queue_size = 5; /*!< Set event queue size. */ - config.a_gpio_number = MODE_ENCODER_A_GPIO; /*!< Set A-phase GPIO pin. */ - config.b_gpio_number = MODE_ENCODER_B_GPIO; /*!< Set B-phase GPIO pin. */ - config.s_gpio_number = MODE_ENCODER_S_GPIO; /*!< Set switch GPIO pin. */ - config.s_gpio_debounce_time = 1000; /*!< Set switch debounce time in microseconds. */ - config.encoder_min_value = 0; /*!< Set minimum encoder value (first menu item). */ - config.encoder_max_value = (sizeof(_main_menu) / sizeof(_main_menu[0])) - 1; /*!< Set maximum encoder value (last menu item). */ - config.encoder_step = 1; /*!< Set encoder step size. */ - config.encoder_number = MODE_ENCODER_NUMBER; /*!< Set encoder instance number. */ - zh_encoder_init(&config, &_mode_encoder_handle); /*!< Initialize encoder driver. */ - zh_encoder_set(&_mode_encoder_handle, 0); /*!< Reset encoder to initial position. */ + config.task_priority = ENCODER_TASK_PRIORITY; + config.stack_size = ENCODER_TASK_STACK_SIZE; + config.queue_size = 5; + config.a_gpio_number = MODE_ENCODER_A_GPIO; + config.b_gpio_number = MODE_ENCODER_B_GPIO; + config.s_gpio_number = MODE_ENCODER_S_GPIO; + config.s_gpio_debounce_time = 1000; + config.encoder_min_value = 0; + config.encoder_max_value = (sizeof(_main_menu) / sizeof(_main_menu[0])) - 1; + config.encoder_step = 1; + config.encoder_number = MODE_ENCODER_NUMBER; + zh_encoder_init(&config, &_mode_encoder_handle); + zh_encoder_set(&_mode_encoder_handle, 0); } -/** - * @brief Initialize inclinometer for channel A and create its processing task. - * - * Configures optical device GPIO pins and encoder pulses (3600). - * Creates a FreeRTOS task for processing inclinometer data. - */ static void _zh_a_inclinometer_init(void) { zh_inclinometer_init_config_t config = ZH_INCLINOMETER_INIT_CONFIG_DEFAULT(); - config.a_gpio_number = A_OPTICAL_DEVICE_A_GPIO; /*!< Set A-phase GPIO pin. */ - config.b_gpio_number = A_OPTICAL_DEVICE_B_GPIO; /*!< Set B-phase GPIO pin. */ - config.encoder_pulses = 3600; /*!< Set encoder pulses per revolution. */ - zh_inclinometer_init(&config, &_a_inclinometer_handle); /*!< Initialize inclinometer driver. */ + config.a_gpio_number = A_OPTICAL_DEVICE_A_GPIO; + config.b_gpio_number = A_OPTICAL_DEVICE_B_GPIO; + config.encoder_pulses = 3600; + zh_inclinometer_init(&config, &_a_inclinometer_handle); xTaskCreatePinnedToCore(&_zh_a_inclinometer_processing_task, "a_inclinometer_processing_task", A_INCLINOMETER_TASK_STACK_SIZE, NULL, A_INCLINOMETER_TASK_PRIORITY, - &_a_inclinometer_task_handle, tskNO_AFFINITY); /*!< Create processing task. */ + &_a_inclinometer_task_handle, tskNO_AFFINITY); } -/** - * @brief Initialize inclinometer for channel B and create its processing task. - * - * Configures optical device GPIO pins and encoder pulses (3600). - * Creates a FreeRTOS task for processing inclinometer data. - */ static void _zh_b_inclinometer_init(void) { zh_inclinometer_init_config_t config = ZH_INCLINOMETER_INIT_CONFIG_DEFAULT(); - config.a_gpio_number = B_OPTICAL_DEVICE_A_GPIO; /*!< Set A-phase GPIO pin. */ - config.b_gpio_number = B_OPTICAL_DEVICE_B_GPIO; /*!< Set B-phase GPIO pin. */ - config.encoder_pulses = 3600; /*!< Set encoder pulses per revolution. */ - zh_inclinometer_init(&config, &_b_inclinometer_handle); /*!< Initialize inclinometer driver. */ + config.a_gpio_number = B_OPTICAL_DEVICE_A_GPIO; + config.b_gpio_number = B_OPTICAL_DEVICE_B_GPIO; + config.encoder_pulses = 3600; + zh_inclinometer_init(&config, &_b_inclinometer_handle); xTaskCreatePinnedToCore(&_zh_b_inclinometer_processing_task, "b_inclinometer_processing_task", B_INCLINOMETER_TASK_STACK_SIZE, NULL, B_INCLINOMETER_TASK_PRIORITY, - &_b_inclinometer_task_handle, tskNO_AFFINITY); /*!< Create processing task. */ + &_b_inclinometer_task_handle, tskNO_AFFINITY); } -/** - * @brief Initialize tachometer for channel A and create its processing task. - * - * Configures optical device GPIO pins and encoder pulses (3600). - * Creates a FreeRTOS task for processing tachometer data. - */ static void _zh_a_tachometer_init(void) { zh_tachometer_init_config_t config = ZH_TACHOMETER_INIT_CONFIG_DEFAULT(); - config.a_gpio_number = A_OPTICAL_DEVICE_A_GPIO; /*!< Set A-phase GPIO pin. */ - config.b_gpio_number = A_OPTICAL_DEVICE_B_GPIO; /*!< Set B-phase GPIO pin. */ - config.encoder_pulses = 3600; /*!< Set encoder pulses per revolution. */ - zh_tachometer_init(&config, &_a_tachometer_handle); /*!< Initialize tachometer driver. */ + config.a_gpio_number = A_OPTICAL_DEVICE_A_GPIO; + config.b_gpio_number = A_OPTICAL_DEVICE_B_GPIO; + config.encoder_pulses = 3600; + zh_tachometer_init(&config, &_a_tachometer_handle); xTaskCreatePinnedToCore(&_zh_a_tachometer_processing_task, "a_tachometer_processing_task", A_TACHOMETER_TASK_STACK_SIZE, NULL, A_TACHOMETER_TASK_PRIORITY, - &_a_tachometer_task_handle, tskNO_AFFINITY); /*!< Create processing task. */ + &_a_tachometer_task_handle, tskNO_AFFINITY); } -/** - * @brief Initialize tachometer for channel B and create its processing task. - * - * Configures optical device GPIO pins and encoder pulses (3600). - * Creates a FreeRTOS task for processing tachometer data. - */ static void _zh_b_tachometer_init(void) { zh_tachometer_init_config_t config = ZH_TACHOMETER_INIT_CONFIG_DEFAULT(); - config.a_gpio_number = B_OPTICAL_DEVICE_A_GPIO; /*!< Set A-phase GPIO pin. */ - config.b_gpio_number = B_OPTICAL_DEVICE_B_GPIO; /*!< Set B-phase GPIO pin. */ - config.encoder_pulses = 3600; /*!< Set encoder pulses per revolution. */ - zh_tachometer_init(&config, &_b_tachometer_handle); /*!< Initialize tachometer driver. */ + config.a_gpio_number = B_OPTICAL_DEVICE_A_GPIO; + config.b_gpio_number = B_OPTICAL_DEVICE_B_GPIO; + config.encoder_pulses = 3600; + zh_tachometer_init(&config, &_b_tachometer_handle); xTaskCreatePinnedToCore(&_zh_b_tachometer_processing_task, "b_tachometer_processing_task", B_TACHOMETER_TASK_STACK_SIZE, NULL, B_TACHOMETER_TASK_PRIORITY, - &_b_tachometer_task_handle, tskNO_AFFINITY); /*!< Create processing task. */ + &_b_tachometer_task_handle, tskNO_AFFINITY); } -/** - * @brief Initialize I2C bus and PCF8574 expander for LCD display. - * - * Configures I2C with internal pull-ups and creates the master bus. - * Initializes the PCF8574 expander and 16x2 LCD wrapper. - */ static void _zh_pcf8574_init(void) { i2c_master_bus_handle_t _i2c_bus_handle = NULL; i2c_master_bus_config_t i2c_bus_config = { .clk_source = I2C_CLK_SRC_DEFAULT, - .scl_io_num = I2C_SCL_GPIO, /*!< I2C clock GPIO. */ - .sda_io_num = I2C_SDA_GPIO, /*!< I2C data GPIO. */ - .glitch_ignore_cnt = 7, /*!< Glitch filter count. */ - .flags.enable_internal_pullup = true, /*!< Enable internal pull-up resistors. */ + .scl_io_num = I2C_SCL_GPIO, + .sda_io_num = I2C_SDA_GPIO, + .glitch_ignore_cnt = 7, + .flags.enable_internal_pullup = true, }; - i2c_new_master_bus(&i2c_bus_config, &_i2c_bus_handle); /*!< Create I2C master bus. */ + i2c_new_master_bus(&i2c_bus_config, &_i2c_bus_handle); zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT(); - config.task_priority = EXPANDER_TASK_PRIORITY; /*!< Set expander task priority. */ - config.stack_size = EXPANDER_TASK_STACK_SIZE; /*!< Set expander task stack size. */ - config.i2c_handle = _i2c_bus_handle; /*!< Assign I2C bus handle. */ - config.i2c_address = LCD_I2C_ADDRESS; /*!< Set I2C address of PCF8574. */ - zh_pcf8574_init(&config, &_lcd_handle); /*!< Initialize PCF8574 driver. */ - zh_160x_init(&_lcd_handle, &_lcd_160x_handle, ZH_LCD_16X2); /*!< Initialize 16x2 LCD wrapper. */ + config.task_priority = EXPANDER_TASK_PRIORITY; + config.stack_size = EXPANDER_TASK_STACK_SIZE; + config.i2c_handle = _i2c_bus_handle; + config.i2c_address = LCD_I2C_ADDRESS; + zh_pcf8574_init(&config, &_lcd_handle); + zh_160x_init(&_lcd_handle, &_lcd_160x_handle, ZH_LCD_16X2); + _lcd_mutex = xSemaphoreCreateMutex(); } -/** - * @brief Display system boot animation on LCD. - * - * Shows company name, project name, and version. - * Then displays a progress bar during system loading. - * Finally, shows the initial operating mode. - */ static void _zh_system_load(void) { - zh_160x_set_cursor(&_lcd_160x_handle, 0, 0); /*!< Set cursor to first row, first column. */ - zh_160x_print_char(&_lcd_160x_handle, "LLC AEROTECH"); /*!< Display company name. */ - zh_160x_set_cursor(&_lcd_160x_handle, 1, 0); /*!< Set cursor to second row, first column. */ - const esp_app_desc_t *esp_app_desc = esp_app_get_description(); /*!< Get application description. */ - zh_160x_print_char(&_lcd_160x_handle, esp_app_desc->project_name); /*!< Display project name. */ - zh_160x_set_cursor(&_lcd_160x_handle, 1, 8); /*!< Set cursor to version position. */ - zh_160x_print_char(&_lcd_160x_handle, "V"); /*!< Display version prefix. */ - zh_160x_print_char(&_lcd_160x_handle, esp_app_desc->version); /*!< Display firmware version. */ - vTaskDelay(1000 / portTICK_PERIOD_MS); /*!< Wait 1 second. */ - zh_160x_lcd_clear(&_lcd_160x_handle); /*!< Clear LCD. */ + zh_160x_set_cursor(&_lcd_160x_handle, 0, 0); + zh_160x_print_char(&_lcd_160x_handle, "LLC AEROTECH"); + zh_160x_set_cursor(&_lcd_160x_handle, 1, 0); + const esp_app_desc_t *esp_app_desc = esp_app_get_description(); + zh_160x_print_char(&_lcd_160x_handle, esp_app_desc->project_name); + zh_160x_set_cursor(&_lcd_160x_handle, 1, 8); + zh_160x_print_char(&_lcd_160x_handle, "V"); + zh_160x_print_char(&_lcd_160x_handle, esp_app_desc->version); + vTaskDelay(1000 / portTICK_PERIOD_MS); + zh_160x_lcd_clear(&_lcd_160x_handle); zh_160x_set_cursor(&_lcd_160x_handle, 0, 0); zh_160x_print_char(&_lcd_160x_handle, "SYSTEM LOADING:"); for (uint8_t i = 0; i <= 100; i += 10) { - zh_160x_print_progress_bar(&_lcd_160x_handle, 1, i); /*!< Draw progress bar at given percentage. */ + zh_160x_print_progress_bar(&_lcd_160x_handle, 1, i); vTaskDelay(100 / portTICK_PERIOD_MS); } vTaskDelay(500 / portTICK_PERIOD_MS); @@ -320,40 +223,24 @@ static void _zh_system_load(void) zh_160x_print_char(&_lcd_160x_handle, _main_menu[0]); } -/** - * @brief Initialize the inclinometer reset timer. - * - * Creates a one-shot timer that triggers after a long button press. - * Used to reset inclinometer angles when the encoder button is held. - */ static void _zh_timer_init(void) { const esp_timer_create_args_t timer_args = { - .callback = &_zh_inclinometer_reset_timer_on_alarm_cb, /*!< Timer callback function. */ + .callback = &_zh_inclinometer_reset_timer_on_alarm_cb, }; - esp_timer_create(&timer_args, &_inclinometer_reset_timer_handle); /*!< Create one-shot timer. */ + esp_timer_create(&timer_args, &_inclinometer_reset_timer_handle); } -/** - * @brief Handle encoder events (button press/release and rotation). - * - * Processes button events for menu navigation and long-press reset. - * Processes rotation events for menu mode selection. - * - * @param arg Unused context argument. - * @param event_base Event base (ZH_ENCODER). - * @param event_id Event identifier (ZH_BUTTON_EVENT or ZH_ENCODER_EVENT). - * @param event_data Pointer to event data structure. - */ static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { + (void)arg; switch (event_id) { case ZH_BUTTON_EVENT: - zh_encoder_button_event_on_isr_t *button_event = event_data; - if (button_event->button_status == ENCODER_BUTTON_PRESSED) + zh_encoder_button_event_on_isr_t *button_event = (zh_encoder_button_event_on_isr_t *)event_data; + if (button_event->button_status == ZH_ENCODER_BUTTON_STATUS_PRESSED) { - esp_timer_start_once(_inclinometer_reset_timer_handle, 2000000); /*!< Start reset timer (2 seconds). */ + esp_timer_start_once(_inclinometer_reset_timer_handle, 2000000); _is_reset_mode = true; } else @@ -365,7 +252,7 @@ static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, in } if (_is_reset_mode == true) { - esp_timer_stop(_inclinometer_reset_timer_handle); /*!< Stop reset timer on button release. */ + esp_timer_stop(_inclinometer_reset_timer_handle); _is_reset_mode = false; } _is_menu_mode = !_is_menu_mode; @@ -374,20 +261,38 @@ static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, in switch (_current_menu_value) { case MODE_ANGLE_ANGLE: - vTaskDelete(_a_inclinometer_task_handle); - vTaskDelete(_b_inclinometer_task_handle); + if (_a_inclinometer_task_handle != NULL) + { + vTaskDelete(_a_inclinometer_task_handle); + } + if (_b_inclinometer_task_handle != NULL) + { + vTaskDelete(_b_inclinometer_task_handle); + } zh_inclinometer_deinit(&_a_inclinometer_handle); zh_inclinometer_deinit(&_b_inclinometer_handle); break; case MODE_TACHO_TACHO: - vTaskDelete(_a_tachometer_task_handle); - vTaskDelete(_b_tachometer_task_handle); + if (_a_tachometer_task_handle != NULL) + { + vTaskDelete(_a_tachometer_task_handle); + } + if (_b_tachometer_task_handle != NULL) + { + vTaskDelete(_b_tachometer_task_handle); + } zh_tachometer_deinit(&_a_tachometer_handle); zh_tachometer_deinit(&_b_tachometer_handle); break; case MODE_ANGLE_TACHO: - vTaskDelete(_a_inclinometer_task_handle); - vTaskDelete(_b_tachometer_task_handle); + if (_a_inclinometer_task_handle != NULL) + { + vTaskDelete(_a_inclinometer_task_handle); + } + if (_b_tachometer_task_handle != NULL) + { + vTaskDelete(_b_tachometer_task_handle); + } zh_inclinometer_deinit(&_a_inclinometer_handle); zh_tachometer_deinit(&_b_tachometer_handle); break; @@ -429,7 +334,7 @@ static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, in } break; case ZH_ENCODER_EVENT: - zh_encoder_event_on_isr_t *encoder_event = event_data; + zh_encoder_event_on_isr_t *encoder_event = (zh_encoder_event_on_isr_t *)event_data; if (_is_menu_mode == true) { _current_menu_value = (uint8_t)encoder_event->encoder_position; @@ -449,35 +354,15 @@ static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, in } } -/** - * @brief Handle ESP-NOW events. - * - * Currently a placeholder. ESP-NOW event handling is not yet implemented. - * - * @param arg Unused context argument. - * @param event_base Event base. - * @param event_id Event identifier. - * @param event_data Pointer to event data structure. - */ static void _zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { // To Do. } -/** - * @brief Handle WiFi events (connection, disconnection, IP acquisition). - * - * Manages STA connection lifecycle: initiates connection on start, - * attempts reconnection on disconnect (with retry limit), and starts - * syslog + stats task upon successful IP acquisition. - * - * @param arg Unused context argument. - * @param event_base Event base (WIFI_EVENT or IP_EVENT). - * @param event_id Event identifier. - * @param event_data Pointer to event data structure. - */ static void _zh_wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { + (void)arg; + (void)event_data; switch (event_id) { case WIFI_EVENT_STA_START: @@ -486,7 +371,10 @@ static void _zh_wifi_event_handler(void *arg, esp_event_base_t event_base, int32 case WIFI_EVENT_STA_DISCONNECTED: if (_is_wifi_connected == true) { - vTaskDelete(_zh_stats_task_handle); + if (_zh_stats_task_handle != NULL) + { + vTaskDelete(_zh_stats_task_handle); + } zh_syslog_deinit(); _is_wifi_connected = false; } @@ -502,23 +390,19 @@ static void _zh_wifi_event_handler(void *arg, esp_event_base_t event_base, int32 zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT(); strcpy(config.syslog_ip, SYSLOG_IP); zh_syslog_init(&config); - xTaskCreatePinnedToCore(&_zh_stats_processing_task, "stats_processing_task", STATS_TASK_STACK_SIZE, NULL, STATS_TASK_PRIORITY, &_zh_stats_task_handle, tskNO_AFFINITY); + if (_zh_stats_task_handle == NULL) + { + xTaskCreatePinnedToCore(&_zh_stats_processing_task, "stats_processing_task", STATS_TASK_STACK_SIZE, NULL, STATS_TASK_PRIORITY, &_zh_stats_task_handle, tskNO_AFFINITY); + } break; default: break; } } -/** - * @brief Timer callback for inclinometer reset on long button press. - * - * Called when the encoder button is held for 2 seconds. - * Resets inclinometer angles for the active mode. - * - * @param arg Unused context argument. - */ static void _zh_inclinometer_reset_timer_on_alarm_cb(void *arg) { + (void)arg; _is_reset_mode = false; _is_reset_occurred = true; if (_is_menu_mode == false) @@ -538,17 +422,11 @@ static void _zh_inclinometer_reset_timer_on_alarm_cb(void *arg) } } -/** - * @brief FreeRTOS task for processing inclinometer A data. - * - * Reads angle from inclinometer A and updates the LCD display - * on row 1, columns 2-5. Tracks minimum free stack size for monitoring. - * - * @param pvParameter Unused parameter. - */ static void _zh_a_inclinometer_processing_task(void *pvParameter) { - float prev_angle = 0, current_angle = 0; + (void)pvParameter; + float prev_angle = 0.0; + float current_angle = 0.0; xSemaphoreTake(_lcd_mutex, portMAX_DELAY); zh_160x_set_cursor(&_lcd_160x_handle, 1, 0); zh_160x_print_char(&_lcd_160x_handle, "A:"); @@ -573,17 +451,11 @@ static void _zh_a_inclinometer_processing_task(void *pvParameter) vTaskDelete(NULL); } -/** - * @brief FreeRTOS task for processing inclinometer B data. - * - * Reads angle from inclinometer B and updates the LCD display - * on row 1, columns 10-13. Tracks minimum free stack size for monitoring. - * - * @param pvParameter Unused parameter. - */ static void _zh_b_inclinometer_processing_task(void *pvParameter) { - float prev_angle = 0, current_angle = 0; + (void)pvParameter; + float prev_angle = 0.0; + float current_angle = 0.0; xSemaphoreTake(_lcd_mutex, portMAX_DELAY); zh_160x_set_cursor(&_lcd_160x_handle, 1, 8); zh_160x_print_char(&_lcd_160x_handle, "B:"); @@ -608,17 +480,11 @@ static void _zh_b_inclinometer_processing_task(void *pvParameter) vTaskDelete(NULL); } -/** - * @brief FreeRTOS task for processing tachometer A data. - * - * Reads RPM from tachometer A and updates the LCD display - * on row 1, columns 2-5. Tracks minimum free stack size for monitoring. - * - * @param pvParameter Unused parameter. - */ static void _zh_a_tachometer_processing_task(void *pvParameter) { - uint16_t prev_rpm = 0, current_rpm = 0; + (void)pvParameter; + uint16_t prev_rpm = 0; + uint16_t current_rpm = 0; xSemaphoreTake(_lcd_mutex, portMAX_DELAY); zh_160x_set_cursor(&_lcd_160x_handle, 1, 0); zh_160x_print_char(&_lcd_160x_handle, "A:"); @@ -643,17 +509,11 @@ static void _zh_a_tachometer_processing_task(void *pvParameter) vTaskDelete(NULL); } -/** - * @brief FreeRTOS task for processing tachometer B data. - * - * Reads RPM from tachometer B and updates the LCD display - * on row 1, columns 10-13. Tracks minimum free stack size for monitoring. - * - * @param pvParameter Unused parameter. - */ static void _zh_b_tachometer_processing_task(void *pvParameter) { - uint16_t prev_rpm = 0, current_rpm = 0; + (void)pvParameter; + uint16_t prev_rpm = 0; + uint16_t current_rpm = 0; xSemaphoreTake(_lcd_mutex, portMAX_DELAY); zh_160x_set_cursor(&_lcd_160x_handle, 1, 8); zh_160x_print_char(&_lcd_160x_handle, "B:"); @@ -678,61 +538,52 @@ static void _zh_b_tachometer_processing_task(void *pvParameter) vTaskDelete(NULL); } -/** - * @brief FreeRTOS task for periodic system statistics logging. - * - * Periodically sends syslog messages with minimum free stack sizes - * for all processing tasks, and error counters for encoder and - * PCF8574 drivers. Logs at INFO level if values are within limits, - * WARNING otherwise. - * - * @param pvParameter Unused parameter. - */ static void _zh_stats_processing_task(void *pvParameter) { + (void)pvParameter; const esp_app_desc_t *esp_app_desc = esp_app_get_description(); for (;;) { char buffer[1024] = {0}; const zh_encoder_stats_t *encoder_stats = zh_encoder_get_stats(); const zh_pcf8574_stats_t *pcf8574_stats = zh_pcf8574_get_stats(); - snprintf(buffer, sizeof(buffer), "A inclinometer task minimum free stack size: %ld.\n", _task_stats.a_inclinometer_task_min_stack_size); + snprintf(buffer, sizeof(buffer), "A inclinometer task minimum free stack size: %lu.\n", _task_stats.a_inclinometer_task_min_stack_size); zh_syslog_send(ZH_KERN, _task_stats.a_inclinometer_task_min_stack_size > 100 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_inclinometer", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "B inclinometer task minimum free stack size: %ld.\n", _task_stats.b_inclinometer_task_min_stack_size); + snprintf(buffer, sizeof(buffer), "B inclinometer task minimum free stack size: %lu.\n", _task_stats.b_inclinometer_task_min_stack_size); zh_syslog_send(ZH_KERN, _task_stats.b_inclinometer_task_min_stack_size > 100 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_inclinometer", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "A tachometer task minimum free stack size: %ld.\n", _task_stats.a_tachometer_task_min_stack_size); + snprintf(buffer, sizeof(buffer), "A tachometer task minimum free stack size: %lu.\n", _task_stats.a_tachometer_task_min_stack_size); zh_syslog_send(ZH_KERN, _task_stats.a_tachometer_task_min_stack_size > 100 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_tachometer", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "B tachometer task minimum free stack size: %ld.\n", _task_stats.b_tachometer_task_min_stack_size); + snprintf(buffer, sizeof(buffer), "B tachometer task minimum free stack size: %lu.\n", _task_stats.b_tachometer_task_min_stack_size); zh_syslog_send(ZH_KERN, _task_stats.b_tachometer_task_min_stack_size > 100 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_tachometer", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "Stats task minimum free stack size: %ld.\n", (uint32_t)uxTaskGetStackHighWaterMark(NULL)); + snprintf(buffer, sizeof(buffer), "Stats task minimum free stack size: %lu.\n", (uint32_t)uxTaskGetStackHighWaterMark(NULL)); zh_syslog_send(ZH_KERN, (uint32_t)uxTaskGetStackHighWaterMark(NULL) > 100 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_syslog", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "Encoder task minimum free stack size: %ld.\n", encoder_stats->min_stack_size); + snprintf(buffer, sizeof(buffer), "Encoder task minimum free stack size: %lu.\n", encoder_stats->min_stack_size); zh_syslog_send(ZH_KERN, encoder_stats->min_stack_size > 100 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_encoder", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "Expander task minimum free stack size: %ld.\n", pcf8574_stats->min_stack_size); + snprintf(buffer, sizeof(buffer), "Expander task minimum free stack size: %lu.\n", pcf8574_stats->min_stack_size); zh_syslog_send(ZH_KERN, pcf8574_stats->min_stack_size > 100 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_pcf8574", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "Number of event post error: %ld.\n", encoder_stats->event_post_error); + snprintf(buffer, sizeof(buffer), "Number of event post error: %lu.\n", encoder_stats->event_post_error); zh_syslog_send(ZH_KERN, encoder_stats->event_post_error == 0 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_encoder", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "Number of queue overflow error: %ld.\n", encoder_stats->queue_overflow_error); + snprintf(buffer, sizeof(buffer), "Number of queue overflow error: %lu.\n", encoder_stats->queue_overflow_error); zh_syslog_send(ZH_KERN, encoder_stats->queue_overflow_error == 0 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_encoder", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "Number of i2c driver error: %ld.\n", pcf8574_stats->i2c_driver_error); + snprintf(buffer, sizeof(buffer), "Number of i2c driver error: %lu.\n", pcf8574_stats->i2c_driver_error); zh_syslog_send(ZH_KERN, pcf8574_stats->i2c_driver_error == 0 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_pcf8574", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "Number of event post error: %ld.\n", pcf8574_stats->event_post_error); + snprintf(buffer, sizeof(buffer), "Number of event post error: %lu.\n", pcf8574_stats->event_post_error); zh_syslog_send(ZH_KERN, pcf8574_stats->event_post_error == 0 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_pcf8574", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "Number of vector error: %ld.\n", pcf8574_stats->vector_error); + snprintf(buffer, sizeof(buffer), "Number of vector error: %lu.\n", pcf8574_stats->vector_error); zh_syslog_send(ZH_KERN, pcf8574_stats->vector_error == 0 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_pcf8574", buffer); vTaskDelay(500 / portTICK_PERIOD_MS); - snprintf(buffer, sizeof(buffer), "Number of queue overflow error: %ld.\n", pcf8574_stats->queue_overflow_error); + snprintf(buffer, sizeof(buffer), "Number of queue overflow error: %lu.\n", pcf8574_stats->queue_overflow_error); zh_syslog_send(ZH_KERN, pcf8574_stats->queue_overflow_error == 0 ? ZH_INFO : ZH_WARNING, esp_app_desc->project_name, "zh_pcf8574", buffer); vTaskDelay(60000 / portTICK_PERIOD_MS); } diff --git a/main/ate0005.h b/main/ate0005.h index 3949b5c..fdfaf39 100644 --- a/main/ate0005.h +++ b/main/ate0005.h @@ -43,17 +43,17 @@ #define EXPANDER_TASK_PRIORITY tskIDLE_PRIORITY + 4 /*!< Priority of the PCF8574 expander task. */ #define EXPANDER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE /*!< Stack size for the PCF8574 expander task. */ -#define TRIAC_ON true /*!< Triac enabled state. */ -#define TRIAC_OFF false /*!< Triac disabled state. */ +// #define TRIAC_ON true /*!< Triac enabled state. */ +// #define TRIAC_OFF false /*!< Triac disabled state. */ -#define ENCODER_BUTTON_RELEASED true /*!< Encoder button released state. */ -#define ENCODER_BUTTON_PRESSED false /*!< Encoder button pressed state. */ +// #define ENCODER_BUTTON_RELEASED true /*!< Encoder button released state. */ +// #define ENCODER_BUTTON_PRESSED false /*!< Encoder button pressed state. */ -#define LED_OFF ZH_PCF8574_GPIO_LOW /*!< LED turned off (low level). */ -#define LED_ON ZH_PCF8574_GPIO_HIGH /*!< LED turned on (high level). */ +// #define LED_OFF ZH_PCF8574_GPIO_LOW /*!< LED turned off (low level). */ +// #define LED_ON ZH_PCF8574_GPIO_HIGH /*!< LED turned on (high level). */ -#define RELAY_OFF ZH_PCF8574_GPIO_LOW /*!< Relay disconnected (low level). */ -#define RELAY_ON ZH_PCF8574_GPIO_HIGH /*!< Relay connected (high level). */ +// #define RELAY_OFF ZH_PCF8574_GPIO_LOW /*!< Relay disconnected (low level). */ +// #define RELAY_ON ZH_PCF8574_GPIO_HIGH /*!< Relay connected (high level). */ #define MODE_ANGLE_ANGLE 0 /*!< Operating mode: both inclinometers active. */ #define MAIN_MENU_ANGLE_ANGLE_NAME "ANGLE/ANGLE" /*!< Menu label for angle/angle mode. */ diff --git a/main/idf_component.yml b/main/idf_component.yml index d31cd1b..245a70e 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,6 +1,6 @@ -description: Honeywell Ram Air Modulation Linear Electromechanical Actuator CMM 21-20-36 P/N 541674-X Linear Actuator Interface Test Box -url: https://github.com/aZholtikov/ate0002 -version: "1.2.0" +description: Universal Optical 2-Channel Angle Gauge / Tachometer +url: https://github.com/aZholtikov/ate0005 +version: "1.1.2" license: "Apache-2.0" maintainers: - "Alexey Zholtikov "