diff --git a/main/zh_sim_race_button_box.c b/main/zh_sim_race_button_box.c index 564e21f..4152025 100755 --- a/main/zh_sim_race_button_box.c +++ b/main/zh_sim_race_button_box.c @@ -1,6 +1,5 @@ #include "zh_sim_race_button_box.h" - // Хэндлы - функции - переменные // #define ENCODER_NUMBER 0x01 // #define LCD_VIEWPORT_ROWS 3 @@ -8,13 +7,13 @@ // #define LCD_TOTAL_ROWS 4 #define BOOT_SPLASH_MS 5000 -#define MAIN_SCREEN_COUNT 5 -#define LOAD_SCREEN_COUNT 5 +// #define MAIN_SCREEN_COUNT 5 +// #define LOAD_SCREEN_COUNT 5 // #define NVS_NAMESPACE "sim_race_box" /* NEW */ // #define NVS_KEY_SETTINGS "settings" /* NEW */ -static const char *TAG = "sim_race_box"; +// static const char *TAG = "sim_race_box"; /* ============================================================ * Данные main-экранов (idle) @@ -25,21 +24,7 @@ int16_t main_times_data[VIEW_CELLS] = {1234, 1201, 1250, -49, 0}; int16_t main_debug_data[VIEW_CELLS] = {45, -42, 152, 12, 0}; int16_t main_blank_data[VIEW_CELLS] = {0, 0, 0, 0, 0}; -/* ---------- Дескрипторы экранов ---------- */ -// typedef struct -// { -// const char *name; -// const char *const labels[VIEW_ROWS]; -// int16_t *data; -// } main_screen_desc_t; - -// typedef struct -// { -// const char *name; -// const char *const lines[VIEW_ROWS]; -// } load_screen_desc_t; - -static const zh_main_screen_description_t main_screens[MAIN_SCREEN_COUNT] = { +static const zh_main_screen_description_t main_screens[] = { {"Race", {"SPD", "RPM", "GER", "LAP"}, main_race_data}, {"Engine", {"OIL", "WTR", "BAT", "FUL"}, main_engine_data}, {"Times", {"LAP", "BST", "LST", "DLT"}, main_times_data}, @@ -47,29 +32,18 @@ static const zh_main_screen_description_t main_screens[MAIN_SCREEN_COUNT] = { {"Blank", {"---", "---", "---", "---"}, main_blank_data}, }; -static const zh_boot_screen_description_t load_screens[LOAD_SCREEN_COUNT] = { - {"Boot", {"Booting...", "RAM: OK", "I2C: OK", "Starting..."}}, - {"Version", {"FW v1.0", "Build 2025-10", "ESP-IDF v5.4", "zh_menu v1.2"}}, - {"Diag", {"I2C: OK", "LCD: OK", "ENC: OK", "All: OK"}}, - {"Ready", {"System ready", "Ready for race", "Let's go", ""}}, - {"Blank", {"", "", "", ""}}, -}; - -/* ---------- Пользовательский выбор ---------- */ -static int _boot_screen = 0; -static int _main_screen = 0; static bool _boot_done = false; static bool _prev_selected = false; /* NEW: для детекции выхода из edit */ /* ---------- Динамические буферы меток ---------- */ -char lbl_boot_screen[MENU_LABEL_LEN] = "B:Boot"; -char lbl_main_screen[MENU_LABEL_LEN] = "M:Race"; -char lbl_temp_on[MENU_LABEL_LEN] = "Temp ON 15C"; -char lbl_temp_off[MENU_LABEL_LEN] = "Temp OFF 35C"; -char lbl_pw_ch_1[MENU_LABEL_LEN] = "PW CH 1 100%"; -char lbl_pw_ch_2[MENU_LABEL_LEN] = "PW CH 2 100%"; -char lbl_pw_ch_3[MENU_LABEL_LEN] = "PW CH 3 100%"; -char lbl_pw_ch_4[MENU_LABEL_LEN] = "PW CH 4 100%"; +// char lbl_boot_screen[LCD_TOTAL_COLS + 1] = "B:Boot"; +// char lbl_main_screen[LCD_TOTAL_COLS + 1] = "M:Race"; +// char lbl_temp_on[LCD_TOTAL_COLS + 1] = "Temp ON 15C"; +// char lbl_temp_off[LCD_TOTAL_COLS + 1] = "Temp OFF 35C"; +// char lbl_pw_ch_1[LCD_TOTAL_COLS + 1] = "PW CH 1 100%"; +// char lbl_pw_ch_2[LCD_TOTAL_COLS + 1] = "PW CH 2 100%"; +// char lbl_pw_ch_3[LCD_TOTAL_COLS + 1] = "PW CH 3 100%"; +// char lbl_pw_ch_4[LCD_TOTAL_COLS + 1] = "PW CH 4 100%"; /* ---------- Handle'ы ---------- */ zh_encoder_handle_t *encoder_handle = NULL; @@ -85,6 +59,14 @@ static void zh_save_settings(void); void zh_encoder_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); +void zh_menu_enter_main_menu_callback(void *arg); +void zh_menu_exit_main_menu_callback(void *arg); +void zh_menu_change_menu_callback(zh_menu_node_t *current_node, uint8_t current_index); +void zh_menu_selectable_item_callback(void *arg); +void zh_menu_back_command_callback(void *arg); +void zh_menu_boot_screen_callback(void *arg); +void zh_menu_main_screen_callback(void *arg); + /* ---------- Состояние меню ---------- */ static zh_menu_node_t *last_node = NULL; static uint8_t last_index = 0; @@ -150,15 +132,15 @@ static void zh_save_settings(void) } /* ---------- Утилиты ---------- */ -static inline int16_t _clamp_i16(int16_t v, int16_t lo, int16_t hi) -{ - return v < lo ? lo : (v > hi ? hi : v); -} +// static inline int16_t _clamp_i16(int16_t v, int16_t lo, int16_t hi) +// { +// return v < lo ? lo : (v > hi ? hi : v); +// } -static inline uint8_t _clamp_u8(int16_t v, uint8_t lo, uint8_t hi) -{ - return v < lo ? lo : (v > hi ? hi : v); -} +// static inline uint8_t _clamp_u8(int16_t v, uint8_t lo, uint8_t hi) +// { +// return v < lo ? lo : (v > hi ? hi : v); +// } static void _invalidaterow_cache(void) { @@ -166,8 +148,7 @@ static void _invalidaterow_cache(void) } /* ---------- Форматирование ---------- */ -static void _format_row(char *buf, const char *label, bool selected, bool edit, - bool arrow_up, bool arrow_down) +static void _format_row(char *buf, const char *label, bool selected, bool edit, bool arrow_up, bool arrow_down) { memset(buf, ' ', LCD_TOTAL_COLS); buf[LCD_TOTAL_COLS] = '\0'; @@ -211,8 +192,9 @@ static void _format_load_row(char *buf, const char *line) static void _lcd_put_row(uint8_t row, const char *text) { if (row_valid[row] && memcmp(row_cache[row], text, LCD_TOTAL_COLS) == 0) + { return; - + } zh_160x_set_cursor(&lcd_handle, row, 0); zh_160x_print_char(&lcd_handle, text); memcpy(row_cache[row], text, LCD_TOTAL_COLS); @@ -255,11 +237,11 @@ static void _refresh_dynamic_labels(zh_menu_node_t *node) } else if (lbl == lbl_boot_screen) { - snprintf(lbl_boot_screen, sizeof(lbl_boot_screen), "B:%s", load_screens[_boot_screen].name); + snprintf(lbl_boot_screen, sizeof(lbl_boot_screen), "B:%s", boot_screens[boot_screen_number].name); } else if (lbl == lbl_main_screen) { - snprintf(lbl_main_screen, sizeof(lbl_main_screen), "M:%s", main_screens[_main_screen].name); + snprintf(lbl_main_screen, sizeof(lbl_main_screen), "M:%s", main_screens[main_screen_number].name); } } } @@ -267,7 +249,7 @@ static void _refresh_dynamic_labels(zh_menu_node_t *node) /* ---------- Отрисовка экранов ---------- */ static void _draw_main_screen(void) { - const zh_main_screen_description_t *s = &main_screens[_main_screen]; + const zh_main_screen_description_t *s = &main_screens[main_screen_number]; for (uint8_t i = 0; i < LCD_TOTAL_ROWS; ++i) { char buf[LCD_TOTAL_COLS + 1]; @@ -278,7 +260,7 @@ static void _draw_main_screen(void) static void _draw_load_screen(void) { - const zh_boot_screen_description_t *s = &load_screens[_boot_screen]; + const zh_boot_screen_description_t *s = &boot_screens[boot_screen_number]; for (uint8_t i = 0; i < LCD_TOTAL_ROWS; ++i) { char buf[LCD_TOTAL_COLS + 1]; @@ -451,7 +433,7 @@ void zh_encoder_event_handler(void *arg, esp_event_base_t event_base, int32_t ev case ZH_BUTTON_EVENT: { zh_encoder_button_event_on_isr_t *button_event = event_data; - if (button_event->button_status == true) + if (button_event->button_status == ENCODER_BUTTON_RELEASED) { menu_status.is_active == false ? zh_menu_set(&menu_handle, ZH_MENU_ENTER, NULL, 0) : menu_status.is_selected == false ? zh_menu_set(&menu_handle, ZH_MENU_SELECT, NULL, 0) : zh_menu_set(&menu_handle, ZH_MENU_BACK, NULL, 0); @@ -531,60 +513,58 @@ void zh_menu_change_menu_callback(zh_menu_node_t *current_node, uint8_t current_ void zh_menu_selectable_item_callback(void *arg) { if (last_node == NULL || last_node->submenu == NULL) + { return; + } if (last_index >= last_node->item_numbers) + { return; - + } zh_menu_node_t *item = &last_node->submenu[last_index]; - if (arg == NULL) { zh_menu_set(&menu_handle, ZH_MENU_SHOW, NULL, 0); return; } - - zh_encoder_event_on_isr_t *enc = arg; - int8_t dir = enc->encoder_status ? +1 : -1; + zh_encoder_event_on_isr_t *encoder = arg; + int8_t dir = encoder->encoder_status ? +1 : -1; bool changed = false; - if (item->label == lbl_temp_on) { - air_condition_temp_on = _clamp_i16(air_condition_temp_on + dir, 15, 30); + air_condition_temp_on = VALUE_CLAMP(air_condition_temp_on + dir, 15, 30); changed = true; } else if (item->label == lbl_temp_off) { - air_condition_temp_off = _clamp_i16(air_condition_temp_off + dir, 15, 30); + air_condition_temp_off = VALUE_CLAMP(air_condition_temp_off + dir, 15, 30); changed = true; } else if (item->label == lbl_pw_ch_1) { - exit_channel_power[0] = _clamp_u8(exit_channel_power[0] + dir * 5, 0, 100); + exit_channel_power[0] = VALUE_CLAMP(exit_channel_power[0] + dir * 5, 0, 100); changed = true; } else if (item->label == lbl_pw_ch_2) { - exit_channel_power[1] = _clamp_u8(exit_channel_power[1] + dir * 5, 0, 100); + exit_channel_power[1] = VALUE_CLAMP(exit_channel_power[1] + dir * 5, 0, 100); changed = true; } else if (item->label == lbl_pw_ch_3) { - exit_channel_power[2] = _clamp_u8(exit_channel_power[2] + dir * 5, 0, 100); + exit_channel_power[2] = VALUE_CLAMP(exit_channel_power[2] + dir * 5, 0, 100); changed = true; } else if (item->label == lbl_pw_ch_4) { - exit_channel_power[3] = _clamp_u8(exit_channel_power[3] + dir * 5, 0, 100); + exit_channel_power[3] = VALUE_CLAMP(exit_channel_power[3] + dir * 5, 0, 100); changed = true; } - - if (changed) + if (changed == true) { zh_menu_set(&menu_handle, ZH_MENU_SHOW, NULL, 0); } } -/* ---------- Selectable: выбор load-экрана ---------- */ void zh_menu_boot_screen_callback(void *arg) { if (arg == NULL) @@ -592,24 +572,24 @@ void zh_menu_boot_screen_callback(void *arg) zh_menu_set(&menu_handle, ZH_MENU_SHOW, NULL, 0); return; } - - zh_encoder_event_on_isr_t *enc = arg; - int8_t dir = enc->encoder_status ? +1 : -1; - - int next = _boot_screen + dir; + zh_encoder_event_on_isr_t *encoder = arg; + int8_t dir = encoder->encoder_status == true ? +1 : -1; + int next = boot_screen_number + dir; if (next < 0) - next = LOAD_SCREEN_COUNT - 1; - if (next >= LOAD_SCREEN_COUNT) - next = 0; - - if (next != _boot_screen) { - _boot_screen = next; + next = ARRAY_SIZE(boot_screens) - 1; + } + if (next >= ARRAY_SIZE(boot_screens)) + { + next = 0; + } + if (next != boot_screen_number) + { + boot_screen_number = next; zh_menu_set(&menu_handle, ZH_MENU_SHOW, NULL, 0); } } -/* ---------- Selectable: выбор main-экрана ---------- */ void zh_menu_main_screen_callback(void *arg) { if (arg == NULL) @@ -617,28 +597,29 @@ void zh_menu_main_screen_callback(void *arg) zh_menu_set(&menu_handle, ZH_MENU_SHOW, NULL, 0); return; } - - zh_encoder_event_on_isr_t *enc = arg; - int8_t dir = enc->encoder_status ? +1 : -1; - - int next = _main_screen + dir; + zh_encoder_event_on_isr_t *encoder = arg; + int8_t dir = encoder->encoder_status == true ? +1 : -1; + int next = main_screen_number + dir; if (next < 0) - next = MAIN_SCREEN_COUNT - 1; - if (next >= MAIN_SCREEN_COUNT) - next = 0; - - if (next != _main_screen) { - _main_screen = next; + next = ARRAY_SIZE(main_screens) - 1; + } + if (next >= ARRAY_SIZE(main_screens)) + { + next = 0; + } + if (next != main_screen_number) + { + main_screen_number = next; zh_menu_set(&menu_handle, ZH_MENU_SHOW, NULL, 0); } } -void zh_menu_simple_item_callback(void *arg) -{ - (void)arg; - ESP_LOGI(TAG, "Simple item callback performed"); -} +// void zh_menu_simple_item_callback(void *arg) +// { +// (void)arg; +// ESP_LOGI(TAG, "Simple item callback performed"); +// } void zh_menu_back_command_callback(void *arg) { diff --git a/main/zh_sim_race_button_box.h b/main/zh_sim_race_button_box.h index 79b2fde..2e110fd 100644 --- a/main/zh_sim_race_button_box.h +++ b/main/zh_sim_race_button_box.h @@ -7,17 +7,30 @@ #include "zh_encoder.h" #include "zh_ota_server.h" +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define VALUE_CLAMP(v, lo, hi) ((v) < (lo) ? (lo) : ((v) > (hi) ? (hi) : (v))) + #define ENCODER_NUMBER 1 #define LCD_TOTAL_ROWS 4 #define LCD_TOTAL_COLS 16 + +#define STATS_TASK_PRIORITY tskIDLE_PRIORITY /*!< Priority of the statistics/monitoring task */ +#define STATS_TASK_STACK_SIZE configMINIMAL_STACK_SIZE + 1280 /*!< Stack size of the statistics/monitoring task */ +#define EXPANDER_TASK_PRIORITY tskIDLE_PRIORITY + 5 /*!< Priority of the PCF8574 expander polling task */ +#define EXPANDER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE /*!< Stack size of the expander polling task */ +#define ENCODER_TASK_PRIORITY tskIDLE_PRIORITY + 4 /*!< Priority of the encoder reading task */ +#define ENCODER_TASK_STACK_SIZE configMINIMAL_STACK_SIZE /*!< Stack size of the encoder task */ // #define LCD_VIEWPORT_ROWS (LCD_TOTAL_ROWS - 1) -#define MENU_LABEL_LEN 17 +#define ENCODER_BUTTON_RELEASED true /*!< State: encoder button released */ +#define ENCODER_BUTTON_PRESSED false /*!< State: encoder button pressed */ + +// #define LCD_TOTAL_COLS+1 17 /* ---------- Размеры view ---------- */ #define VIEW_CELLS 5 /* ячеек в массиве данных (main) */ -#define VIEW_ROWS 4 /* строк отрисовывается на LCD */ +// #define VIEW_ROWS 4 /* строк отрисовывается на LCD */ #define NVS_NAMESPACE "sim_race_box" /* NEW */ #define NVS_KEY_SETTINGS "settings" /* NEW */ @@ -29,36 +42,25 @@ extern int16_t main_times_data[VIEW_CELLS]; extern int16_t main_debug_data[VIEW_CELLS]; extern int16_t main_blank_data[VIEW_CELLS]; -/* ---------- Динамические буферы меток ---------- */ -extern char lbl_temp_on[MENU_LABEL_LEN]; -extern char lbl_temp_off[MENU_LABEL_LEN]; -extern char lbl_pw_ch_1[MENU_LABEL_LEN]; -extern char lbl_pw_ch_2[MENU_LABEL_LEN]; -extern char lbl_pw_ch_3[MENU_LABEL_LEN]; -extern char lbl_pw_ch_4[MENU_LABEL_LEN]; -extern char lbl_boot_screen[MENU_LABEL_LEN]; /* "B: <имя load-экрана>" */ -extern char lbl_main_screen[MENU_LABEL_LEN]; /* "M: <имя main-экрана>" */ - -/* ---------- Переменные значений ---------- */ -// extern int16_t g_temp_on; -// extern int16_t g_temp_off; -// extern uint8_t g_pw_ch[4]; - -/* ---------- Callbacks ---------- */ -void zh_menu_enter_main_menu_callback(void *arg); -void zh_menu_exit_main_menu_callback(void *arg); -void zh_menu_change_menu_callback(zh_menu_node_t *current_node, uint8_t current_index); -void zh_menu_selectable_item_callback(void *arg); -void zh_menu_simple_item_callback(void *args); -void zh_menu_back_command_callback(void *arg); -void zh_menu_boot_screen_callback(void *arg); -void zh_menu_main_screen_callback(void *arg); - #ifdef __cplusplus extern "C" { #endif + extern void zh_menu_selectable_item_callback(void *arg); + extern void zh_menu_back_command_callback(void *arg); + extern void zh_menu_boot_screen_callback(void *arg); + extern void zh_menu_main_screen_callback(void *arg); + + static char lbl_boot_screen[LCD_TOTAL_COLS + 1] = "B:Boot"; + static char lbl_main_screen[LCD_TOTAL_COLS + 1] = "M:Race"; + static char lbl_temp_on[LCD_TOTAL_COLS + 1] = "Temp ON 15C"; + static char lbl_temp_off[LCD_TOTAL_COLS + 1] = "Temp OFF 35C"; + static char lbl_pw_ch_1[LCD_TOTAL_COLS + 1] = "PW CH 1 100%"; + static char lbl_pw_ch_2[LCD_TOTAL_COLS + 1] = "PW CH 2 100%"; + static char lbl_pw_ch_3[LCD_TOTAL_COLS + 1] = "PW CH 3 100%"; + static char lbl_pw_ch_4[LCD_TOTAL_COLS + 1] = "PW CH 4 100%"; + typedef struct { uint8_t air_condition_temp_on; @@ -82,6 +84,14 @@ extern "C" const char *const lines[LCD_TOTAL_ROWS]; } zh_boot_screen_description_t; + static const zh_boot_screen_description_t boot_screens[] = { + {"Boot", {"Booting...", "RAM: OK", "I2C: OK", "Starting..."}}, + {"Version", {"FW v1.0", "Build 2025-10", "ESP-IDF v5.4", ""}}, + {"Diag", {"I2C: OK", "LCD: OK", "ENC: OK", "All: OK"}}, + {"Ready", {"System ready", "Ready for race", "Let's go", ""}}, + {"Blank", {"---", "---", "---", "---"}}, + }; + zh_menu_node_t main_menu = { .label = "Settings", .submenu = (zh_menu_node_t[]){