Files
arcs/apps/arcs-mini/main.c
2026-08-13 16:50:52 +08:00

283 lines
8.4 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.
#include "FreeRTOS.h"
#include "task.h"
#include "project_version.h"
#define TAG "main"
#include "lisa_log.h"
#include "lisa_time.h"
#include "alarm_aiui.h"
#include "service_led.h"
#include "service_volume.h"
#include "service_brightness.h"
#include "service_button.h"
#include "service_camera.h"
#include "service_alarm.h"
#include "service_image.h"
#include "voice_msg.h"
#include "lisa_kv.h"
#include "wifi_manager/wifi_manager.h"
#include "app_datas.h"
#include "tone.h"
#include "player_mgr.h"
#include "power/power_manager.h"
#include "pa_manager.h"
#include "lisa_display.h"
#include "battery/battery.h"
#include "lisa_ui_nav_scr.h"
#include "apps/llm/models/model_voice.h"
#include "voice_cloud.h"
#ifdef CONFIG_VOICE_LINK_LINGXIN
#include "lingxin_server_config.h"
#endif
#ifdef CONFIG_VOICE_LINK_LINGXIN
#define LINGXIN_BUTTON_WAKEUP_DEBOUNCE_MS 800U
static bool lingxin_button_wakeup_debounce(void)
{
static uint32_t s_last_wakeup_ms;
uint32_t now_ms = (uint32_t)lisa_os_get_tick_ms();
if (s_last_wakeup_ms != 0 && (uint32_t)(now_ms - s_last_wakeup_ms) < LINGXIN_BUTTON_WAKEUP_DEBOUNCE_MS) {
LISA_LOGI(TAG, "[Lingxin] single click ignored by debounce");
return false;
}
s_last_wakeup_ms = now_ms;
return true;
}
static void lingxin_publish_button_wakeup(void)
{
struct app_datas *app_datas = get_app_datas();
if (app_datas && (app_datas->voice_work_mode & VOICE_WORK_MODE_BUTTON_WAKEUP)) {
voice_msg_pub(VOICE_MSG_WAKEUP_BUTTON_START, NULL, 0);
} else {
const char keyword[] = "xiao ling xiao ling";
voice_msg_pub(VOICE_MSG_WAKEUP_KEYWORD, (void *)keyword, sizeof(keyword));
}
}
#endif
extern uint8_t app_ble_adv_start(uint8_t adv_id, uint8_t adv_type);
void network_reset(void)
{
LOGI("network reset running...");
#if CONFIG_WIFI_MANAGER
wifi_mgr_sta_disconnect(true);
wifi_mgr_sta_config_t list[16] = {0};
int count = 0;
do {
count = wifi_mgr_storage_search_ap(list, (int)(sizeof(list) / sizeof(list[0])), SEARCH_ALL, NULL);
if (count > 0) {
int del_count = count;
if (del_count > (int)(sizeof(list) / sizeof(list[0]))) {
del_count = (int)(sizeof(list) / sizeof(list[0]));
}
for (int i = 0; i < del_count; i++) {
wifi_mgr_storage_delete_ap(&list[i]);
}
}
} while (count > (int)(sizeof(list) / sizeof(list[0])));
#endif
}
void factory_reset(void)
{
LOGI("factory reset running...");
lisa_kv_clear();
network_reset();
LOGI("factory reset dwone.");
LOGI("The system will restart after 300ms.");
player_mgr_play(LOCAL, app_tone_get_url(TONE_ID_103), 0);
vTaskDelay(2000);
extern void sys_platform_sw_full_reset(void);
sys_platform_sw_full_reset();
}
static void voice_system_network_probe_success(void *unused, uint32_t msg_id, void *data, uint32_t len, void *user_data)
{
#ifdef CONFIG_VOICE_LINK_LINGXIN
if (lingxin_server_config_fetch() != 0) {
LOGE("[Lingxin] failed to load runtime config");
}
#endif
service_alarm_init();
}
static void button_changed(void *unused, uint32_t msg_id, void *data, uint32_t len, void *user_data)
{
voice_msg_button_evt_t *evt = (voice_msg_button_evt_t *)data;
service_image_waiting_cancel();
if (evt->button_id != 0) {
return;
}
switch (evt->action) {
case VOICE_MSG_BUTTON_ACTION_CLICK:
{
/* 单击:非主页先回主页;主页则触发按键唤醒 */
if (lisa_ui_nav_scr_get_top_id() != 0) {
LISA_LOGI(TAG, "Single click: not on home page, navigating home");
lisa_ui_nav_scr_nav_to(0);
break;
} else {
LISA_LOGI(TAG, "Single click: wakeup trigger");
#ifdef CONFIG_VOICE_LINK_LINGXIN
if (!lingxin_button_wakeup_debounce()) {
break;
}
LISA_LOGI(TAG, "[Lingxin] single click: wakeup/barge-in trigger");
lingxin_publish_button_wakeup();
#else
if (model_voice_tts_is_playing()) {
LISA_LOGI(TAG, "Single click: TTS playing, stop it");
player_mgr_stop(TTS);
break;
}
#ifdef CONFIG_VOICE_LINK_LSCHAT
if (model_voice_cloud_is_running()) {
voice_msg_pub(VOICE_MSG_CLOUD_MCP_CHAT_EXIT, NULL, 0);
} else {
const char keyword[] = "xiao ling xiao ling";
voice_msg_pub(VOICE_MSG_WAKEUP_KEYWORD, (void *)keyword, sizeof(keyword));
}
#else
LISA_LOGI(TAG, "LSChat link inactive, ignore LSChat wakeup trigger");
#endif
#endif
}
break;
}
case VOICE_MSG_BUTTON_ACTION_DOUBLE_CLICK:
{
/* 双击:留给 LiveKit 设备呼叫,避免同时触发拍照识图 */
LISA_LOGI(TAG, "power button double click, reserved for livekit call");
break;
}
case VOICE_MSG_BUTTON_ACTION_TRIPLE_CLICK:
{
/* 三击:留给 LiveKit 来电拒接,不再打开二维码/信息页 */
LISA_LOGI(TAG, "power button triple click, reserved for livekit reject");
break;
}
case VOICE_MSG_BUTTON_ACTION_QUADRUPLE_CLICK:
{
/* 四击:拍照识图 */
LISA_LOGI(TAG, "power button quadruple click, image recognition");
voice_msg_pub(VOICE_MSG_BUTTON_IMAGE_RECOGNITION, NULL, 0);
break;
}
case VOICE_MSG_BUTTON_ACTION_QUINTUPLE_CLICK:
case VOICE_MSG_BUTTON_ACTION_SEXTUPLE_CLICK:
case VOICE_MSG_BUTTON_ACTION_SEPTUPLE_CLICK:
{
struct app_datas *app_datas = get_app_datas();
/* 连击 >=5进入 BLE 配网并打开信息页 */
LISA_LOGI(TAG, "power button multi click, enter BLE config");
if (app_datas != NULL && !app_datas->wifi_connected) {
player_mgr_play(LOCAL, app_tone_get_url(TONE_ID_70), 0);
}
vTaskDelay(pdMS_TO_TICKS(1000));
network_reset();
app_ble_adv_start(0, 1);
voice_msg_pub(VOICE_MSG_CLOUD_OPEN_INFO, NULL, 0);
break;
}
case VOICE_MSG_BUTTON_ACTION_REPEAT_CLICK:
{
/* 连击 >=8恢复出厂 */
LISA_LOGI(TAG, "power button repeat click, factory reset");
factory_reset();
break;
}
case VOICE_MSG_BUTTON_ACTION_LONG_HOLD:
{
/* 长按关机USB 供电时忽略)*/
if (power_is_usb_plugged()) {
LISA_LOGI(TAG, "USB connected, ignore long press shutdown");
} else {
LISA_LOGI(TAG, "power button long press hold, shutting down...");
power_shutdown();
}
break;
}
}
}
static void shutdown(void)
{
LISA_LOGI(TAG, "System shutting down...");
pa_manager_onoff(0);
lisa_device_t *disp = lisa_device_get("display");
lisa_display_blanking_on(disp);
lisa_display_set_brightness(disp, 0);
vTaskDelay(pdMS_TO_TICKS(500));
}
int main(int argc, char **argv)
{
LOGI("Application version: %s-%s", PROJECT_VERSION_STR, PROJECT_VERSION_COMMIT);
boot_watchdog_feed();
power_config_t power_cfg = {
.on_shutdown = shutdown,
};
power_init(&power_cfg);
if (!power_wait_settle()) {
power_shutdown();
return 0;
}
battery_init();
voice_msg_sub(VOICE_MSG_SYSTEM_NETWORK_PROBE_SUCCESS, voice_system_network_probe_success, NULL);
voice_msg_sub(VOICE_MSG_BUTTON_CHANGE, button_changed, NULL);
service_led_init();
service_volume_init();
service_brightness_init();
service_button_init();
service_image_init();
#if !CONFIG_4G_MODULE
service_camera_init();
#endif
#if CONFIG_APPLICATION_UI
extern int lisa_ui_init(void);
lisa_ui_init();
#endif
#if CONFIG_WIFI_MANAGER
wifi_mgr_sta_config_t list[8] = {0};
int count = wifi_mgr_storage_search_ap(list, (int)(sizeof(list) / sizeof(list[0])), SEARCH_ALL, NULL);
if (count == 0) {
voice_msg_pub(VOICE_MSG_CLOUD_OPEN_INFO, NULL, 0);
player_mgr_play(LOCAL, app_tone_get_url(TONE_ID_70), 0);
}
#endif
vTaskDelay(pdMS_TO_TICKS(3000));
while (1) {
boot_watchdog_feed();
vTaskDelay(pdMS_TO_TICKS(100));
}
return 0;
}