Compare commits
14
Commits
8fb8ef434d
...
menu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd5bcf2290 | ||
|
|
e9fb27ca88 | ||
|
|
1ad6a80fce | ||
|
|
e987d4cafb | ||
|
|
b8aa3a594d | ||
|
|
2a2d099504 | ||
|
|
32c5579fc9 | ||
|
|
69055cd185 | ||
|
|
ee121e1e59 | ||
|
|
9d82dbcbe9 | ||
|
|
d0ea38b750 | ||
|
|
45df58a940 | ||
|
|
eaf66e38e5 | ||
|
|
67e207c111 |
No files matched your search
@@ -5,3 +5,6 @@ sdkconfig.old
|
|||||||
desktop.ini
|
desktop.ini
|
||||||
.PVS-Studio
|
.PVS-Studio
|
||||||
sdkconfig
|
sdkconfig
|
||||||
|
dependencies.lock
|
||||||
|
managed_components
|
||||||
|
rules.md
|
||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
[submodule "components/zh_inclinometer"]
|
|
||||||
path = components/zh_inclinometer
|
|
||||||
url = https://github.com/aZholtikov/zh_inclinometer
|
|
||||||
[submodule "components/zh_encoder"]
|
|
||||||
path = components/zh_encoder
|
|
||||||
url = https://github.com/aZholtikov/zh_encoder
|
|
||||||
[submodule "components/zh_160x_i2c"]
|
|
||||||
path = components/zh_160x_i2c
|
|
||||||
url = https://github.com/aZholtikov/zh_160x_i2c
|
|
||||||
[submodule "components/zh_pcf8574"]
|
|
||||||
path = components/zh_pcf8574
|
|
||||||
url = https://github.com/aZholtikov/zh_pcf8574
|
|
||||||
[submodule "components/zh_vector"]
|
|
||||||
path = components/zh_vector
|
|
||||||
url = https://github.com/aZholtikov/zh_vector
|
|
||||||
[submodule "components/zh_ota_server"]
|
|
||||||
path = components/zh_ota_server
|
|
||||||
url = https://github.com/aZholtikov/zh_ota_server
|
|
||||||
[submodule "components/zh_espnow"]
|
|
||||||
path = components/zh_espnow
|
|
||||||
url = https://github.com/aZholtikov/zh_espnow
|
|
||||||
[submodule "components/zh_tachometer"]
|
|
||||||
path = components/zh_tachometer
|
|
||||||
url = https://github.com/aZholtikov/zh_tachometer
|
|
||||||
[submodule "components/zh_syslog"]
|
|
||||||
path = components/zh_syslog
|
|
||||||
url = https://github.com/aZholtikov/zh_syslog
|
|
||||||
@@ -1,18 +1,21 @@
|
|||||||
# Universal Optical 2-Channel Angle Gauge / Tachometer
|
# Universal Optical 2-Channel Angle Gauge / Tachometer
|
||||||
|
|
||||||
## Tested on
|
## Features
|
||||||
|
|
||||||
1. [ESP32 ESP-IDF v5.5.3](https://docs.espressif.com/projects/esp-idf/en/v5.5.3/esp32/index.html)
|
1. Two independent channels supporting optical encoders with 3600 pulses per revolution.
|
||||||
|
2. Four operating modes: both inclinometers, both tachometers, mixed angle/tachometer, and remote via ESP-NOW.
|
||||||
## SAST Tools
|
3. 16x2 LCD display (PCF8574 I2C expander) with boot animation, progress bar, and real-time value updates.
|
||||||
|
4. Rotary encoder menu with push-button for mode switching and angle reset (long press, 2 seconds).
|
||||||
[PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.
|
5. WiFi AP+STA mode with local access and STA connection for remote logging.
|
||||||
|
6. Over-the-Air (OTA) firmware updates via built-in HTTP server.
|
||||||
|
7. Remote syslog with periodic logging of task stack usage and driver error counters.
|
||||||
|
8. FreeRTOS-based multitasking with separate tasks for each channel, encoder, LCD expander, and statistics monitoring.
|
||||||
|
|
||||||
## Build and flash
|
## Build and flash
|
||||||
|
|
||||||
Run the following command to firmware build and flash module:
|
Run the following command to firmware build and flash module:
|
||||||
|
|
||||||
```text
|
```bash
|
||||||
cd your_projects_folder
|
cd your_projects_folder
|
||||||
git clone --recurse-submodules https://github.com/aZholtikov/ate0005
|
git clone --recurse-submodules https://github.com/aZholtikov/ate0005
|
||||||
cd ate0005
|
cd ate0005
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+3037
File diff suppressed because it is too large.
Load diff
+354126
File diff suppressed because it is too large.
Load diff
Submodule components/zh_160x_i2c deleted from 3077b35930.
Submodule components/zh_encoder deleted from 04aeb09e49.
Submodule components/zh_espnow deleted from af76d3172f.
Submodule components/zh_inclinometer deleted from 58a63d2f7d.
Submodule components/zh_ota_server deleted from ede39ad145.
Submodule components/zh_pcf8574 deleted from 828fcb9b7f.
Submodule components/zh_syslog deleted from 6105b97292.
Submodule components/zh_tachometer deleted from 2653b47f7c.
Submodule components/zh_vector deleted from a19e4da88a.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
|||||||
idf_component_register(SRCS "ate0005.c" INCLUDE_DIRS "" REQUIRES zh_160x_i2c zh_encoder zh_inclinometer zh_tachometer zh_espnow zh_ota_server zh_syslog esp_wifi nvs_flash esp_timer esp_app_format)
|
idf_component_register(SRCS "ate0005.c" INCLUDE_DIRS "" REQUIRES zh_160x_i2c zh_encoder zh_inclinometer zh_tachometer zh_espnow zh_ota_server zh_syslog zh_menu esp_wifi nvs_flash esp_timer esp_app_format)
|
||||||
+437
-198
@@ -1,17 +1,18 @@
|
|||||||
#include "ate0005.h"
|
#include "ate0005.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
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 handles ──────────────────────────────── */
|
||||||
|
|
||||||
static httpd_handle_t _http_server_handle = NULL;
|
static httpd_handle_t _http_server_handle = NULL;
|
||||||
|
static zh_pcf8574_handle_t *_lcd_handle = NULL;
|
||||||
static zh_pcf8574_handle_t _lcd_handle = {0};
|
static zh_160x_i2c_handle_t *_lcd_160x_handle = NULL;
|
||||||
static zh_encoder_handle_t _mode_encoder_handle = {0};
|
static zh_encoder_handle_t *_mode_encoder_handle = NULL;
|
||||||
static zh_inclinometer_handle_t _a_inclinometer_handle = {0};
|
static zh_inclinometer_handle_t *_a_inclinometer_handle = NULL;
|
||||||
static zh_inclinometer_handle_t _b_inclinometer_handle = {0};
|
static zh_inclinometer_handle_t *_b_inclinometer_handle = NULL;
|
||||||
static zh_tachometer_handle_t _a_tachometer_handle = {0};
|
static zh_tachometer_handle_t *_a_tachometer_handle = NULL;
|
||||||
static zh_tachometer_handle_t _b_tachometer_handle = {0};
|
static zh_tachometer_handle_t *_b_tachometer_handle = NULL;
|
||||||
static esp_timer_handle_t _inclinometer_reset_timer_handle = {0};
|
static esp_timer_handle_t _inclinometer_reset_timer_handle = {0};
|
||||||
|
|
||||||
static SemaphoreHandle_t _lcd_mutex = NULL;
|
static SemaphoreHandle_t _lcd_mutex = NULL;
|
||||||
static TaskHandle_t _a_inclinometer_task_handle = NULL;
|
static TaskHandle_t _a_inclinometer_task_handle = NULL;
|
||||||
static TaskHandle_t _b_inclinometer_task_handle = NULL;
|
static TaskHandle_t _b_inclinometer_task_handle = NULL;
|
||||||
@@ -19,10 +20,18 @@ static TaskHandle_t _a_tachometer_task_handle = NULL;
|
|||||||
static TaskHandle_t _b_tachometer_task_handle = NULL;
|
static TaskHandle_t _b_tachometer_task_handle = NULL;
|
||||||
static TaskHandle_t _zh_stats_task_handle = NULL;
|
static TaskHandle_t _zh_stats_task_handle = NULL;
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Menu handles ───────────────────────────────── */
|
||||||
|
|
||||||
|
static zh_menu_handle_t *_menu_handle = NULL;
|
||||||
|
static zh_menu_node_t _main_menu_tree[];
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Forward declarations ───────────────────────── */
|
||||||
|
|
||||||
static void _zh_wifi_init(void);
|
static void _zh_wifi_init(void);
|
||||||
static void _zh_webserver_init(void);
|
static void _zh_webserver_init(void);
|
||||||
static void _zh_espnow_init(void);
|
static void _zh_espnow_init(void);
|
||||||
static void _zh_encoder_init(void);
|
static void _zh_encoder_init(void);
|
||||||
|
static void _zh_menu_init(void);
|
||||||
static void _zh_a_inclinometer_init(void);
|
static void _zh_a_inclinometer_init(void);
|
||||||
static void _zh_b_inclinometer_init(void);
|
static void _zh_b_inclinometer_init(void);
|
||||||
static void _zh_a_tachometer_init(void);
|
static void _zh_a_tachometer_init(void);
|
||||||
@@ -34,35 +43,74 @@ 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_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_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_inclinometer_reset_timer_on_alarm_cb(void *arg);
|
||||||
|
|
||||||
static void _zh_a_inclinometer_processing_task(void *pvParameter);
|
static void _zh_a_inclinometer_processing_task(void *pvParameter);
|
||||||
static void _zh_b_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_a_tachometer_processing_task(void *pvParameter);
|
||||||
static void _zh_b_tachometer_processing_task(void *pvParameter);
|
static void _zh_b_tachometer_processing_task(void *pvParameter);
|
||||||
static void _zh_stats_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};
|
/* Menu callbacks */
|
||||||
volatile static bool _is_menu_mode = false;
|
static void _menu_enter_cb(void *arg);
|
||||||
|
static void _menu_exit_cb(void *arg);
|
||||||
|
static void _menu_change_cb(zh_menu_node_t *current_node, uint8_t current_index);
|
||||||
|
static void _menu_select_angle_angle(void *arg);
|
||||||
|
static void _menu_select_tacho_tacho(void *arg);
|
||||||
|
static void _menu_select_angle_tacho(void *arg);
|
||||||
|
static void _menu_select_remote(void *arg);
|
||||||
|
static void _menu_select_exit(void *arg);
|
||||||
|
|
||||||
|
/* ──────────────────────────────── State variables ───────────────────────────── */
|
||||||
|
|
||||||
|
volatile static task_stats_t _task_stats = {0};
|
||||||
volatile static bool _is_reset_mode = false;
|
volatile static bool _is_reset_mode = false;
|
||||||
volatile static bool _is_reset_occurred = false;
|
volatile static bool _is_reset_occurred = false;
|
||||||
volatile static uint8_t _current_menu_value = 0;
|
volatile static uint8_t _current_menu_value = MODE_ANGLE_ANGLE; /* active mode, not menu index */
|
||||||
volatile static uint8_t _wifi_reconnect_retry_num = 0;
|
volatile static uint8_t _wifi_reconnect_retry_num = 0;
|
||||||
volatile static bool _is_wifi_connected = false;
|
volatile static bool _is_wifi_connected = false;
|
||||||
|
|
||||||
|
/* Task-stop flags for graceful termination */
|
||||||
|
volatile static bool _stop_a_inclinometer = false;
|
||||||
|
volatile static bool _stop_b_inclinometer = false;
|
||||||
|
volatile static bool _stop_a_tachometer = false;
|
||||||
|
volatile static bool _stop_b_tachometer = false;
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Menu tree definition ──────────────────────── */
|
||||||
|
|
||||||
|
static zh_menu_node_t _main_menu_tree[] = {
|
||||||
|
{.label = MAIN_MENU_ANGLE_ANGLE_NAME, .item_cb = &_menu_select_angle_angle},
|
||||||
|
{.label = MAIN_MENU_TACHO_TACHO_NAME, .item_cb = &_menu_select_tacho_tacho},
|
||||||
|
{.label = MAIN_MENU_ANGLE_TACHO_NAME, .item_cb = &_menu_select_angle_tacho},
|
||||||
|
{.label = MAIN_MENU_REMOTE_NAME, .item_cb = &_menu_select_remote},
|
||||||
|
{.label = "Exit", .item_cb = &_menu_select_exit},
|
||||||
|
};
|
||||||
|
|
||||||
|
static zh_menu_node_t _root_menu = {
|
||||||
|
.label = "MODE",
|
||||||
|
.submenu = _main_menu_tree,
|
||||||
|
.item_numbers = sizeof(_main_menu_tree) / sizeof(_main_menu_tree[0]),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ──────────────────────────────── app_main ───────────────────────────────────── */
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
_lcd_mutex = xSemaphoreCreateMutex();
|
esp_err_t err = nvs_flash_init();
|
||||||
nvs_flash_init();
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
||||||
|
{
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
|
}
|
||||||
esp_event_loop_create_default();
|
esp_event_loop_create_default();
|
||||||
_zh_wifi_init();
|
|
||||||
_zh_webserver_init();
|
|
||||||
_zh_pcf8574_init();
|
_zh_pcf8574_init();
|
||||||
_zh_system_load();
|
_zh_system_load();
|
||||||
_zh_encoder_init();
|
_zh_encoder_init();
|
||||||
_zh_a_inclinometer_init();
|
|
||||||
_zh_b_inclinometer_init();
|
|
||||||
_zh_espnow_init();
|
|
||||||
_zh_timer_init();
|
_zh_timer_init();
|
||||||
|
_zh_menu_init();
|
||||||
|
_zh_a_inclinometer_init(); /* start with default mode */
|
||||||
|
_zh_b_inclinometer_init();
|
||||||
|
_zh_wifi_init();
|
||||||
|
_zh_webserver_init();
|
||||||
|
_zh_espnow_init();
|
||||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||||
esp_ota_img_states_t ota_state = {0};
|
esp_ota_img_states_t ota_state = {0};
|
||||||
esp_ota_get_state_partition(running, &ota_state);
|
esp_ota_get_state_partition(running, &ota_state);
|
||||||
@@ -73,13 +121,16 @@ void app_main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── WiFi ───────────────────────────────────────── */
|
||||||
|
|
||||||
static void _zh_wifi_init(void)
|
static void _zh_wifi_init(void)
|
||||||
{
|
{
|
||||||
esp_netif_init();
|
esp_netif_init();
|
||||||
esp_netif_create_default_wifi_ap();
|
esp_netif_create_default_wifi_ap();
|
||||||
esp_netif_create_default_wifi_sta();
|
esp_netif_create_default_wifi_sta();
|
||||||
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
|
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
esp_wifi_init(&wifi_init_config);
|
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
|
||||||
|
|
||||||
wifi_config_t wifi_ap_config = {
|
wifi_config_t wifi_ap_config = {
|
||||||
.ap.ssid = WIFI_AP_SSID,
|
.ap.ssid = WIFI_AP_SSID,
|
||||||
.ap.password = WIFI_AP_PASS,
|
.ap.password = WIFI_AP_PASS,
|
||||||
@@ -91,18 +142,20 @@ static void _zh_wifi_init(void)
|
|||||||
.sta.ssid = WIFI_STA_SSID,
|
.sta.ssid = WIFI_STA_SSID,
|
||||||
.sta.password = WIFI_STA_PASS,
|
.sta.password = WIFI_STA_PASS,
|
||||||
};
|
};
|
||||||
esp_wifi_set_mode(WIFI_MODE_APSTA);
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
|
||||||
esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config);
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config));
|
||||||
esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config);
|
ESP_ERROR_CHECK(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(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_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &_zh_wifi_event_handler, NULL, NULL);
|
||||||
esp_wifi_start();
|
ESP_ERROR_CHECK(esp_wifi_start());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Web server ─────────────────────────────────── */
|
||||||
|
|
||||||
static void _zh_webserver_init(void)
|
static void _zh_webserver_init(void)
|
||||||
{
|
{
|
||||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||||
httpd_start(&_http_server_handle, &config);
|
ESP_ERROR_CHECK(httpd_start(&_http_server_handle, &config));
|
||||||
zh_ota_server_init(_http_server_handle, "/");
|
zh_ota_server_init(_http_server_handle, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +164,8 @@ static void _zh_espnow_init(void)
|
|||||||
// To Do.
|
// To Do.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Encoder ────────────────────────────────────── */
|
||||||
|
|
||||||
static void _zh_encoder_init(void)
|
static void _zh_encoder_init(void)
|
||||||
{
|
{
|
||||||
esp_event_handler_instance_register(ZH_ENCODER, ESP_EVENT_ANY_ID, &_zh_encoder_event_handler, NULL, NULL);
|
esp_event_handler_instance_register(ZH_ENCODER, ESP_EVENT_ANY_ID, &_zh_encoder_event_handler, NULL, NULL);
|
||||||
@@ -123,56 +178,31 @@ static void _zh_encoder_init(void)
|
|||||||
config.s_gpio_number = MODE_ENCODER_S_GPIO;
|
config.s_gpio_number = MODE_ENCODER_S_GPIO;
|
||||||
config.s_gpio_debounce_time = 1000;
|
config.s_gpio_debounce_time = 1000;
|
||||||
config.encoder_min_value = 0;
|
config.encoder_min_value = 0;
|
||||||
config.encoder_max_value = (sizeof(_main_menu) / sizeof(_main_menu[0])) - 1;
|
config.encoder_max_value = 3;
|
||||||
config.encoder_step = 1;
|
config.encoder_step = 1;
|
||||||
config.encoder_number = MODE_ENCODER_NUMBER;
|
config.encoder_number = MODE_ENCODER_NUMBER;
|
||||||
zh_encoder_init(&config, &_mode_encoder_handle);
|
zh_encoder_init(&config, &_mode_encoder_handle);
|
||||||
zh_encoder_set(&_mode_encoder_handle, 0);
|
zh_encoder_set(&_mode_encoder_handle, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _zh_a_inclinometer_init(void)
|
/* ──────────────────────────────── Menu ───────────────────────────────────────── */
|
||||||
|
|
||||||
|
static void _zh_menu_init(void)
|
||||||
{
|
{
|
||||||
zh_inclinometer_init_config_t config = ZH_INCLINOMETER_INIT_CONFIG_DEFAULT();
|
zh_menu_init_config_t config = ZH_MENU_INIT_CONFIG_DEFAULT();
|
||||||
config.a_gpio_number = A_OPTICAL_DEVICE_A_GPIO;
|
config.task_priority = MENU_TASK_PRIORITY;
|
||||||
config.b_gpio_number = A_OPTICAL_DEVICE_B_GPIO;
|
config.stack_size = MENU_TASK_STACK_SIZE;
|
||||||
config.encoder_pulses = 3600;
|
config.queue_size = 10;
|
||||||
zh_inclinometer_init(&config, &_a_inclinometer_handle);
|
config.root = &_root_menu;
|
||||||
xTaskCreatePinnedToCore(&_zh_a_inclinometer_processing_task, "a_inclinometer_processing_task", A_INCLINOMETER_TASK_STACK_SIZE, NULL, A_INCLINOMETER_TASK_PRIORITY,
|
config.loop = false; /* no wrap-around, so "Exit" is at the end */
|
||||||
&_a_inclinometer_task_handle, tskNO_AFFINITY);
|
config.viewport_rows = 1; /* LCD 16x2: row 0 = header, row 1 = one item */
|
||||||
|
config.enter_cb = &_menu_enter_cb;
|
||||||
|
config.exit_cb = &_menu_exit_cb;
|
||||||
|
config.change_cb = &_menu_change_cb;
|
||||||
|
ESP_ERROR_CHECK(zh_menu_init(&config, &_menu_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _zh_b_inclinometer_init(void)
|
/* ──────────────────────────────── PCF8574 / LCD ──────────────────────────────── */
|
||||||
{
|
|
||||||
zh_inclinometer_init_config_t config = ZH_INCLINOMETER_INIT_CONFIG_DEFAULT();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _zh_pcf8574_init(void)
|
static void _zh_pcf8574_init(void)
|
||||||
{
|
{
|
||||||
@@ -184,58 +214,92 @@ static void _zh_pcf8574_init(void)
|
|||||||
.glitch_ignore_cnt = 7,
|
.glitch_ignore_cnt = 7,
|
||||||
.flags.enable_internal_pullup = true,
|
.flags.enable_internal_pullup = true,
|
||||||
};
|
};
|
||||||
i2c_new_master_bus(&i2c_bus_config, &_i2c_bus_handle);
|
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &_i2c_bus_handle));
|
||||||
zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
|
zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
|
||||||
config.task_priority = EXPANDER_TASK_PRIORITY;
|
config.task_priority = EXPANDER_TASK_PRIORITY;
|
||||||
config.stack_size = EXPANDER_TASK_STACK_SIZE;
|
config.stack_size = EXPANDER_TASK_STACK_SIZE;
|
||||||
config.i2c_handle = _i2c_bus_handle;
|
config.i2c_handle = _i2c_bus_handle;
|
||||||
config.i2c_address = LCD_I2C_ADDRESS;
|
config.i2c_address = LCD_I2C_ADDRESS;
|
||||||
zh_pcf8574_init(&config, &_lcd_handle);
|
zh_pcf8574_init(&config, &_lcd_handle);
|
||||||
zh_160x_init(&_lcd_handle, ZH_LCD_16X2);
|
zh_160x_init(&_lcd_handle, &_lcd_160x_handle, ZH_LCD_16X2);
|
||||||
|
_lcd_mutex = xSemaphoreCreateMutex();
|
||||||
|
configASSERT(_lcd_mutex != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _zh_system_load(void)
|
static void _zh_system_load(void)
|
||||||
{
|
{
|
||||||
zh_160x_set_cursor(&_lcd_handle, 0, 0);
|
zh_160x_set_cursor(&_lcd_160x_handle, 0, 0);
|
||||||
zh_160x_print_char(&_lcd_handle, "LLC AEROTECH");
|
zh_160x_print_char(&_lcd_160x_handle, "LLC AEROTECH");
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 0);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 0);
|
||||||
const esp_app_desc_t *esp_app_desc = esp_app_get_description();
|
const esp_app_desc_t *esp_app_desc = esp_app_get_description();
|
||||||
zh_160x_print_char(&_lcd_handle, esp_app_desc->project_name);
|
zh_160x_print_char(&_lcd_160x_handle, esp_app_desc->project_name);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 8);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 8);
|
||||||
zh_160x_print_char(&_lcd_handle, "V");
|
zh_160x_print_char(&_lcd_160x_handle, "V");
|
||||||
zh_160x_print_char(&_lcd_handle, esp_app_desc->version);
|
zh_160x_print_char(&_lcd_160x_handle, esp_app_desc->version);
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
zh_160x_lcd_clear(&_lcd_handle);
|
zh_160x_lcd_clear(&_lcd_160x_handle);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 0, 0);
|
zh_160x_set_cursor(&_lcd_160x_handle, 0, 0);
|
||||||
zh_160x_print_char(&_lcd_handle, "SYSTEM LOADING:");
|
zh_160x_print_char(&_lcd_160x_handle, "SYSTEM LOADING:");
|
||||||
for (uint8_t i = 0; i <= 100; i += 10)
|
for (uint8_t i = 0; i <= 100; i += 10)
|
||||||
{
|
{
|
||||||
zh_160x_print_progress_bar(&_lcd_handle, 1, i);
|
zh_160x_print_progress_bar(&_lcd_160x_handle, 1, i);
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
zh_160x_lcd_clear(&_lcd_handle);
|
zh_160x_lcd_clear(&_lcd_160x_handle);
|
||||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 0, 0);
|
zh_160x_set_cursor(&_lcd_160x_handle, 0, 0);
|
||||||
zh_160x_print_char(&_lcd_handle, "MODE:");
|
zh_160x_print_char(&_lcd_160x_handle, "MODE:");
|
||||||
zh_160x_print_char(&_lcd_handle, _main_menu[0]);
|
zh_160x_print_char(&_lcd_160x_handle, _main_menu_tree[0].label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Timer ──────────────────────────────────────── */
|
||||||
|
|
||||||
static void _zh_timer_init(void)
|
static void _zh_timer_init(void)
|
||||||
{
|
{
|
||||||
const esp_timer_create_args_t timer_args = {
|
const esp_timer_create_args_t timer_args = {
|
||||||
.callback = &_zh_inclinometer_reset_timer_on_alarm_cb,
|
.callback = &_zh_inclinometer_reset_timer_on_alarm_cb,
|
||||||
};
|
};
|
||||||
esp_timer_create(&timer_args, &_inclinometer_reset_timer_handle);
|
ESP_ERROR_CHECK(esp_timer_create(&timer_args, &_inclinometer_reset_timer_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Task stopping helpers ──────────────────────── */
|
||||||
|
|
||||||
|
static void _stop_all_processing_tasks(void)
|
||||||
|
{
|
||||||
|
_stop_a_inclinometer = true;
|
||||||
|
_stop_b_inclinometer = true;
|
||||||
|
_stop_a_tachometer = true;
|
||||||
|
_stop_b_tachometer = true;
|
||||||
|
|
||||||
|
/* Give tasks up to 200 ms to exit their loops and call vTaskDelete(NULL) */
|
||||||
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
_stop_a_inclinometer = false;
|
||||||
|
_stop_b_inclinometer = false;
|
||||||
|
_stop_a_tachometer = false;
|
||||||
|
_stop_b_tachometer = false;
|
||||||
|
|
||||||
|
_a_inclinometer_task_handle = NULL;
|
||||||
|
_b_inclinometer_task_handle = NULL;
|
||||||
|
_a_tachometer_task_handle = NULL;
|
||||||
|
_b_tachometer_task_handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Encoder event handler ──────────────────────── */
|
||||||
|
|
||||||
static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||||
{
|
{
|
||||||
|
(void)arg;
|
||||||
|
zh_menu_status_t menu_status = {0};
|
||||||
|
zh_menu_get(&_menu_handle, &menu_status);
|
||||||
|
|
||||||
switch (event_id)
|
switch (event_id)
|
||||||
{
|
{
|
||||||
case ZH_BUTTON_EVENT:
|
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);
|
esp_timer_start_once(_inclinometer_reset_timer_handle, 2000000);
|
||||||
_is_reset_mode = true;
|
_is_reset_mode = true;
|
||||||
@@ -252,42 +316,71 @@ static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, in
|
|||||||
esp_timer_stop(_inclinometer_reset_timer_handle);
|
esp_timer_stop(_inclinometer_reset_timer_handle);
|
||||||
_is_reset_mode = false;
|
_is_reset_mode = false;
|
||||||
}
|
}
|
||||||
_is_menu_mode = !_is_menu_mode;
|
|
||||||
if (_is_menu_mode == true)
|
if (menu_status.is_active == false)
|
||||||
{
|
{
|
||||||
switch (_current_menu_value)
|
zh_menu_set(&_menu_handle, ZH_MENU_ENTER, NULL, 0);
|
||||||
{
|
|
||||||
case MODE_ANGLE_ANGLE:
|
|
||||||
vTaskDelete(_a_inclinometer_task_handle);
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
zh_inclinometer_deinit(&_a_inclinometer_handle);
|
|
||||||
zh_tachometer_deinit(&_b_tachometer_handle);
|
|
||||||
break;
|
|
||||||
case MODE_REMOTE:
|
|
||||||
// To Do.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
zh_160x_clear_row(&_lcd_handle, 1);
|
else if (menu_status.is_selected == false)
|
||||||
zh_160x_set_cursor(&_lcd_handle, 0, 0);
|
{
|
||||||
zh_160x_on_cursor(&_lcd_handle, true);
|
zh_menu_set(&_menu_handle, ZH_MENU_SELECT, NULL, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zh_160x_off_cursor(&_lcd_handle);
|
zh_menu_set(&_menu_handle, ZH_MENU_BACK, NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZH_ENCODER_EVENT:
|
||||||
|
{
|
||||||
|
zh_encoder_event_on_isr_t *encoder_event = (zh_encoder_event_on_isr_t *)event_data;
|
||||||
|
if (menu_status.is_active == true)
|
||||||
|
{
|
||||||
|
if (menu_status.is_selected == true)
|
||||||
|
{
|
||||||
|
zh_menu_set(&_menu_handle, ZH_MENU_SELECT, encoder_event, sizeof(zh_encoder_event_on_isr_t));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (encoder_event->encoder_status == true)
|
||||||
|
{
|
||||||
|
zh_menu_set(&_menu_handle, ZH_MENU_UP, NULL, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
zh_menu_set(&_menu_handle, ZH_MENU_DOWN, NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
zh_encoder_set(&_mode_encoder_handle, (float)_current_menu_value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Menu callbacks ────────────────────────────── */
|
||||||
|
|
||||||
|
static void _menu_enter_cb(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
|
zh_160x_on_cursor(&_lcd_160x_handle, true);
|
||||||
|
xSemaphoreGive(_lcd_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _menu_exit_cb(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
|
zh_160x_off_cursor(&_lcd_160x_handle);
|
||||||
|
xSemaphoreGive(_lcd_mutex);
|
||||||
|
_stop_all_processing_tasks();
|
||||||
switch (_current_menu_value)
|
switch (_current_menu_value)
|
||||||
{
|
{
|
||||||
case MODE_ANGLE_ANGLE:
|
case MODE_ANGLE_ANGLE:
|
||||||
@@ -303,43 +396,109 @@ static void _zh_encoder_event_handler(void *arg, esp_event_base_t event_base, in
|
|||||||
_zh_b_tachometer_init();
|
_zh_b_tachometer_init();
|
||||||
break;
|
break;
|
||||||
case MODE_REMOTE:
|
case MODE_REMOTE:
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 0);
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
zh_160x_print_char(&_lcd_handle, "NOT CONNECTED");
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 0);
|
||||||
break;
|
zh_160x_print_char(&_lcd_160x_handle, "NOT CONNECTED");
|
||||||
default:
|
xSemaphoreGive(_lcd_mutex);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZH_ENCODER_EVENT:
|
|
||||||
zh_encoder_event_on_isr_t *encoder_event = event_data;
|
|
||||||
if (_is_menu_mode == true)
|
|
||||||
{
|
|
||||||
_current_menu_value = (uint8_t)encoder_event->encoder_position; // -V2004
|
|
||||||
zh_160x_clear_row(&_lcd_handle, 0);
|
|
||||||
zh_160x_set_cursor(&_lcd_handle, 0, 0);
|
|
||||||
zh_160x_print_char(&_lcd_handle, "MODE:");
|
|
||||||
zh_160x_print_char(&_lcd_handle, _main_menu[(uint8_t)encoder_event->encoder_position]); // -V2004
|
|
||||||
zh_160x_set_cursor(&_lcd_handle, 0, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
zh_encoder_set(&_mode_encoder_handle, (float)_current_menu_value);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
static void _menu_change_cb(zh_menu_node_t *current_node, uint8_t current_index)
|
||||||
{
|
{
|
||||||
// To Do.
|
zh_menu_view_t view = {0};
|
||||||
|
zh_menu_get_view(&_menu_handle, &view);
|
||||||
|
|
||||||
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
/* Header row */
|
||||||
|
zh_160x_clear_row(&_lcd_160x_handle, 0);
|
||||||
|
zh_160x_set_cursor(&_lcd_160x_handle, 0, 0);
|
||||||
|
zh_160x_print_char(&_lcd_160x_handle, "MODE:");
|
||||||
|
|
||||||
|
/* Single visible item row (viewport_rows = 1) */
|
||||||
|
zh_160x_clear_row(&_lcd_160x_handle, 1);
|
||||||
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 0);
|
||||||
|
|
||||||
|
uint8_t idx = view.first_visible;
|
||||||
|
char line[17] = {0};
|
||||||
|
snprintf(line, sizeof(line), "%c%s",
|
||||||
|
(idx == current_index) ? '>' : ' ',
|
||||||
|
current_node->submenu[idx].label);
|
||||||
|
zh_160x_print_char(&_lcd_160x_handle, line);
|
||||||
|
|
||||||
|
/* Hidden-item indicators */
|
||||||
|
if (view.first_visible > 0)
|
||||||
|
{
|
||||||
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 15);
|
||||||
|
zh_160x_print_char(&_lcd_160x_handle, "^");
|
||||||
|
}
|
||||||
|
if ((uint8_t)(view.first_visible + view.visible_count) < current_node->item_numbers)
|
||||||
|
{
|
||||||
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 15);
|
||||||
|
zh_160x_print_char(&_lcd_160x_handle, "v");
|
||||||
|
}
|
||||||
|
|
||||||
|
xSemaphoreGive(_lcd_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _menu_select_angle_angle(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
_stop_all_processing_tasks();
|
||||||
|
_current_menu_value = MODE_ANGLE_ANGLE;
|
||||||
|
_zh_a_inclinometer_init();
|
||||||
|
_zh_b_inclinometer_init();
|
||||||
|
zh_menu_set(&_menu_handle, ZH_MENU_BACK, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _menu_select_tacho_tacho(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
_stop_all_processing_tasks();
|
||||||
|
_current_menu_value = MODE_TACHO_TACHO;
|
||||||
|
_zh_a_tachometer_init();
|
||||||
|
_zh_b_tachometer_init();
|
||||||
|
zh_menu_set(&_menu_handle, ZH_MENU_BACK, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _menu_select_angle_tacho(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
_stop_all_processing_tasks();
|
||||||
|
_current_menu_value = MODE_ANGLE_TACHO;
|
||||||
|
_zh_a_inclinometer_init();
|
||||||
|
_zh_b_tachometer_init();
|
||||||
|
zh_menu_set(&_menu_handle, ZH_MENU_BACK, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _menu_select_remote(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
_stop_all_processing_tasks();
|
||||||
|
_current_menu_value = MODE_REMOTE;
|
||||||
|
/* TODO: initialise ESP-NOW remote mode */
|
||||||
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 0);
|
||||||
|
zh_160x_print_char(&_lcd_160x_handle, "NOT CONNECTED");
|
||||||
|
xSemaphoreGive(_lcd_mutex);
|
||||||
|
zh_menu_set(&_menu_handle, ZH_MENU_BACK, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _menu_select_exit(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
zh_menu_set(&_menu_handle, ZH_MENU_BACK, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── WiFi event handler ────────────────────────── */
|
||||||
|
|
||||||
static void _zh_wifi_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)
|
||||||
{
|
{
|
||||||
|
(void)arg;
|
||||||
|
(void)event_data;
|
||||||
switch (event_id)
|
switch (event_id)
|
||||||
{
|
{
|
||||||
case WIFI_EVENT_STA_START:
|
case WIFI_EVENT_STA_START:
|
||||||
@@ -347,8 +506,12 @@ static void _zh_wifi_event_handler(void *arg, esp_event_base_t event_base, int32
|
|||||||
break;
|
break;
|
||||||
case WIFI_EVENT_STA_DISCONNECTED:
|
case WIFI_EVENT_STA_DISCONNECTED:
|
||||||
if (_is_wifi_connected == true)
|
if (_is_wifi_connected == true)
|
||||||
|
{
|
||||||
|
if (_zh_stats_task_handle != NULL)
|
||||||
{
|
{
|
||||||
vTaskDelete(_zh_stats_task_handle);
|
vTaskDelete(_zh_stats_task_handle);
|
||||||
|
_zh_stats_task_handle = NULL; /* critical: vTaskDelete does NOT NULL the handle */
|
||||||
|
}
|
||||||
zh_syslog_deinit();
|
zh_syslog_deinit();
|
||||||
_is_wifi_connected = false;
|
_is_wifi_connected = false;
|
||||||
}
|
}
|
||||||
@@ -362,21 +525,30 @@ static void _zh_wifi_event_handler(void *arg, esp_event_base_t event_base, int32
|
|||||||
_wifi_reconnect_retry_num = 0;
|
_wifi_reconnect_retry_num = 0;
|
||||||
_is_wifi_connected = true;
|
_is_wifi_connected = true;
|
||||||
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT();
|
||||||
strcpy(config.syslog_ip, SYSLOG_IP);
|
snprintf(config.syslog_ip, sizeof(config.syslog_ip), "%s", SYSLOG_IP);
|
||||||
zh_syslog_init(&config);
|
zh_syslog_init(&config);
|
||||||
|
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);
|
xTaskCreatePinnedToCore(&_zh_stats_processing_task, "stats_processing_task", STATS_TASK_STACK_SIZE, NULL, STATS_TASK_PRIORITY, &_zh_stats_task_handle, tskNO_AFFINITY);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Reset timer callback ──────────────────────── */
|
||||||
|
|
||||||
static void _zh_inclinometer_reset_timer_on_alarm_cb(void *arg)
|
static void _zh_inclinometer_reset_timer_on_alarm_cb(void *arg)
|
||||||
{
|
{
|
||||||
|
(void)arg;
|
||||||
_is_reset_mode = false;
|
_is_reset_mode = false;
|
||||||
_is_reset_occurred = true;
|
|
||||||
if (_is_menu_mode == false)
|
zh_menu_status_t menu_status = {0};
|
||||||
|
zh_menu_get(&_menu_handle, &menu_status);
|
||||||
|
if (menu_status.is_active == false)
|
||||||
{
|
{
|
||||||
|
_is_reset_occurred = true;
|
||||||
switch (_current_menu_value)
|
switch (_current_menu_value)
|
||||||
{
|
{
|
||||||
case MODE_ANGLE_ANGLE:
|
case MODE_ANGLE_ANGLE:
|
||||||
@@ -392,25 +564,79 @@ static void _zh_inclinometer_reset_timer_on_alarm_cb(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ──────────────────────────────── Processing tasks ──────────────────────────── */
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
static void _zh_a_inclinometer_processing_task(void *pvParameter)
|
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);
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 0);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 0);
|
||||||
zh_160x_print_char(&_lcd_handle, "A:");
|
zh_160x_print_char(&_lcd_160x_handle, "A:");
|
||||||
zh_160x_print_float(&_lcd_handle, current_angle, 1);
|
zh_160x_print_float(&_lcd_160x_handle, current_angle, 1);
|
||||||
xSemaphoreGive(_lcd_mutex);
|
xSemaphoreGive(_lcd_mutex);
|
||||||
for (;;)
|
|
||||||
|
while (!_stop_a_inclinometer)
|
||||||
{
|
{
|
||||||
zh_inclinometer_get(&_a_inclinometer_handle, ¤t_angle);
|
zh_inclinometer_get(&_a_inclinometer_handle, ¤t_angle);
|
||||||
if (prev_angle != current_angle)
|
if (prev_angle != current_angle)
|
||||||
{
|
{
|
||||||
prev_angle = current_angle;
|
prev_angle = current_angle;
|
||||||
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 5);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 5);
|
||||||
zh_160x_print_char(&_lcd_handle, " ");
|
zh_160x_print_char(&_lcd_160x_handle, " ");
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 2);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 2);
|
||||||
zh_160x_print_float(&_lcd_handle, current_angle, 1);
|
zh_160x_print_float(&_lcd_160x_handle, current_angle, 1);
|
||||||
xSemaphoreGive(_lcd_mutex);
|
xSemaphoreGive(_lcd_mutex);
|
||||||
}
|
}
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
@@ -421,23 +647,27 @@ static void _zh_a_inclinometer_processing_task(void *pvParameter)
|
|||||||
|
|
||||||
static void _zh_b_inclinometer_processing_task(void *pvParameter)
|
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);
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 8);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 8);
|
||||||
zh_160x_print_char(&_lcd_handle, "B:");
|
zh_160x_print_char(&_lcd_160x_handle, "B:");
|
||||||
zh_160x_print_float(&_lcd_handle, current_angle, 1);
|
zh_160x_print_float(&_lcd_160x_handle, current_angle, 1);
|
||||||
xSemaphoreGive(_lcd_mutex);
|
xSemaphoreGive(_lcd_mutex);
|
||||||
for (;;)
|
|
||||||
|
while (!_stop_b_inclinometer)
|
||||||
{
|
{
|
||||||
zh_inclinometer_get(&_b_inclinometer_handle, ¤t_angle);
|
zh_inclinometer_get(&_b_inclinometer_handle, ¤t_angle);
|
||||||
if (prev_angle != current_angle)
|
if (prev_angle != current_angle)
|
||||||
{
|
{
|
||||||
prev_angle = current_angle;
|
prev_angle = current_angle;
|
||||||
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 13);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 13);
|
||||||
zh_160x_print_char(&_lcd_handle, " ");
|
zh_160x_print_char(&_lcd_160x_handle, " ");
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 10);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 10);
|
||||||
zh_160x_print_float(&_lcd_handle, current_angle, 1);
|
zh_160x_print_float(&_lcd_160x_handle, current_angle, 1);
|
||||||
xSemaphoreGive(_lcd_mutex);
|
xSemaphoreGive(_lcd_mutex);
|
||||||
}
|
}
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
@@ -448,23 +678,27 @@ static void _zh_b_inclinometer_processing_task(void *pvParameter)
|
|||||||
|
|
||||||
static void _zh_a_tachometer_processing_task(void *pvParameter)
|
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);
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 0);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 0);
|
||||||
zh_160x_print_char(&_lcd_handle, "A:");
|
zh_160x_print_char(&_lcd_160x_handle, "A:");
|
||||||
zh_160x_print_int(&_lcd_handle, current_rpm);
|
zh_160x_print_int(&_lcd_160x_handle, current_rpm);
|
||||||
xSemaphoreGive(_lcd_mutex);
|
xSemaphoreGive(_lcd_mutex);
|
||||||
for (;;)
|
|
||||||
|
while (!_stop_a_tachometer)
|
||||||
{
|
{
|
||||||
zh_tachometer_get(&_a_tachometer_handle, ¤t_rpm);
|
zh_tachometer_get(&_a_tachometer_handle, ¤t_rpm);
|
||||||
if (prev_rpm != current_rpm)
|
if (prev_rpm != current_rpm)
|
||||||
{
|
{
|
||||||
prev_rpm = current_rpm;
|
prev_rpm = current_rpm;
|
||||||
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 3);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 3);
|
||||||
zh_160x_print_char(&_lcd_handle, " ");
|
zh_160x_print_char(&_lcd_160x_handle, " ");
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 2);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 2);
|
||||||
zh_160x_print_int(&_lcd_handle, current_rpm);
|
zh_160x_print_int(&_lcd_160x_handle, current_rpm);
|
||||||
xSemaphoreGive(_lcd_mutex);
|
xSemaphoreGive(_lcd_mutex);
|
||||||
}
|
}
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
@@ -475,23 +709,27 @@ static void _zh_a_tachometer_processing_task(void *pvParameter)
|
|||||||
|
|
||||||
static void _zh_b_tachometer_processing_task(void *pvParameter)
|
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);
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 8);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 8);
|
||||||
zh_160x_print_char(&_lcd_handle, "B:");
|
zh_160x_print_char(&_lcd_160x_handle, "B:");
|
||||||
zh_160x_print_int(&_lcd_handle, current_rpm);
|
zh_160x_print_int(&_lcd_160x_handle, current_rpm);
|
||||||
xSemaphoreGive(_lcd_mutex);
|
xSemaphoreGive(_lcd_mutex);
|
||||||
for (;;)
|
|
||||||
|
while (!_stop_b_tachometer)
|
||||||
{
|
{
|
||||||
zh_tachometer_get(&_b_tachometer_handle, ¤t_rpm);
|
zh_tachometer_get(&_b_tachometer_handle, ¤t_rpm);
|
||||||
if (prev_rpm != current_rpm)
|
if (prev_rpm != current_rpm)
|
||||||
{
|
{
|
||||||
prev_rpm = current_rpm;
|
prev_rpm = current_rpm;
|
||||||
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
xSemaphoreTake(_lcd_mutex, portMAX_DELAY);
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 11);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 11);
|
||||||
zh_160x_print_char(&_lcd_handle, " ");
|
zh_160x_print_char(&_lcd_160x_handle, " ");
|
||||||
zh_160x_set_cursor(&_lcd_handle, 1, 10);
|
zh_160x_set_cursor(&_lcd_160x_handle, 1, 10);
|
||||||
zh_160x_print_int(&_lcd_handle, current_rpm);
|
zh_160x_print_int(&_lcd_160x_handle, current_rpm);
|
||||||
xSemaphoreGive(_lcd_mutex);
|
xSemaphoreGive(_lcd_mutex);
|
||||||
}
|
}
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
@@ -502,49 +740,50 @@ static void _zh_b_tachometer_processing_task(void *pvParameter)
|
|||||||
|
|
||||||
static void _zh_stats_processing_task(void *pvParameter)
|
static void _zh_stats_processing_task(void *pvParameter)
|
||||||
{
|
{
|
||||||
|
(void)pvParameter;
|
||||||
const esp_app_desc_t *esp_app_desc = esp_app_get_description();
|
const esp_app_desc_t *esp_app_desc = esp_app_get_description();
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
char buffer[1024] = {0};
|
char buffer[1024] = {0};
|
||||||
const zh_encoder_stats_t *encoder_stats = zh_encoder_get_stats();
|
const zh_encoder_stats_t *encoder_stats = zh_encoder_get_stats();
|
||||||
const zh_pcf8574_stats_t *pcf8574_stats = zh_pcf8574_get_stats();
|
const zh_pcf8574_stats_t *pcf8574_stats = zh_pcf8574_get_stats();
|
||||||
sprintf(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", (unsigned long)_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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(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", (unsigned long)_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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(buffer, "A tachometer task minimum free stack size: %ld.\n", _task_stats.b_tachometer_task_min_stack_size);
|
snprintf(buffer, sizeof(buffer), "A tachometer task minimum free stack size: %lu.\n", (unsigned long)_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: %lu.\n", (unsigned long)_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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(buffer, "B tachometer task minimum free stack size: %ld.\n", _task_stats.b_tachometer_task_min_stack_size);
|
snprintf(buffer, sizeof(buffer), "Stats task minimum free stack size: %lu.\n", (unsigned long)uxTaskGetStackHighWaterMark(NULL));
|
||||||
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);
|
|
||||||
sprintf(buffer, "Stats task minimum free stack size: %ld.\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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(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", (unsigned long)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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(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", (unsigned long)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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(buffer, "Number of event post error: %ld.\n", encoder_stats->event_post_error);
|
snprintf(buffer, sizeof(buffer), "Number of event post error: %lu.\n", (unsigned long)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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(buffer, "Number of queue overflow error: %ld.\n", encoder_stats->queue_overflow_error);
|
snprintf(buffer, sizeof(buffer), "Number of queue overflow error: %lu.\n", (unsigned long)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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(buffer, "Number of i2c driver error: %ld.\n", pcf8574_stats->i2c_driver_error);
|
snprintf(buffer, sizeof(buffer), "Number of i2c driver error: %lu.\n", (unsigned long)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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(buffer, "Number of event post error: %ld.\n", pcf8574_stats->event_post_error);
|
snprintf(buffer, sizeof(buffer), "Number of event post error: %lu.\n", (unsigned long)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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(buffer, "Number of vector error: %ld.\n", pcf8574_stats->vector_error);
|
snprintf(buffer, sizeof(buffer), "Number of vector error: %lu.\n", (unsigned long)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);
|
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);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
sprintf(buffer, "Number of queue overflow error: %ld.\n", pcf8574_stats->queue_overflow_error);
|
snprintf(buffer, sizeof(buffer), "Number of queue overflow error: %lu.\n", (unsigned long)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);
|
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);
|
vTaskDelay(60000 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
|||||||
+75
-53
@@ -1,5 +1,18 @@
|
|||||||
/**
|
/**
|
||||||
* @file ate0005.h
|
* @file ate0005.h
|
||||||
|
*
|
||||||
|
* @brief Header file for ATE0005 — Universal Optical 2-Channel Angle Gauge / Tachometer
|
||||||
|
*
|
||||||
|
* This header defines task priorities, stack sizes, mode constants,
|
||||||
|
* WiFi configuration, GPIO pin mappings, and data structures for the
|
||||||
|
* ATE0005 device running on ESP32 platform with FreeRTOS.
|
||||||
|
*
|
||||||
|
* Key features:
|
||||||
|
* - Task configuration for inclinometer, tachometer, encoder, and stats
|
||||||
|
* - WiFi AP/STA mode configuration
|
||||||
|
* - I2C and GPIO pin definitions for peripherals
|
||||||
|
* - Mode selection constants for different operating modes
|
||||||
|
* - LCD display and PCF8574 expander macros
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -14,81 +27,90 @@
|
|||||||
#include "zh_ota_server.h"
|
#include "zh_ota_server.h"
|
||||||
#include "zh_espnow.h"
|
#include "zh_espnow.h"
|
||||||
#include "zh_syslog.h"
|
#include "zh_syslog.h"
|
||||||
|
#include "zh_menu.h"
|
||||||
|
|
||||||
#define STATS_TASK_PRIORITY tskIDLE_PRIORITY
|
#define STATS_TASK_PRIORITY (tskIDLE_PRIORITY) /*!< Priority of the statistics logging task. */
|
||||||
#define STATS_TASK_STACK_SIZE configMINIMAL_STACK_SIZE + 1024
|
#define STATS_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE + 1280) /*!< Stack size for the statistics logging task. */
|
||||||
#define A_INCLINOMETER_TASK_PRIORITY tskIDLE_PRIORITY + 5
|
#define A_INCLINOMETER_TASK_PRIORITY (tskIDLE_PRIORITY + 5) /*!< Priority of the A inclinometer processing task. */
|
||||||
#define A_INCLINOMETER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE + 512
|
#define A_INCLINOMETER_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE + 512) /*!< Stack size for the A inclinometer processing task. */
|
||||||
#define B_INCLINOMETER_TASK_PRIORITY tskIDLE_PRIORITY + 5
|
#define B_INCLINOMETER_TASK_PRIORITY (tskIDLE_PRIORITY + 5) /*!< Priority of the B inclinometer processing task. */
|
||||||
#define B_INCLINOMETER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE + 512
|
#define B_INCLINOMETER_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE + 512) /*!< Stack size for the B inclinometer processing task. */
|
||||||
#define A_TACHOMETER_TASK_PRIORITY tskIDLE_PRIORITY + 5
|
#define A_TACHOMETER_TASK_PRIORITY (tskIDLE_PRIORITY + 5) /*!< Priority of the A tachometer processing task. */
|
||||||
#define A_TACHOMETER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE + 512
|
#define A_TACHOMETER_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE + 512) /*!< Stack size for the A tachometer processing task. */
|
||||||
#define B_TACHOMETER_TASK_PRIORITY tskIDLE_PRIORITY + 5
|
#define B_TACHOMETER_TASK_PRIORITY (tskIDLE_PRIORITY + 5) /*!< Priority of the B tachometer processing task. */
|
||||||
#define B_TACHOMETER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE + 512
|
#define B_TACHOMETER_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE + 512) /*!< Stack size for the B tachometer processing task. */
|
||||||
#define ENCODER_TASK_PRIORITY tskIDLE_PRIORITY + 4
|
#define ENCODER_TASK_PRIORITY (tskIDLE_PRIORITY + 4) /*!< Priority of the mode encoder task. */
|
||||||
#define ENCODER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
|
#define ENCODER_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE + 1280) /*!< Stack size for the mode encoder task. */
|
||||||
#define EXPANDER_TASK_PRIORITY tskIDLE_PRIORITY + 4
|
#define EXPANDER_TASK_PRIORITY (tskIDLE_PRIORITY + 4) /*!< Priority of the PCF8574 expander task. */
|
||||||
#define EXPANDER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
|
#define EXPANDER_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE) /*!< Stack size for the PCF8574 expander task. */
|
||||||
|
#define MENU_TASK_PRIORITY (tskIDLE_PRIORITY + 3) /*!< Priority of the menu task. */
|
||||||
|
#define MENU_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE + 512) /*!< Stack size for the menu task. */
|
||||||
|
|
||||||
#define TRIAC_ON true
|
// #define TRIAC_ON true /*!< Triac enabled state. */
|
||||||
#define TRIAC_OFF false
|
// #define TRIAC_OFF false /*!< Triac disabled state. */
|
||||||
|
|
||||||
#define ENCODER_BUTTON_RELEASED true
|
// #define ENCODER_BUTTON_RELEASED true /*!< Encoder button released state. */
|
||||||
#define ENCODER_BUTTON_PRESSED false
|
// #define ENCODER_BUTTON_PRESSED false /*!< Encoder button pressed state. */
|
||||||
|
|
||||||
#define LED_OFF ZH_PCF8574_GPIO_LOW
|
// #define LED_OFF ZH_PCF8574_GPIO_LOW /*!< LED turned off (low level). */
|
||||||
#define LED_ON ZH_PCF8574_GPIO_HIGH
|
// #define LED_ON ZH_PCF8574_GPIO_HIGH /*!< LED turned on (high level). */
|
||||||
|
|
||||||
#define RELAY_OFF ZH_PCF8574_GPIO_LOW
|
// #define RELAY_OFF ZH_PCF8574_GPIO_LOW /*!< Relay disconnected (low level). */
|
||||||
#define RELAY_ON ZH_PCF8574_GPIO_HIGH
|
// #define RELAY_ON ZH_PCF8574_GPIO_HIGH /*!< Relay connected (high level). */
|
||||||
|
|
||||||
#define MODE_ANGLE_ANGLE 0
|
#define MODE_ANGLE_ANGLE 0 /*!< Operating mode: both inclinometers active. */
|
||||||
#define MAIN_MENU_ANGLE_ANGLE_NAME "ANGLE/ANGLE"
|
#define MAIN_MENU_ANGLE_ANGLE_NAME "ANGLE/ANGLE" /*!< Menu label for angle/angle mode. */
|
||||||
#define MODE_TACHO_TACHO 1
|
#define MODE_TACHO_TACHO 1 /*!< Operating mode: both tachometers active. */
|
||||||
#define MAIN_MENU_TACHO_TACHO_NAME "TACHO/TACHO"
|
#define MAIN_MENU_TACHO_TACHO_NAME "TACHO/TACHO" /*!< Menu label for tachometer/tachometer mode. */
|
||||||
#define MODE_ANGLE_TACHO 2
|
#define MODE_ANGLE_TACHO 2 /*!< Operating mode: A inclinometer and B tachometer active. */
|
||||||
#define MAIN_MENU_ANGLE_TACHO_NAME "ANGLE/TACHO"
|
#define MAIN_MENU_ANGLE_TACHO_NAME "ANGLE/TACHO" /*!< Menu label for angle/tachometer mode. */
|
||||||
#define MODE_REMOTE 3
|
#define MODE_REMOTE 3 /*!< Operating mode: remote control via ESP-NOW. */
|
||||||
#define MAIN_MENU_REMOTE_NAME "REMOTE"
|
#define MAIN_MENU_REMOTE_NAME "REMOTE" /*!< Menu label for remote mode. */
|
||||||
|
|
||||||
#define WIFI_AP_SSID "ATE0005"
|
#define WIFI_AP_SSID "ATE0005" /*!< WiFi AP SSID. */
|
||||||
#define WIFI_AP_PASS "repairlab"
|
#define WIFI_AP_PASS "repairlab" /*!< WiFi AP password. */
|
||||||
#define WIFI_AP_CHANNEL 1
|
#define WIFI_AP_CHANNEL 1 /*!< WiFi AP channel. */
|
||||||
#define MAX_AP_CONNECTION 4
|
#define MAX_AP_CONNECTION 4 /*!< Maximum number of stations connected to AP. */
|
||||||
|
|
||||||
#define WIFI_STA_SSID "rick_professor"
|
#define WIFI_STA_SSID "rick_professor" /*!< WiFi STA SSID. */
|
||||||
#define WIFI_STA_PASS "repairlab"
|
#define WIFI_STA_PASS "repairlab" /*!< WiFi STA password. */
|
||||||
#define WIFI_STA_MAXIMUM_RETRY 10
|
#define WIFI_STA_MAXIMUM_RETRY 10 /*!< Maximum number of reconnection attempts for STA mode. */
|
||||||
|
|
||||||
#define SYSLOG_IP "77.51.201.8"
|
#define SYSLOG_IP "77.51.201.8" /*!< IP address of the remote syslog server. */
|
||||||
|
|
||||||
#define I2C_SCL_GPIO GPIO_NUM_22
|
#define I2C_SCL_GPIO GPIO_NUM_22 /*!< I2C clock line GPIO. */
|
||||||
#define I2C_SDA_GPIO GPIO_NUM_21
|
#define I2C_SDA_GPIO GPIO_NUM_21 /*!< I2C data line GPIO. */
|
||||||
|
|
||||||
#define LCD_I2C_ADDRESS 0x20 /*!< U2. */
|
#define LCD_I2C_ADDRESS 0x20 /*!< I2C address of the LCD PCF8574 expander (U2). */
|
||||||
|
|
||||||
#define MODE_ENCODER_NUMBER 0x01 /*!< Connector EN1. */
|
#define MODE_ENCODER_NUMBER 0x01 /*!< Encoder instance number (Connector EN1). */
|
||||||
#define MODE_ENCODER_A_GPIO GPIO_NUM_27
|
#define MODE_ENCODER_A_GPIO GPIO_NUM_27 /*!< Mode encoder A-phase GPIO. */
|
||||||
#define MODE_ENCODER_B_GPIO GPIO_NUM_26
|
#define MODE_ENCODER_B_GPIO GPIO_NUM_26 /*!< Mode encoder B-phase GPIO. */
|
||||||
#define MODE_ENCODER_S_GPIO GPIO_NUM_25
|
#define MODE_ENCODER_S_GPIO GPIO_NUM_25 /*!< Mode encoder switch GPIO. */
|
||||||
|
|
||||||
#define A_OPTICAL_DEVICE_A_GPIO GPIO_NUM_14 /*!< Connector EN2. */
|
#define A_OPTICAL_DEVICE_A_GPIO GPIO_NUM_14 /*!< Optical device A-phase GPIO for channel A (Connector EN2). */
|
||||||
#define A_OPTICAL_DEVICE_B_GPIO GPIO_NUM_13
|
#define A_OPTICAL_DEVICE_B_GPIO GPIO_NUM_13 /*!< Optical device B-phase GPIO for channel A. */
|
||||||
|
|
||||||
#define B_OPTICAL_DEVICE_A_GPIO GPIO_NUM_18 /*!< Connector EN3. */
|
#define B_OPTICAL_DEVICE_A_GPIO GPIO_NUM_18 /*!< Optical device A-phase GPIO for channel B (Connector EN3). */
|
||||||
#define B_OPTICAL_DEVICE_B_GPIO GPIO_NUM_19
|
#define B_OPTICAL_DEVICE_B_GPIO GPIO_NUM_19 /*!< Optical device B-phase GPIO for channel B. */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure holding minimum free stack sizes for processing tasks.
|
||||||
|
*
|
||||||
|
* Tracks the minimum free stack size observed at runtime for each
|
||||||
|
* processing task, used for syslog monitoring and stack overflow detection.
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint32_t a_inclinometer_task_min_stack_size;
|
volatile uint32_t a_inclinometer_task_min_stack_size; /*!< Minimum free stack size of the A inclinometer task. */
|
||||||
uint32_t b_inclinometer_task_min_stack_size;
|
volatile uint32_t b_inclinometer_task_min_stack_size; /*!< Minimum free stack size of the B inclinometer task. */
|
||||||
uint32_t a_tachometer_task_min_stack_size;
|
volatile uint32_t a_tachometer_task_min_stack_size; /*!< Minimum free stack size of the A tachometer task. */
|
||||||
uint32_t b_tachometer_task_min_stack_size;
|
volatile uint32_t b_tachometer_task_min_stack_size; /*!< Minimum free stack size of the B tachometer task. */
|
||||||
} task_stats_t;
|
} task_stats_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
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 <alexey.zholtikov@yandex.ru>"
|
||||||
|
dependencies:
|
||||||
|
idf: ">=5.0"
|
||||||
|
zh_160x_i2c:
|
||||||
|
git: "https://github.com/aZholtikov/zh_160x_i2c.git"
|
||||||
|
zh_syslog:
|
||||||
|
git: "https://github.com/aZholtikov/zh_syslog.git"
|
||||||
|
zh_ota_server:
|
||||||
|
git: "https://github.com/aZholtikov/zh_ota_server.git"
|
||||||
|
zh_encoder:
|
||||||
|
git: "https://github.com/aZholtikov/zh_encoder.git"
|
||||||
|
zh_inclinometer:
|
||||||
|
git: "https://github.com/aZholtikov/zh_inclinometer"
|
||||||
|
zh_tachometer:
|
||||||
|
git: "https://github.com/aZholtikov/zh_tachometer"
|
||||||
|
zh_espnow:
|
||||||
|
git: "https://github.com/aZholtikov/zh_espnow"
|
||||||
|
zh_menu:
|
||||||
|
git: "https://github.com/aZholtikov/zh_menu"
|
||||||
+1
-1
@@ -13,7 +13,7 @@ CONFIG_PCNT_ISR_IRAM_SAFE=y
|
|||||||
CONFIG_RMT_RECV_FUNC_IN_IRAM=y
|
CONFIG_RMT_RECV_FUNC_IN_IRAM=y
|
||||||
CONFIG_RMT_TX_ISR_CACHE_SAFE=y
|
CONFIG_RMT_TX_ISR_CACHE_SAFE=y
|
||||||
CONFIG_RMT_RX_ISR_CACHE_SAFE=y
|
CONFIG_RMT_RX_ISR_CACHE_SAFE=y
|
||||||
CONFIG_SPI_MASTER_IN_IRAM=y
|
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
|
||||||
CONFIG_UART_ISR_IN_IRAM=y
|
CONFIG_UART_ISR_IN_IRAM=y
|
||||||
CONFIG_HTTPD_WS_SUPPORT=y
|
CONFIG_HTTPD_WS_SUPPORT=y
|
||||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
1.1.0
|
1.1.2
|
||||||
Reference in new issue
Block a user