- Progress bar under status line shows captured/total WPA targets - Three visual states per network: Green (pending) -> Orange blinking (active target) -> Red + checkmark (captured) - Active targets show live info: client count during observation, EAPOL progress during capture (e.g. "⚡ NetworkName 1/2") - Status line shows channel number and phase context - LVGL symbols: lightning bolt for active, checkmark for captured - Title updated to "⚡ Capture" with WiFi icon Made-with: Cursor
192 lines
7.0 KiB
C++
192 lines
7.0 KiB
C++
#include "LVGL_Driver.h"
|
|
|
|
static lv_disp_draw_buf_t draw_buf;
|
|
static lv_color_t buf1[LVGL_BUF_LEN];
|
|
static lv_color_t buf2[LVGL_BUF_LEN];
|
|
static lv_obj_t *status_label = nullptr;
|
|
static lv_obj_t *list_label = nullptr;
|
|
static lv_obj_t *network_container = nullptr;
|
|
static lv_obj_t *network_labels[20] = {nullptr};
|
|
static int network_count = 0;
|
|
static lv_obj_t *progress_bar = nullptr;
|
|
static lv_obj_t *progress_label = nullptr;
|
|
|
|
void Ui_SetWifiStatus(const char *text) {
|
|
if (status_label != nullptr) {
|
|
lv_label_set_text(status_label, text);
|
|
}
|
|
}
|
|
|
|
void Ui_ClearNetworkList(void) {
|
|
if (network_container == nullptr) return;
|
|
for (int i = 0; i < network_count; i++) {
|
|
if (network_labels[i] != nullptr) {
|
|
lv_obj_del(network_labels[i]);
|
|
network_labels[i] = nullptr;
|
|
}
|
|
}
|
|
network_count = 0;
|
|
}
|
|
|
|
void Ui_AddNetwork(const char* text, int index) {
|
|
if (network_container == nullptr || index < 0 || index >= 20) return;
|
|
if (network_labels[index] != nullptr) {
|
|
lv_label_set_text(network_labels[index], text);
|
|
return;
|
|
}
|
|
lv_obj_t* label = lv_label_create(network_container);
|
|
lv_label_set_text(label, text);
|
|
lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_GREEN), 0);
|
|
lv_obj_set_style_text_font(label, &lv_font_montserrat_12, 0);
|
|
lv_obj_set_width(label, lv_pct(100));
|
|
network_labels[index] = label;
|
|
if (index >= network_count) network_count = index + 1;
|
|
}
|
|
|
|
void Ui_SetNetworkColor(int index, lv_color_t color) {
|
|
if (index < 0 || index >= 20 || network_labels[index] == nullptr) return;
|
|
lv_obj_set_style_text_color(network_labels[index], color, 0);
|
|
}
|
|
|
|
void Ui_SetNetworkText(int index, const char* text) {
|
|
if (index < 0 || index >= 20 || network_labels[index] == nullptr) return;
|
|
lv_label_set_text(network_labels[index], text);
|
|
}
|
|
|
|
void Ui_SetProgress(int current, int total) {
|
|
if (progress_bar == nullptr) return;
|
|
if (total <= 0) {
|
|
lv_bar_set_value(progress_bar, 0, LV_ANIM_OFF);
|
|
if (progress_label) lv_label_set_text(progress_label, "");
|
|
return;
|
|
}
|
|
int pct = (current * 100) / total;
|
|
lv_bar_set_value(progress_bar, pct, LV_ANIM_ON);
|
|
|
|
char buf[16];
|
|
snprintf(buf, sizeof(buf), "%d/%d", current, total);
|
|
if (progress_label) lv_label_set_text(progress_label, buf);
|
|
}
|
|
|
|
void Ui_ShowProgress(bool visible) {
|
|
if (progress_bar == nullptr) return;
|
|
if (visible) {
|
|
lv_obj_clear_flag(progress_bar, LV_OBJ_FLAG_HIDDEN);
|
|
if (progress_label) lv_obj_clear_flag(progress_label, LV_OBJ_FLAG_HIDDEN);
|
|
} else {
|
|
lv_obj_add_flag(progress_bar, LV_OBJ_FLAG_HIDDEN);
|
|
if (progress_label) lv_obj_add_flag(progress_label, LV_OBJ_FLAG_HIDDEN);
|
|
}
|
|
}
|
|
|
|
void Lvgl_Display_LCD(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) {
|
|
LCD_addWindow(area->x1, area->y1, area->x2, area->y2, (uint16_t*)&color_p->full);
|
|
lv_disp_flush_ready(disp_drv);
|
|
}
|
|
|
|
void Lvgl_Touchpad_Read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
|
|
(void)indev_drv;
|
|
(void)data;
|
|
}
|
|
|
|
void example_increase_lvgl_tick(void *arg) {
|
|
(void)arg;
|
|
lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
|
|
}
|
|
|
|
void Lvgl_Init(void) {
|
|
lv_init();
|
|
lv_disp_draw_buf_init(&draw_buf, buf1, buf2, LVGL_BUF_LEN);
|
|
|
|
static lv_disp_drv_t disp_drv;
|
|
lv_disp_drv_init(&disp_drv);
|
|
disp_drv.hor_res = LVGL_WIDTH;
|
|
disp_drv.ver_res = LVGL_HEIGHT;
|
|
disp_drv.flush_cb = Lvgl_Display_LCD;
|
|
disp_drv.full_refresh = 0;
|
|
disp_drv.draw_buf = &draw_buf;
|
|
lv_disp_drv_register(&disp_drv);
|
|
|
|
static lv_indev_drv_t indev_drv;
|
|
lv_indev_drv_init(&indev_drv);
|
|
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
|
indev_drv.read_cb = Lvgl_Touchpad_Read;
|
|
lv_indev_drv_register(&indev_drv);
|
|
|
|
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_black(), 0);
|
|
lv_obj_set_style_bg_opa(lv_scr_act(), LV_OPA_COVER, 0);
|
|
|
|
// Title
|
|
lv_obj_t *title = lv_label_create(lv_scr_act());
|
|
lv_obj_set_style_text_color(title, lv_palette_main(LV_PALETTE_GREEN), 0);
|
|
lv_obj_set_style_text_font(title, &lv_font_montserrat_16, 0);
|
|
lv_label_set_text(title, LV_SYMBOL_WIFI " Capture");
|
|
lv_obj_align(title, LV_ALIGN_TOP_LEFT, 10, 6);
|
|
|
|
// Status line
|
|
status_label = lv_label_create(lv_scr_act());
|
|
lv_obj_set_style_text_color(status_label, lv_palette_lighten(LV_PALETTE_GREEN, 2), 0);
|
|
lv_obj_set_style_text_font(status_label, &lv_font_montserrat_12, 0);
|
|
lv_label_set_text(status_label, "Starting...");
|
|
lv_obj_align(status_label, LV_ALIGN_TOP_LEFT, 10, 28);
|
|
|
|
// Progress bar (hidden until capture starts)
|
|
progress_bar = lv_bar_create(lv_scr_act());
|
|
lv_obj_set_size(progress_bar, 114, 6);
|
|
lv_obj_align(progress_bar, LV_ALIGN_TOP_LEFT, 10, 44);
|
|
lv_bar_set_range(progress_bar, 0, 100);
|
|
lv_bar_set_value(progress_bar, 0, LV_ANIM_OFF);
|
|
lv_obj_set_style_bg_color(progress_bar, lv_color_make(25, 25, 25), LV_PART_MAIN);
|
|
lv_obj_set_style_bg_opa(progress_bar, LV_OPA_COVER, LV_PART_MAIN);
|
|
lv_obj_set_style_bg_color(progress_bar, lv_palette_main(LV_PALETTE_GREEN), LV_PART_INDICATOR);
|
|
lv_obj_set_style_bg_opa(progress_bar, LV_OPA_COVER, LV_PART_INDICATOR);
|
|
lv_obj_set_style_radius(progress_bar, 2, LV_PART_MAIN);
|
|
lv_obj_set_style_radius(progress_bar, 2, LV_PART_INDICATOR);
|
|
lv_obj_add_flag(progress_bar, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
// Progress count label (right of bar)
|
|
progress_label = lv_label_create(lv_scr_act());
|
|
lv_obj_set_style_text_color(progress_label, lv_palette_main(LV_PALETTE_GREEN), 0);
|
|
lv_obj_set_style_text_font(progress_label, &lv_font_montserrat_12, 0);
|
|
lv_label_set_text(progress_label, "");
|
|
lv_obj_align(progress_label, LV_ALIGN_TOP_LEFT, 130, 41);
|
|
lv_obj_add_flag(progress_label, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
// Network list panel
|
|
lv_obj_t *list_panel = lv_obj_create(lv_scr_act());
|
|
lv_obj_set_size(list_panel, 164, 254);
|
|
lv_obj_align(list_panel, LV_ALIGN_TOP_LEFT, 4, 54);
|
|
lv_obj_set_style_bg_color(list_panel, lv_color_black(), 0);
|
|
lv_obj_set_style_bg_opa(list_panel, LV_OPA_TRANSP, 0);
|
|
lv_obj_set_style_border_width(list_panel, 1, 0);
|
|
lv_obj_set_style_border_color(list_panel, lv_palette_darken(LV_PALETTE_GREEN, 2), 0);
|
|
lv_obj_set_style_pad_all(list_panel, 6, 0);
|
|
lv_obj_set_scrollbar_mode(list_panel, LV_SCROLLBAR_MODE_OFF);
|
|
|
|
network_container = lv_obj_create(list_panel);
|
|
lv_obj_set_size(network_container, lv_pct(100), lv_pct(100));
|
|
lv_obj_set_flex_flow(network_container, LV_FLEX_FLOW_COLUMN);
|
|
lv_obj_set_flex_align(network_container, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
|
|
lv_obj_clear_flag(network_container, LV_OBJ_FLAG_SCROLLABLE);
|
|
lv_obj_set_style_pad_all(network_container, 0, 0);
|
|
lv_obj_set_style_border_width(network_container, 0, 0);
|
|
lv_obj_set_style_bg_opa(network_container, LV_OPA_TRANSP, 0);
|
|
|
|
list_label = lv_label_create(list_panel);
|
|
lv_obj_set_width(list_label, lv_pct(100));
|
|
lv_label_set_text(list_label, "");
|
|
lv_obj_add_flag(list_label, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
const esp_timer_create_args_t lvgl_tick_timer_args = {
|
|
.callback = &example_increase_lvgl_tick,
|
|
.name = "lvgl_tick"
|
|
};
|
|
esp_timer_handle_t lvgl_tick_timer = NULL;
|
|
esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer);
|
|
esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000);
|
|
}
|
|
|
|
void Timer_Loop(void) {
|
|
lv_timer_handler();
|
|
}
|