Files
arcs/apps-ui/apps/llm/presenters/setting_wifi_presenter.c
2026-08-13 16:50:52 +08:00

437 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file setting_wifi_presenter.c
* @brief WiFi settings presenter - handles data logic only
*/
#define TAG "setting_wifi_presenter"
#include <stdlib.h>
#include <string.h>
#include "lisa_ui_nav_scr.h"
#include "lisa_ui.h"
#include "lisa_ui_nav_scr_ids.h"
#include "setting_wifi_view.h"
#include "model_wifi.h"
#include "lisa_ui_toast.h"
struct setting_wifi_nav_scr_data {
lv_obj_t *view;
bool wifi_enabled;
bool model_inited;
lv_timer_t *scan_timer; /* WiFi扫描定时器 */
};
static struct setting_wifi_nav_scr_data *g_scr_data = NULL;
/**
* @brief WiFi 定时扫描回调
*/
static void wifi_scan_timer_cb(lv_timer_t *timer)
{
(void)timer;
if (!g_scr_data || !g_scr_data->model_inited) {
return;
}
LISA_UI_LOGD("Timer triggered WiFi scan");
int ret = model_wifi_scan_start();
if (ret != 0) {
LISA_UI_LOGE("Timer: Failed to start WiFi scan: %d", ret);
}
}
/**
* @brief WiFi 连接成功回调
*/
static void on_wifi_connected(model_wifi_sta_config_t *sta_info, void *arg)
{
(void)arg;
if (sta_info) {
LISA_UI_LOGD("WiFi connected to: %s", sta_info->ssid);
/* 重新扫描WiFi列表以更新连接状态 */
if (g_scr_data && g_scr_data->model_inited) {
int ret = model_wifi_scan_start();
if (ret != 0) {
LISA_UI_LOGE("Failed to start WiFi scan after connection: %d", ret);
}
}
}
}
/**
* @brief WiFi 断开连接回调
*/
static void on_wifi_disconnected(int reason, void *arg)
{
(void)arg;
LISA_UI_LOGD("WiFi disconnected, reason: %d", reason);
/* 重新扫描WiFi列表以更新连接状态 */
if (g_scr_data && g_scr_data->model_inited) {
int ret = model_wifi_scan_start();
if (ret != 0) {
LISA_UI_LOGE("Failed to start WiFi scan after disconnection: %d", ret);
}
}
}
/**
* @brief WiFi 正在连接回调
*/
static void on_wifi_connecting(void *arg)
{
(void)arg;
LISA_UI_LOGD("WiFi connecting...");
// TODO: 更新UI显示连接中状态
}
/**
* @brief WiFi 连接失败回调
*/
static void on_wifi_connection_failed(int reason, void *arg)
{
(void)arg;
LISA_UI_LOGE("WiFi connection failed, reason: %d", reason);
lisa_ui_toast_show("连接失败");
}
/**
* @brief RSSI 比较函数 - 用于排序
* 排序规则:
* 1. 已连接的WiFi排在最前面
* 2. 其余WiFi按信号强度从高到低排序
*/
static int rssi_compare(const void *a, const void *b)
{
const lisa_ui_wifi_ap_info_t *ap_a = (const lisa_ui_wifi_ap_info_t *)a;
const lisa_ui_wifi_ap_info_t *ap_b = (const lisa_ui_wifi_ap_info_t *)b;
/* 如果a已连接b未连接a排在前面 */
if (ap_a->is_connected && !ap_b->is_connected) {
return -1;
}
/* 如果b已连接a未连接b排在前面 */
if (!ap_a->is_connected && ap_b->is_connected) {
return 1;
}
/* 两者连接状态相同按RSSI值越大信号越强应该排在前面 */
return ap_b->rssi - ap_a->rssi;
}
/**
* @brief WiFi 扫描完成回调
*/
static void on_wifi_scan_done(model_wifi_scan_info_t *aps_info, int ap_num, void *arg)
{
(void)arg;
LISA_UI_LOGD("WiFi scan done, found %d APs", ap_num);
if (!g_scr_data || !g_scr_data->view) {
return;
}
if (ap_num <= 0) {
/* 没有扫描到 WiFi */
lisa_ui_setting_wifi_view_clear_list(g_scr_data->view);
return;
}
/* 获取当前连接的WiFi信息 */
model_wifi_sta_config_t connected_sta;
bool has_connected = false;
if (model_wifi_get_connected_info(&connected_sta) == 0) {
has_connected = true;
LISA_UI_LOGD("Currently connected to: %s", connected_sta.ssid);
}
/* 转换为 view 层的数据结构 */
lisa_ui_wifi_ap_info_t *ap_list = lisa_ui_malloc(sizeof(lisa_ui_wifi_ap_info_t) * ap_num);
if (!ap_list) {
LISA_UI_LOGE("Failed to allocate memory for AP list");
return;
}
int unique_count = 0;
for (int i = 0; i < ap_num; i++) {
/* 过滤空SSID */
if (aps_info[i].ssid[0] == '\0' || strlen(aps_info[i].ssid) == 0) {
LISA_UI_LOGD("Skipping empty SSID at index %d", i);
continue;
}
/* 检查是否已存在相同的SSID (去重) */
bool is_duplicate = false;
for (int j = 0; j < unique_count; j++) {
if (strcmp(ap_list[j].ssid, aps_info[i].ssid) == 0) {
is_duplicate = true;
/* 如果发现重复,保留信号更强的 */
if (aps_info[i].rssi > ap_list[j].rssi) {
LISA_UI_LOGD("Found duplicate SSID '%s', updating with stronger signal (%d > %d)",
aps_info[i].ssid, aps_info[i].rssi, ap_list[j].rssi);
ap_list[j].rssi = aps_info[i].rssi;
ap_list[j].channel = aps_info[i].channel;
}
break;
}
}
if (is_duplicate) {
continue;
}
/* 添加到列表 */
strncpy(ap_list[unique_count].ssid, aps_info[i].ssid, sizeof(ap_list[unique_count].ssid) - 1);
ap_list[unique_count].ssid[sizeof(ap_list[unique_count].ssid) - 1] = '\0';
ap_list[unique_count].rssi = aps_info[i].rssi;
ap_list[unique_count].channel = aps_info[i].channel;
/* 检查是否为当前连接的WiFi */
ap_list[unique_count].is_connected = has_connected &&
(strcmp(ap_list[unique_count].ssid, connected_sta.ssid) == 0);
unique_count++;
}
/* 如果过滤后没有WiFi */
if (unique_count == 0) {
LISA_UI_LOGD("No valid WiFi APs after filtering");
lisa_ui_free(ap_list);
lisa_ui_setting_wifi_view_clear_list(g_scr_data->view);
return;
}
LISA_UI_LOGD("Filtered %d -> %d unique APs", ap_num, unique_count);
/* 按照信号强度排序 (RSSI从高到低) */
qsort(ap_list, unique_count, sizeof(lisa_ui_wifi_ap_info_t), rssi_compare);
for (int i = 0; i < unique_count; i++) {
LISA_UI_LOGD("AP[%d]: SSID=%s, RSSI=%d, Channel=%d, Connected=%d",
i, ap_list[i].ssid, ap_list[i].rssi, ap_list[i].channel, ap_list[i].is_connected);
}
/* 更新 UI 显示 WiFi 列表 */
lisa_ui_setting_wifi_view_update_list(g_scr_data->view, ap_list, unique_count);
lisa_ui_free(ap_list);
}
/**
* @brief WiFi 扫描失败回调
*/
static void on_wifi_scan_failed(int reason, void *arg)
{
(void)arg;
LISA_UI_LOGE("WiFi scan failed, reason: %d", reason);
// TODO: 更新UI显示扫描失败
}
// WiFi model 回调结构
static const struct model_wifi_cb wifi_callbacks = {
.on_connected = on_wifi_connected,
.on_disconnected = on_wifi_disconnected,
.on_connecting = on_wifi_connecting,
.on_connection_failed = on_wifi_connection_failed,
.on_scan_done = on_wifi_scan_done,
.on_scan_failed = on_wifi_scan_failed,
};
/**
* @brief 密码输入确认回调
*/
static void on_password_confirm(const char *ssid, const char *password, void *user_data)
{
(void)user_data;
LISA_UI_LOGD("Password confirmed for SSID: %s", ssid);
if (!g_scr_data || !g_scr_data->view) {
return;
}
if (password == NULL || strlen(password) < 8) {
lisa_ui_toast_show("密码长度需大于8个字符");
return;
}
/* 隐藏密码输入界面 */
lisa_ui_setting_wifi_view_hide_password_input(g_scr_data->view);
/* 尝试连接WiFi */
LISA_UI_LOGI("Attempting to connect to: %s", ssid);
int ret = model_wifi_connect(ssid, password, NULL);
if (ret != 0) {
LISA_UI_LOGE("Failed to start WiFi connection: %d", ret);
}
}
/**
* @brief 密码输入取消回调
*/
static void on_password_cancel(void *user_data)
{
(void)user_data;
LISA_UI_LOGD("Password input cancelled");
}
/**
* @brief WiFi 项点击回调
*/
static void on_wifi_item_clicked(const char *ssid, void *user_data)
{
(void)user_data;
LISA_UI_LOGD("WiFi item clicked: %s", ssid);
if (!g_scr_data || !g_scr_data->view) {
return;
}
/* 检查是否为当前已连接的WiFi */
model_wifi_sta_config_t connected_sta;
if (model_wifi_get_connected_info(&connected_sta) == 0) {
if (strcmp(connected_sta.ssid, ssid) == 0) {
LISA_UI_LOGD("Clicked WiFi is already connected, ignoring");
return;
}
}
/* 显示密码输入界面 */
lisa_ui_setting_wifi_view_show_password_input(g_scr_data->view, ssid,
on_password_confirm,
on_password_cancel,
g_scr_data);
}
/**
* @brief 返回按钮回调 - 处理返回到设置主页面的导航
* 这是presenter层的业务逻辑
*/
static void setting_wifi_back_btn_cb(void *user_data)
{
(void)user_data;
LISA_UI_LOGD("WiFi settings back button clicked, returning to settings");
lisa_ui_nav_scr_nav_back();
}
static int setting_wifi_nav_scr_open(const struct lisa_ui_nav_scr *scr, void **data)
{
LISA_UI_LOGD("WiFi settings nav scr open");
struct setting_wifi_nav_scr_data *scr_data = lisa_ui_malloc(sizeof(struct setting_wifi_nav_scr_data));
if (!scr_data) {
return -1;
}
memset(scr_data, 0, sizeof(struct setting_wifi_nav_scr_data));
scr_data->wifi_enabled = true; /* 默认开启自动扫描 */
scr_data->model_inited = false;
scr_data->scan_timer = NULL;
g_scr_data = scr_data;
// 初始化 WiFi model
int ret = model_wifi_init();
if (ret != 0) {
LISA_UI_LOGE("Failed to initialize WiFi model: %d", ret);
} else {
scr_data->model_inited = true;
// 注册 WiFi 回调
ret = model_wifi_cb_register(&wifi_callbacks, scr_data);
if (ret != 0) {
LISA_UI_LOGE("Failed to register WiFi callbacks: %d", ret);
}
}
// Create WiFi view (UI layout handled by view)
scr_data->view = lisa_ui_setting_wifi_view_create(lv_scr_act());
if (!scr_data->view) {
LISA_UI_LOGE("Failed to create WiFi view");
if (scr_data->model_inited) {
model_wifi_cb_unregister(&wifi_callbacks);
}
lisa_ui_free(scr_data);
g_scr_data = NULL;
return -1;
}
// Attach data logic to auto scan switch
// lv_obj_t *wifi_switch = lisa_ui_setting_wifi_view_get_switch(scr_data->view);
// if (wifi_switch) {
// // 设置开关初始状态为开启
// // lv_obj_add_state(wifi_switch, LV_STATE_CHECKED);
// lv_obj_add_event_cb(wifi_switch, wifi_switch_cb, LV_EVENT_VALUE_CHANGED, scr_data);
// }
/* 注册返回按钮回调 */
lisa_ui_setting_wifi_view_set_back_cb(scr_data->view, setting_wifi_back_btn_cb, NULL);
/* 注册 WiFi 项点击回调 */
lisa_ui_setting_wifi_view_set_item_cb(scr_data->view, on_wifi_item_clicked, scr_data);
/* 立即扫描一次 */
model_wifi_scan_start();
scr_data->scan_timer = lv_timer_create(wifi_scan_timer_cb, 1000 * 20, NULL);
lv_timer_resume(g_scr_data->scan_timer);
if (scr_data->scan_timer) {
LISA_UI_LOGD("WiFi scan timer created (10s interval)");
} else {
LISA_UI_LOGE("Failed to create WiFi scan timer");
}
*data = scr_data;
return 0;
}
static int setting_wifi_nav_scr_show(const struct lisa_ui_nav_scr *scr, void *data)
{
LISA_UI_LOGD("WiFi settings nav scr show");
struct setting_wifi_nav_scr_data *scr_data = (struct setting_wifi_nav_scr_data *)data;
if (!scr_data || !scr_data->view) {
LISA_UI_LOGE("WiFi view is NULL");
return -1;
}
lv_obj_clear_flag(scr_data->view, LV_OBJ_FLAG_HIDDEN);
return 0;
}
static int setting_wifi_nav_scr_close(const struct lisa_ui_nav_scr *scr, void *data)
{
struct setting_wifi_nav_scr_data *scr_data = (struct setting_wifi_nav_scr_data *)data;
if (scr_data) {
/* 删除定时器 */
if (scr_data->scan_timer) {
lv_timer_del(scr_data->scan_timer);
scr_data->scan_timer = NULL;
LISA_UI_LOGD("WiFi scan timer deleted");
}
// 注销 WiFi 回调
if (scr_data->model_inited) {
model_wifi_cb_unregister(&wifi_callbacks);
}
if (scr_data->view) {
lv_obj_del(scr_data->view);
}
lisa_ui_free(scr_data);
g_scr_data = NULL;
}
return 0;
}
const struct lisa_ui_nav_scr setting_wifi_nav_scr = {
.unique_id = LISA_UI_NAV_SCR_ID_SETTING_WIFI,
.open = setting_wifi_nav_scr_open,
.show = setting_wifi_nav_scr_show,
.pause = NULL,
.resume = NULL,
.close = setting_wifi_nav_scr_close,
};