纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。 Co-authored-by: Cursor <cursoragent@cursor.com>
1889 lines
88 KiB
C
1889 lines
88 KiB
C
/*****************************************************include files **************************************************************************/
|
||
#include "config.h"
|
||
#include "ui.h"
|
||
#include "lvgl.h"
|
||
#include "FLASH/flash.h"
|
||
#include "driver/rtc_io.h"
|
||
#include "esp_heap_caps.h"
|
||
#include <inttypes.h>
|
||
#include <errno.h>
|
||
#include <string.h>
|
||
|
||
#include "LVGL/lvgl_src.h"
|
||
#include "LVGL/lvgl_init.h"
|
||
#include "remapping.h"
|
||
|
||
|
||
#include <stdio.h>
|
||
#include "EMOJI_STORAGE/emoji_storage.h"
|
||
#include <sys/stat.h>
|
||
|
||
#include "esp_lcd_panel_io.h"
|
||
#include "esp_lcd_panel_vendor.h"
|
||
#include "driver/periph_ctrl.h"
|
||
#include "driver/gpio.h"
|
||
#include "BLE/ble_send.h"
|
||
#include "BLE/ble_data_ansy.h"
|
||
#include "esp_timer.h"
|
||
#include "esp_log.h"
|
||
#include "esp_heap_caps.h"
|
||
#include "events_init.h"
|
||
#include "ui_cmd.h"
|
||
#include "UI_DISPATCH/ui_dispatch.h"
|
||
#include "custom.h"
|
||
#include "font_runtime.h"
|
||
#include "main.h"
|
||
#include "freertos/FreeRTOS.h"
|
||
#include "freertos/task.h"
|
||
#include "MOTOR/motor.h"
|
||
#include "SCREEN/screen_init.h"
|
||
#include "SPEECH/speech_app.h"
|
||
#include "lvgl_lottie.h"
|
||
#include "MOTOR/motor_control.h"
|
||
|
||
/******************************************************* variable declaration ************************************************************************/
|
||
lv_obj_t *new_lottie = NULL;
|
||
const unsigned char lottie_data[] = { //测试显示屏的数组类型动画
|
||
0x7b, 0x22, 0x76, 0x22, 0x3a, 0x22, 0x35, 0x2e, 0x36, 0x2e, 0x31, 0x30, 0x22, 0x2c, 0x22, 0x66,
|
||
0x72, 0x22, 0x3a, 0x33, 0x30, 0x2c, 0x22, 0x69, 0x70, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70,
|
||
0x22, 0x3a, 0x39, 0x30, 0x2c, 0x22, 0x77, 0x22, 0x3a, 0x35, 0x30, 0x32, 0x2c, 0x22, 0x68, 0x22,
|
||
0x3a, 0x34, 0x31, 0x30, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22, 0x64, 0x65, 0x66, 0x61, 0x75,
|
||
0x6c, 0x74, 0x22, 0x2c, 0x22, 0x64, 0x64, 0x64, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x61, 0x73, 0x73,
|
||
0x65, 0x74, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x22,
|
||
0x3a, 0x5b, 0x7b, 0x22, 0x64, 0x64, 0x64, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x6e, 0x64, 0x22,
|
||
0x3a, 0x31, 0x2c, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x34, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22,
|
||
0x22, 0x2c, 0x22, 0x73, 0x72, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x6b, 0x73, 0x22, 0x3a, 0x7b, 0x22,
|
||
0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x31, 0x30,
|
||
0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x31, 0x7d, 0x2c, 0x22, 0x72, 0x22, 0x3a, 0x7b,
|
||
0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22,
|
||
0x3a, 0x31, 0x30, 0x7d, 0x2c, 0x22, 0x70, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x31, 0x2c,
|
||
0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30,
|
||
0x2e, 0x36, 0x36, 0x37, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a,
|
||
0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e, 0x33, 0x33, 0x33, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x30,
|
||
0x7d, 0x2c, 0x22, 0x74, 0x22, 0x3a, 0x34, 0x31, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x31, 0x38,
|
||
0x36, 0x2e, 0x32, 0x30, 0x31, 0x2c, 0x32, 0x32, 0x33, 0x2e, 0x36, 0x38, 0x39, 0x2c, 0x30, 0x5d,
|
||
0x2c, 0x22, 0x74, 0x6f, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x31, 0x2e, 0x36, 0x36, 0x37, 0x2c, 0x30,
|
||
0x5d, 0x2c, 0x22, 0x74, 0x69, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x2c, 0x30, 0x5d, 0x7d, 0x2c,
|
||
0x7b, 0x22, 0x69, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e, 0x36, 0x36, 0x37, 0x2c,
|
||
0x22, 0x79, 0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a,
|
||
0x30, 0x2e, 0x33, 0x33, 0x33, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x22, 0x74, 0x22,
|
||
0x3a, 0x34, 0x34, 0x2e, 0x32, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x31, 0x38, 0x36, 0x2e, 0x32,
|
||
0x30, 0x31, 0x2c, 0x32, 0x33, 0x33, 0x2e, 0x36, 0x38, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x74,
|
||
0x6f, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x74, 0x69, 0x22, 0x3a,
|
||
0x5b, 0x30, 0x2c, 0x31, 0x2e, 0x36, 0x36, 0x37, 0x2c, 0x30, 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74,
|
||
0x22, 0x3a, 0x34, 0x37, 0x2e, 0x34, 0x30, 0x30, 0x33, 0x39, 0x30, 0x36, 0x32, 0x35, 0x2c, 0x22,
|
||
0x73, 0x22, 0x3a, 0x5b, 0x31, 0x38, 0x36, 0x2e, 0x32, 0x30, 0x31, 0x2c, 0x32, 0x32, 0x33, 0x2e,
|
||
0x36, 0x38, 0x39, 0x2c, 0x30, 0x5d, 0x7d, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x32, 0x7d,
|
||
0x2c, 0x22, 0x61, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a,
|
||
0x5b, 0x30, 0x2c, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x7d, 0x2c,
|
||
0x22, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b,
|
||
0x31, 0x30, 0x30, 0x2c, 0x31, 0x30, 0x30, 0x2c, 0x31, 0x30, 0x30, 0x5d, 0x2c, 0x22, 0x69, 0x78,
|
||
0x22, 0x3a, 0x36, 0x7d, 0x7d, 0x2c, 0x22, 0x61, 0x6f, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73, 0x68,
|
||
0x61, 0x70, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x67, 0x72,
|
||
0x22, 0x2c, 0x22, 0x69, 0x74, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x6e, 0x64, 0x22, 0x3a, 0x30,
|
||
0x2c, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x73, 0x68, 0x22, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a,
|
||
0x31, 0x2c, 0x22, 0x6b, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x6b,
|
||
0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e, 0x36,
|
||
0x36, 0x37, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22,
|
||
0x78, 0x22, 0x3a, 0x30, 0x2e, 0x33, 0x33, 0x33, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x30, 0x7d, 0x2c,
|
||
0x22, 0x74, 0x22, 0x3a, 0x34, 0x31, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x22,
|
||
0x3a, 0x5b, 0x5b, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30,
|
||
0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30,
|
||
0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x2e, 0x35, 0x31, 0x37, 0x2c, 0x2d, 0x30, 0x2e, 0x34, 0x39, 0x31,
|
||
0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x34, 0x2e, 0x38, 0x38,
|
||
0x35, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x5d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x5b, 0x5b,
|
||
0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c,
|
||
0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x35, 0x2e, 0x35, 0x33, 0x39, 0x5d,
|
||
0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x34, 0x2e, 0x38, 0x36, 0x36, 0x2c, 0x30, 0x2e,
|
||
0x34, 0x33, 0x33, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x35, 0x2e,
|
||
0x32, 0x30, 0x39, 0x5d, 0x5d, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x5b, 0x5b, 0x34, 0x32, 0x2e, 0x37,
|
||
0x39, 0x2c, 0x33, 0x38, 0x2e, 0x30, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x2d, 0x34, 0x32, 0x2e, 0x37,
|
||
0x39, 0x2c, 0x33, 0x38, 0x2e, 0x30, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x32, 0x2e, 0x32,
|
||
0x32, 0x32, 0x2c, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x39, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x32, 0x2e,
|
||
0x32, 0x32, 0x32, 0x2c, 0x2d, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x38, 0x5d, 0x2c, 0x5b, 0x2d, 0x34,
|
||
0x31, 0x2e, 0x39, 0x35, 0x34, 0x2c, 0x2d, 0x33, 0x37, 0x2e, 0x39, 0x39, 0x33, 0x5d, 0x2c, 0x5b,
|
||
0x34, 0x33, 0x2e, 0x36, 0x32, 0x36, 0x2c, 0x2d, 0x33, 0x30, 0x2e, 0x33, 0x37, 0x39, 0x5d, 0x2c,
|
||
0x5b, 0x35, 0x32, 0x2e, 0x32, 0x32, 0x32, 0x2c, 0x2d, 0x32, 0x30, 0x2e, 0x39, 0x38, 0x34, 0x5d,
|
||
0x2c, 0x5b, 0x35, 0x32, 0x2e, 0x32, 0x32, 0x32, 0x2c, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x39, 0x5d,
|
||
0x5d, 0x2c, 0x22, 0x63, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x7d, 0x5d, 0x7d, 0x2c, 0x7b, 0x22,
|
||
0x69, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e, 0x36, 0x36, 0x37, 0x2c, 0x22, 0x79,
|
||
0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e,
|
||
0x33, 0x33, 0x33, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x22, 0x74, 0x22, 0x3a, 0x34,
|
||
0x34, 0x2e, 0x32, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x22, 0x3a, 0x5b, 0x5b,
|
||
0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b,
|
||
0x30, 0x2c, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b,
|
||
0x2d, 0x35, 0x2e, 0x35, 0x31, 0x37, 0x2c, 0x2d, 0x30, 0x2e, 0x34, 0x39, 0x31, 0x5d, 0x2c, 0x5b,
|
||
0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x34, 0x2e, 0x38, 0x38, 0x35, 0x5d, 0x2c,
|
||
0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x5d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x5b, 0x5b, 0x30, 0x2c, 0x30,
|
||
0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c,
|
||
0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x35, 0x2e, 0x35, 0x33, 0x39, 0x5d, 0x2c, 0x5b, 0x30,
|
||
0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x34, 0x2e, 0x38, 0x36, 0x36, 0x2c, 0x30, 0x2e, 0x34, 0x33, 0x33,
|
||
0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x35, 0x2e, 0x32, 0x30, 0x39,
|
||
0x5d, 0x5d, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x5b, 0x5b, 0x34, 0x32, 0x2e, 0x37, 0x31, 0x34, 0x2c,
|
||
0x31, 0x35, 0x2e, 0x35, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x2d, 0x34, 0x32, 0x2e, 0x38, 0x36, 0x36,
|
||
0x2c, 0x31, 0x35, 0x2e, 0x35, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x32, 0x2e, 0x32, 0x39,
|
||
0x39, 0x2c, 0x36, 0x2e, 0x30, 0x39, 0x39, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x32, 0x2e, 0x30, 0x35,
|
||
0x31, 0x2c, 0x36, 0x2e, 0x34, 0x30, 0x32, 0x5d, 0x2c, 0x5b, 0x2d, 0x34, 0x31, 0x2e, 0x37, 0x38,
|
||
0x33, 0x2c, 0x2d, 0x32, 0x2e, 0x39, 0x39, 0x33, 0x5d, 0x2c, 0x5b, 0x34, 0x33, 0x2e, 0x35, 0x35,
|
||
0x2c, 0x2d, 0x32, 0x2e, 0x38, 0x37, 0x39, 0x5d, 0x2c, 0x5b, 0x35, 0x32, 0x2e, 0x31, 0x34, 0x36,
|
||
0x2c, 0x36, 0x2e, 0x35, 0x31, 0x36, 0x5d, 0x2c, 0x5b, 0x35, 0x32, 0x2e, 0x31, 0x34, 0x36, 0x2c,
|
||
0x36, 0x2e, 0x30, 0x39, 0x39, 0x5d, 0x5d, 0x2c, 0x22, 0x63, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65,
|
||
0x7d, 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x22, 0x3a, 0x34, 0x37, 0x2e, 0x34, 0x30, 0x30, 0x33,
|
||
0x39, 0x30, 0x36, 0x32, 0x35, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x22, 0x3a,
|
||
0x5b, 0x5b, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d,
|
||
0x2c, 0x5b, 0x30, 0x2c, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d,
|
||
0x2c, 0x5b, 0x2d, 0x35, 0x2e, 0x35, 0x31, 0x37, 0x2c, 0x2d, 0x30, 0x2e, 0x34, 0x39, 0x31, 0x5d,
|
||
0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x34, 0x2e, 0x38, 0x38, 0x35,
|
||
0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x5d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x5b, 0x5b, 0x30,
|
||
0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x5b,
|
||
0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x35, 0x2e, 0x35, 0x33, 0x39, 0x5d, 0x2c,
|
||
0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x34, 0x2e, 0x38, 0x36, 0x36, 0x2c, 0x30, 0x2e, 0x34,
|
||
0x33, 0x33, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x35, 0x2e, 0x32,
|
||
0x30, 0x39, 0x5d, 0x5d, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x5b, 0x5b, 0x34, 0x32, 0x2e, 0x37, 0x39,
|
||
0x2c, 0x33, 0x38, 0x2e, 0x30, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x2d, 0x34, 0x32, 0x2e, 0x37, 0x39,
|
||
0x2c, 0x33, 0x38, 0x2e, 0x30, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x32, 0x2e, 0x32, 0x32,
|
||
0x32, 0x2c, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x39, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x32, 0x2e, 0x32,
|
||
0x32, 0x32, 0x2c, 0x2d, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x38, 0x5d, 0x2c, 0x5b, 0x2d, 0x34, 0x31,
|
||
0x2e, 0x39, 0x35, 0x34, 0x2c, 0x2d, 0x33, 0x37, 0x2e, 0x39, 0x39, 0x33, 0x5d, 0x2c, 0x5b, 0x34,
|
||
0x33, 0x2e, 0x36, 0x32, 0x36, 0x2c, 0x2d, 0x33, 0x30, 0x2e, 0x33, 0x37, 0x39, 0x5d, 0x2c, 0x5b,
|
||
0x35, 0x32, 0x2e, 0x32, 0x32, 0x32, 0x2c, 0x2d, 0x32, 0x30, 0x2e, 0x39, 0x38, 0x34, 0x5d, 0x2c,
|
||
0x5b, 0x35, 0x32, 0x2e, 0x32, 0x32, 0x32, 0x2c, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x39, 0x5d, 0x5d,
|
||
0x2c, 0x22, 0x63, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x7d, 0x5d, 0x7d, 0x5d, 0x2c, 0x22, 0x69,
|
||
0x78, 0x22, 0x3a, 0x32, 0x7d, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22, 0x20, 0x31, 0x22, 0x2c,
|
||
0x22, 0x6d, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x44, 0x42, 0x45, 0x20, 0x56, 0x65, 0x63, 0x74, 0x6f,
|
||
0x72, 0x20, 0x53, 0x68, 0x61, 0x70, 0x65, 0x20, 0x2d, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22,
|
||
0x2c, 0x22, 0x68, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x7d, 0x2c, 0x7b, 0x22, 0x74,
|
||
0x79, 0x22, 0x3a, 0x22, 0x66, 0x6c, 0x22, 0x2c, 0x22, 0x63, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22,
|
||
0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x30, 0x2e, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||
0x30, 0x30, 0x35, 0x39, 0x36, 0x2c, 0x31, 0x2c, 0x30, 0x2e, 0x37, 0x31, 0x33, 0x37, 0x32, 0x35,
|
||
0x35, 0x30, 0x37, 0x32, 0x35, 0x39, 0x2c, 0x31, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x34,
|
||
0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22,
|
||
0x3a, 0x31, 0x30, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x35, 0x7d, 0x2c, 0x22, 0x72, 0x22,
|
||
0x3a, 0x31, 0x2c, 0x22, 0x62, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22,
|
||
0x20, 0x31, 0x22, 0x2c, 0x22, 0x6d, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x44, 0x42, 0x45, 0x20, 0x56,
|
||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x2d, 0x20,
|
||
0x46, 0x69, 0x6c, 0x6c, 0x22, 0x2c, 0x22, 0x68, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65,
|
||
0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x74, 0x72, 0x22, 0x2c, 0x22, 0x70, 0x22,
|
||
0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30,
|
||
0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x32, 0x7d, 0x2c, 0x22, 0x61, 0x22, 0x3a, 0x7b, 0x22,
|
||
0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x22,
|
||
0x69, 0x78, 0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a,
|
||
0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x31, 0x30, 0x30, 0x2c, 0x31, 0x30, 0x30, 0x5d, 0x2c,
|
||
0x22, 0x69, 0x78, 0x22, 0x3a, 0x33, 0x7d, 0x2c, 0x22, 0x72, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22,
|
||
0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x36, 0x7d,
|
||
0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a,
|
||
0x31, 0x30, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x37, 0x7d, 0x2c, 0x22, 0x73, 0x6b, 0x22,
|
||
0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69,
|
||
0x78, 0x22, 0x3a, 0x34, 0x7d, 0x2c, 0x22, 0x73, 0x61, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a,
|
||
0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x35, 0x7d, 0x2c,
|
||
0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22, 0x22, 0x7d, 0x5d, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22,
|
||
0x22, 0x2c, 0x22, 0x6e, 0x70, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x69, 0x78, 0x22, 0x3a, 0x32,
|
||
0x2c, 0x22, 0x62, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x2c, 0x22,
|
||
0x6d, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x44, 0x42, 0x45, 0x20, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72,
|
||
0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x2c, 0x22, 0x68, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c,
|
||
0x73, 0x65, 0x7d, 0x5d, 0x2c, 0x22, 0x69, 0x70, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22,
|
||
0x3a, 0x39, 0x30, 0x2c, 0x22, 0x73, 0x74, 0x22, 0x3a, 0x34, 0x2c, 0x22, 0x62, 0x6d, 0x22, 0x3a,
|
||
0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x64, 0x64, 0x64, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x6e, 0x64,
|
||
0x22, 0x3a, 0x32, 0x2c, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x34, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a,
|
||
0x22, 0x22, 0x2c, 0x22, 0x73, 0x72, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x6b, 0x73, 0x22, 0x3a, 0x7b,
|
||
0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x31,
|
||
0x30, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x31, 0x7d, 0x2c, 0x22, 0x72, 0x22, 0x3a,
|
||
0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78,
|
||
0x22, 0x3a, 0x31, 0x30, 0x7d, 0x2c, 0x22, 0x70, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x31,
|
||
0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a,
|
||
0x30, 0x2e, 0x36, 0x36, 0x37, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x6f, 0x22,
|
||
0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e, 0x33, 0x33, 0x33, 0x2c, 0x22, 0x79, 0x22, 0x3a,
|
||
0x30, 0x7d, 0x2c, 0x22, 0x74, 0x22, 0x3a, 0x34, 0x31, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x33,
|
||
0x31, 0x36, 0x2e, 0x35, 0x31, 0x39, 0x2c, 0x32, 0x32, 0x33, 0x2e, 0x36, 0x38, 0x39, 0x2c, 0x30,
|
||
0x5d, 0x2c, 0x22, 0x74, 0x6f, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x31, 0x2e, 0x36, 0x36, 0x37, 0x2c,
|
||
0x30, 0x5d, 0x2c, 0x22, 0x74, 0x69, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x2c, 0x30, 0x5d, 0x7d,
|
||
0x2c, 0x7b, 0x22, 0x69, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e, 0x36, 0x36, 0x37,
|
||
0x2c, 0x22, 0x79, 0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22,
|
||
0x3a, 0x30, 0x2e, 0x33, 0x33, 0x33, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x22, 0x74,
|
||
0x22, 0x3a, 0x34, 0x34, 0x2e, 0x32, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x33, 0x31, 0x36, 0x2e,
|
||
0x35, 0x31, 0x39, 0x2c, 0x32, 0x33, 0x33, 0x2e, 0x36, 0x38, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x22,
|
||
0x74, 0x6f, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x74, 0x69, 0x22,
|
||
0x3a, 0x5b, 0x30, 0x2c, 0x31, 0x2e, 0x36, 0x36, 0x37, 0x2c, 0x30, 0x5d, 0x7d, 0x2c, 0x7b, 0x22,
|
||
0x74, 0x22, 0x3a, 0x34, 0x37, 0x2e, 0x34, 0x30, 0x30, 0x33, 0x39, 0x30, 0x36, 0x32, 0x35, 0x2c,
|
||
0x22, 0x73, 0x22, 0x3a, 0x5b, 0x33, 0x31, 0x36, 0x2e, 0x35, 0x31, 0x39, 0x2c, 0x32, 0x32, 0x33,
|
||
0x2e, 0x36, 0x38, 0x39, 0x2c, 0x30, 0x5d, 0x7d, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x32,
|
||
0x7d, 0x2c, 0x22, 0x61, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22,
|
||
0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x7d,
|
||
0x2c, 0x22, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a,
|
||
0x5b, 0x31, 0x30, 0x30, 0x2c, 0x31, 0x30, 0x30, 0x2c, 0x31, 0x30, 0x30, 0x5d, 0x2c, 0x22, 0x69,
|
||
0x78, 0x22, 0x3a, 0x36, 0x7d, 0x7d, 0x2c, 0x22, 0x61, 0x6f, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73,
|
||
0x68, 0x61, 0x70, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x67,
|
||
0x72, 0x22, 0x2c, 0x22, 0x69, 0x74, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x6e, 0x64, 0x22, 0x3a,
|
||
0x30, 0x2c, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x73, 0x68, 0x22, 0x2c, 0x22, 0x69, 0x78, 0x22,
|
||
0x3a, 0x31, 0x2c, 0x22, 0x6b, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x31, 0x2c, 0x22,
|
||
0x6b, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e,
|
||
0x36, 0x36, 0x37, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b,
|
||
0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e, 0x33, 0x33, 0x33, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x30, 0x7d,
|
||
0x2c, 0x22, 0x74, 0x22, 0x3a, 0x34, 0x31, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69,
|
||
0x22, 0x3a, 0x5b, 0x5b, 0x2d, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30,
|
||
0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x5d, 0x2c, 0x5b, 0x30,
|
||
0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x35, 0x2e, 0x35, 0x31, 0x37, 0x2c, 0x2d, 0x30, 0x2e, 0x34, 0x39,
|
||
0x31, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x34, 0x2e, 0x38,
|
||
0x38, 0x35, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x5d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x5b,
|
||
0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c,
|
||
0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x35, 0x2e, 0x35, 0x33, 0x39, 0x5d,
|
||
0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x2d, 0x34, 0x2e, 0x38, 0x36, 0x36, 0x2c, 0x30,
|
||
0x2e, 0x34, 0x33, 0x33, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x35,
|
||
0x2e, 0x32, 0x30, 0x39, 0x5d, 0x5d, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x5b, 0x5b, 0x2d, 0x34, 0x32,
|
||
0x2e, 0x37, 0x39, 0x2c, 0x33, 0x38, 0x2e, 0x30, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x34, 0x32, 0x2e,
|
||
0x37, 0x39, 0x2c, 0x33, 0x38, 0x2e, 0x30, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x35, 0x32, 0x2e, 0x32,
|
||
0x32, 0x32, 0x2c, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x39, 0x5d, 0x2c, 0x5b, 0x35, 0x32, 0x2e, 0x32,
|
||
0x32, 0x32, 0x2c, 0x2d, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x38, 0x5d, 0x2c, 0x5b, 0x34, 0x31, 0x2e,
|
||
0x39, 0x35, 0x34, 0x2c, 0x2d, 0x33, 0x37, 0x2e, 0x39, 0x39, 0x33, 0x5d, 0x2c, 0x5b, 0x2d, 0x34,
|
||
0x33, 0x2e, 0x36, 0x32, 0x36, 0x2c, 0x2d, 0x33, 0x30, 0x2e, 0x33, 0x37, 0x39, 0x5d, 0x2c, 0x5b,
|
||
0x2d, 0x35, 0x32, 0x2e, 0x32, 0x32, 0x32, 0x2c, 0x2d, 0x32, 0x30, 0x2e, 0x39, 0x38, 0x34, 0x5d,
|
||
0x2c, 0x5b, 0x2d, 0x35, 0x32, 0x2e, 0x32, 0x32, 0x32, 0x2c, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x39,
|
||
0x5d, 0x5d, 0x2c, 0x22, 0x63, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x7d, 0x5d, 0x7d, 0x2c, 0x7b,
|
||
0x22, 0x69, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30, 0x2e, 0x36, 0x36, 0x37, 0x2c, 0x22,
|
||
0x79, 0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x78, 0x22, 0x3a, 0x30,
|
||
0x2e, 0x33, 0x33, 0x33, 0x2c, 0x22, 0x79, 0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x22, 0x74, 0x22, 0x3a,
|
||
0x34, 0x34, 0x2e, 0x32, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69, 0x22, 0x3a, 0x5b,
|
||
0x5b, 0x2d, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d,
|
||
0x2c, 0x5b, 0x30, 0x2c, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d,
|
||
0x2c, 0x5b, 0x35, 0x2e, 0x35, 0x31, 0x37, 0x2c, 0x2d, 0x30, 0x2e, 0x34, 0x39, 0x31, 0x5d, 0x2c,
|
||
0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x34, 0x2e, 0x38, 0x38, 0x35, 0x5d,
|
||
0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x5d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x5b, 0x5b, 0x30, 0x2c,
|
||
0x30, 0x5d, 0x2c, 0x5b, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c,
|
||
0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x35, 0x2e, 0x35, 0x33, 0x39, 0x5d, 0x2c, 0x5b, 0x30,
|
||
0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x2d, 0x34, 0x2e, 0x38, 0x36, 0x36, 0x2c, 0x30, 0x2e, 0x34, 0x33,
|
||
0x33, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x35, 0x2e, 0x32, 0x30,
|
||
0x39, 0x5d, 0x5d, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x5b, 0x5b, 0x2d, 0x34, 0x32, 0x2e, 0x35, 0x34,
|
||
0x39, 0x2c, 0x31, 0x35, 0x2e, 0x35, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x34, 0x33, 0x2e, 0x30, 0x33,
|
||
0x31, 0x2c, 0x31, 0x35, 0x2e, 0x35, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x35, 0x32, 0x2e, 0x34, 0x36,
|
||
0x33, 0x2c, 0x36, 0x2e, 0x30, 0x39, 0x39, 0x5d, 0x2c, 0x5b, 0x35, 0x32, 0x2e, 0x34, 0x34, 0x35,
|
||
0x2c, 0x35, 0x2e, 0x34, 0x30, 0x32, 0x5d, 0x2c, 0x5b, 0x34, 0x32, 0x2e, 0x31, 0x37, 0x37, 0x2c,
|
||
0x2d, 0x33, 0x2e, 0x39, 0x39, 0x33, 0x5d, 0x2c, 0x5b, 0x2d, 0x34, 0x33, 0x2e, 0x36, 0x34, 0x34,
|
||
0x2c, 0x2d, 0x34, 0x2e, 0x33, 0x37, 0x39, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x32, 0x2e, 0x32, 0x34,
|
||
0x31, 0x2c, 0x35, 0x2e, 0x30, 0x31, 0x36, 0x5d, 0x2c, 0x5b, 0x2d, 0x35, 0x31, 0x2e, 0x39, 0x38,
|
||
0x31, 0x2c, 0x36, 0x2e, 0x30, 0x39, 0x39, 0x5d, 0x5d, 0x2c, 0x22, 0x63, 0x22, 0x3a, 0x74, 0x72,
|
||
0x75, 0x65, 0x7d, 0x5d, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x22, 0x3a, 0x34, 0x37, 0x2e, 0x34, 0x30,
|
||
0x30, 0x33, 0x39, 0x30, 0x36, 0x32, 0x35, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69,
|
||
0x22, 0x3a, 0x5b, 0x5b, 0x2d, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30,
|
||
0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x5d, 0x2c, 0x5b, 0x30,
|
||
0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x35, 0x2e, 0x35, 0x31, 0x37, 0x2c, 0x2d, 0x30, 0x2e, 0x34, 0x39,
|
||
0x31, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x34, 0x2e, 0x38,
|
||
0x38, 0x35, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x5d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x5b,
|
||
0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x35, 0x2e, 0x32, 0x30, 0x39, 0x2c, 0x30, 0x5d, 0x2c,
|
||
0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x2d, 0x35, 0x2e, 0x35, 0x33, 0x39, 0x5d,
|
||
0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x2d, 0x34, 0x2e, 0x38, 0x36, 0x36, 0x2c, 0x30,
|
||
0x2e, 0x34, 0x33, 0x33, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x35,
|
||
0x2e, 0x32, 0x30, 0x39, 0x5d, 0x5d, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x5b, 0x5b, 0x2d, 0x34, 0x32,
|
||
0x2e, 0x37, 0x39, 0x2c, 0x33, 0x38, 0x2e, 0x30, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x34, 0x32, 0x2e,
|
||
0x37, 0x39, 0x2c, 0x33, 0x38, 0x2e, 0x30, 0x33, 0x31, 0x5d, 0x2c, 0x5b, 0x35, 0x32, 0x2e, 0x32,
|
||
0x32, 0x32, 0x2c, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x39, 0x5d, 0x2c, 0x5b, 0x35, 0x32, 0x2e, 0x32,
|
||
0x32, 0x32, 0x2c, 0x2d, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x38, 0x5d, 0x2c, 0x5b, 0x34, 0x31, 0x2e,
|
||
0x39, 0x35, 0x34, 0x2c, 0x2d, 0x33, 0x37, 0x2e, 0x39, 0x39, 0x33, 0x5d, 0x2c, 0x5b, 0x2d, 0x34,
|
||
0x33, 0x2e, 0x36, 0x32, 0x36, 0x2c, 0x2d, 0x33, 0x30, 0x2e, 0x33, 0x37, 0x39, 0x5d, 0x2c, 0x5b,
|
||
0x2d, 0x35, 0x32, 0x2e, 0x32, 0x32, 0x32, 0x2c, 0x2d, 0x32, 0x30, 0x2e, 0x39, 0x38, 0x34, 0x5d,
|
||
0x2c, 0x5b, 0x2d, 0x35, 0x32, 0x2e, 0x32, 0x32, 0x32, 0x2c, 0x32, 0x38, 0x2e, 0x35, 0x39, 0x39,
|
||
0x5d, 0x5d, 0x2c, 0x22, 0x63, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x7d, 0x5d, 0x7d, 0x5d, 0x2c,
|
||
0x22, 0x69, 0x78, 0x22, 0x3a, 0x32, 0x7d, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22, 0x20, 0x31,
|
||
0x22, 0x2c, 0x22, 0x6d, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x44, 0x42, 0x45, 0x20, 0x56, 0x65, 0x63,
|
||
0x74, 0x6f, 0x72, 0x20, 0x53, 0x68, 0x61, 0x70, 0x65, 0x20, 0x2d, 0x20, 0x47, 0x72, 0x6f, 0x75,
|
||
0x70, 0x22, 0x2c, 0x22, 0x68, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x7d, 0x2c, 0x7b,
|
||
0x22, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x66, 0x6c, 0x22, 0x2c, 0x22, 0x63, 0x22, 0x3a, 0x7b, 0x22,
|
||
0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x30, 0x2e, 0x34, 0x30, 0x30, 0x30,
|
||
0x30, 0x30, 0x30, 0x30, 0x35, 0x39, 0x36, 0x2c, 0x31, 0x2c, 0x30, 0x2e, 0x37, 0x31, 0x33, 0x37,
|
||
0x32, 0x35, 0x35, 0x30, 0x37, 0x32, 0x35, 0x39, 0x2c, 0x31, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22,
|
||
0x3a, 0x34, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22,
|
||
0x6b, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x35, 0x7d, 0x2c, 0x22,
|
||
0x72, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x62, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6e, 0x6d, 0x22,
|
||
0x3a, 0x22, 0x20, 0x31, 0x22, 0x2c, 0x22, 0x6d, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x44, 0x42, 0x45,
|
||
0x20, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x20,
|
||
0x2d, 0x20, 0x46, 0x69, 0x6c, 0x6c, 0x22, 0x2c, 0x22, 0x68, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c,
|
||
0x73, 0x65, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x74, 0x72, 0x22, 0x2c, 0x22,
|
||
0x70, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x30,
|
||
0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x32, 0x7d, 0x2c, 0x22, 0x61, 0x22, 0x3a,
|
||
0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x5d,
|
||
0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61,
|
||
0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x31, 0x30, 0x30, 0x2c, 0x31, 0x30, 0x30,
|
||
0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x33, 0x7d, 0x2c, 0x22, 0x72, 0x22, 0x3a, 0x7b, 0x22,
|
||
0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a,
|
||
0x36, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b,
|
||
0x22, 0x3a, 0x31, 0x30, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x37, 0x7d, 0x2c, 0x22, 0x73,
|
||
0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30, 0x2c,
|
||
0x22, 0x69, 0x78, 0x22, 0x3a, 0x34, 0x7d, 0x2c, 0x22, 0x73, 0x61, 0x22, 0x3a, 0x7b, 0x22, 0x61,
|
||
0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x35,
|
||
0x7d, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22, 0x22, 0x7d, 0x5d, 0x2c, 0x22, 0x6e, 0x6d, 0x22,
|
||
0x3a, 0x22, 0x22, 0x2c, 0x22, 0x6e, 0x70, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x69, 0x78, 0x22,
|
||
0x3a, 0x32, 0x2c, 0x22, 0x62, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31,
|
||
0x2c, 0x22, 0x6d, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x44, 0x42, 0x45, 0x20, 0x56, 0x65, 0x63, 0x74,
|
||
0x6f, 0x72, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x2c, 0x22, 0x68, 0x64, 0x22, 0x3a, 0x66,
|
||
0x61, 0x6c, 0x73, 0x65, 0x7d, 0x5d, 0x2c, 0x22, 0x69, 0x70, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f,
|
||
0x70, 0x22, 0x3a, 0x39, 0x30, 0x2c, 0x22, 0x73, 0x74, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x62, 0x6d,
|
||
0x22, 0x3a, 0x30, 0x7d, 0x2c, 0x7b, 0x22, 0x64, 0x64, 0x64, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69,
|
||
0x6e, 0x64, 0x22, 0x3a, 0x33, 0x2c, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x34, 0x2c, 0x22, 0x6e, 0x6d,
|
||
0x22, 0x3a, 0x22, 0x64, 0x6f, 0x74, 0x22, 0x2c, 0x22, 0x73, 0x72, 0x22, 0x3a, 0x31, 0x2c, 0x22,
|
||
0x6b, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c,
|
||
0x22, 0x6b, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x31, 0x7d,
|
||
0x2c, 0x22, 0x72, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a,
|
||
0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x30, 0x7d, 0x2c, 0x22, 0x70, 0x22, 0x3a, 0x7b,
|
||
0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x32, 0x35, 0x30, 0x2e, 0x39,
|
||
0x37, 0x37, 0x2c, 0x32, 0x30, 0x35, 0x2e, 0x33, 0x39, 0x33, 0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x69,
|
||
0x78, 0x22, 0x3a, 0x32, 0x7d, 0x2c, 0x22, 0x61, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30,
|
||
0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x69, 0x78,
|
||
0x22, 0x3a, 0x31, 0x7d, 0x2c, 0x22, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c,
|
||
0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x31, 0x30, 0x30, 0x2c, 0x31, 0x30, 0x30, 0x2c, 0x31, 0x30, 0x30,
|
||
0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x36, 0x7d, 0x7d, 0x2c, 0x22, 0x61, 0x6f, 0x22, 0x3a,
|
||
0x30, 0x2c, 0x22, 0x73, 0x68, 0x61, 0x70, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x74, 0x79,
|
||
0x22, 0x3a, 0x22, 0x67, 0x72, 0x22, 0x2c, 0x22, 0x69, 0x74, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x69,
|
||
0x6e, 0x64, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x73, 0x68, 0x22, 0x2c,
|
||
0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x6b, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22,
|
||
0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x69, 0x22, 0x3a, 0x5b, 0x5b, 0x30, 0x2c,
|
||
0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b,
|
||
0x30, 0x2c, 0x30, 0x5d, 0x5d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x5b, 0x5b, 0x30, 0x2c, 0x30, 0x5d,
|
||
0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x5b, 0x30, 0x2c,
|
||
0x30, 0x5d, 0x5d, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x5b, 0x5b, 0x32, 0x35, 0x31, 0x2c, 0x32, 0x30,
|
||
0x35, 0x5d, 0x2c, 0x5b, 0x2d, 0x32, 0x35, 0x31, 0x2c, 0x32, 0x30, 0x35, 0x5d, 0x2c, 0x5b, 0x2d,
|
||
0x32, 0x35, 0x31, 0x2c, 0x2d, 0x32, 0x30, 0x35, 0x5d, 0x2c, 0x5b, 0x32, 0x35, 0x31, 0x2c, 0x2d,
|
||
0x32, 0x30, 0x35, 0x5d, 0x5d, 0x2c, 0x22, 0x63, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x7d, 0x2c,
|
||
0x22, 0x69, 0x78, 0x22, 0x3a, 0x32, 0x7d, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22, 0x20, 0x31,
|
||
0x22, 0x2c, 0x22, 0x6d, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x44, 0x42, 0x45, 0x20, 0x56, 0x65, 0x63,
|
||
0x74, 0x6f, 0x72, 0x20, 0x53, 0x68, 0x61, 0x70, 0x65, 0x20, 0x2d, 0x20, 0x47, 0x72, 0x6f, 0x75,
|
||
0x70, 0x22, 0x2c, 0x22, 0x68, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x7d, 0x2c, 0x7b,
|
||
0x22, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x66, 0x6c, 0x22, 0x2c, 0x22, 0x63, 0x22, 0x3a, 0x7b, 0x22,
|
||
0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x2c, 0x30, 0x2c,
|
||
0x31, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x34, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b,
|
||
0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x2c, 0x22, 0x69,
|
||
0x78, 0x22, 0x3a, 0x35, 0x7d, 0x2c, 0x22, 0x72, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x62, 0x6d, 0x22,
|
||
0x3a, 0x30, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22, 0x20, 0x31, 0x22, 0x2c, 0x22, 0x6d, 0x6e,
|
||
0x22, 0x3a, 0x22, 0x41, 0x44, 0x42, 0x45, 0x20, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x47,
|
||
0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x2d, 0x20, 0x46, 0x69, 0x6c, 0x6c, 0x22, 0x2c, 0x22,
|
||
0x68, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x7d, 0x2c, 0x7b, 0x22, 0x74, 0x79, 0x22,
|
||
0x3a, 0x22, 0x74, 0x72, 0x22, 0x2c, 0x22, 0x70, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30,
|
||
0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a,
|
||
0x32, 0x7d, 0x2c, 0x22, 0x61, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b,
|
||
0x22, 0x3a, 0x5b, 0x30, 0x2c, 0x30, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x7d, 0x2c,
|
||
0x22, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x5b,
|
||
0x31, 0x30, 0x30, 0x2c, 0x31, 0x30, 0x30, 0x5d, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x33, 0x7d,
|
||
0x2c, 0x22, 0x72, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a,
|
||
0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x36, 0x7d, 0x2c, 0x22, 0x6f, 0x22, 0x3a, 0x7b, 0x22,
|
||
0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x2c, 0x22, 0x69, 0x78,
|
||
0x22, 0x3a, 0x37, 0x7d, 0x2c, 0x22, 0x73, 0x6b, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30,
|
||
0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x34, 0x7d, 0x2c, 0x22,
|
||
0x73, 0x61, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x30,
|
||
0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x35, 0x7d, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22, 0x22,
|
||
0x7d, 0x5d, 0x2c, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x22, 0x20, 0x31, 0x22, 0x2c, 0x22, 0x6e, 0x70,
|
||
0x22, 0x3a, 0x32, 0x2c, 0x22, 0x63, 0x69, 0x78, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x62, 0x6d, 0x22,
|
||
0x3a, 0x30, 0x2c, 0x22, 0x69, 0x78, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x6d, 0x6e, 0x22, 0x3a, 0x22,
|
||
0x41, 0x44, 0x42, 0x45, 0x20, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x47, 0x72, 0x6f, 0x75,
|
||
0x70, 0x22, 0x2c, 0x22, 0x68, 0x64, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x7d, 0x5d, 0x2c,
|
||
0x22, 0x69, 0x70, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x39, 0x30, 0x2c, 0x22,
|
||
0x73, 0x74, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x62, 0x6d, 0x22, 0x3a, 0x30, 0x7d, 0x5d, 0x2c, 0x22,
|
||
0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x7d
|
||
};
|
||
const unsigned int lottie_data_size = 5308;
|
||
|
||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||
TaskHandle_t change_task_handle = NULL;
|
||
static QueueHandle_t g_result_que = NULL;
|
||
|
||
static volatile int task_flag = 0;
|
||
|
||
|
||
// 阻止自动休眠的标志 (用于 OTA、哨兵模式等不能中断的场景)
|
||
bool block_auto_sleep = false;
|
||
const char *default_emoji_path = "/extflash/0/default.json";
|
||
const char *cold_emoji_path = "/extflash/0/cold.json";
|
||
|
||
|
||
volatile uint16_t g_ble_play_sticker_pending_action_id = 0;
|
||
volatile uint8_t g_ble_play_sticker_pending_direction = 0x00;
|
||
int lottie_id = 0;
|
||
int last_lottie_id = 0;
|
||
bool back2default = false;
|
||
bool first_display = true;
|
||
uint32_t g_current_emoji_event = 0; // 记录当前播放的事件类型
|
||
/* 当前播放的 action_id,用于去抖;在播放状态重置后清零,允许同动作再次触发 */
|
||
uint16_t current_emoji_action_id = 0;
|
||
/* completed_cb 回灌 pending 时,允许同 action_id 重播一次,避免被去抖误吞 */
|
||
// static volatile bool g_allow_same_action_replay_once = false;
|
||
|
||
static TaskHandle_t lvgl_task_handle = NULL;
|
||
|
||
bool lvgl_port_task_is_current(void)
|
||
{
|
||
return (lvgl_task_handle != NULL && xTaskGetCurrentTaskHandle() == lvgl_task_handle);
|
||
}
|
||
static esp_timer_handle_t lvgl_tick_timer_handle = NULL;
|
||
static void *lvgl_draw_buf1 = NULL;
|
||
static void *lvgl_draw_buf2 = NULL;
|
||
static bool lvgl_deinitialized = false;
|
||
static bool g_auto_sleep_checker_inited = false;
|
||
|
||
|
||
volatile char *emoji_file_path = {0};
|
||
|
||
char g_play_lottie_path[128] = {0};
|
||
|
||
static volatile bool g_lottie_switch_in_progress = false;
|
||
typedef struct {
|
||
char path[128];
|
||
} lottie_switch_req_t;
|
||
|
||
static QueueHandle_t g_lottie_switch_queue = NULL;
|
||
static QueueHandle_t g_change_action_queue = NULL;
|
||
|
||
// LVGL 库不是线程安全的,本示例将从不同的任务调用 LVGL API,因此使用互斥锁来保护它
|
||
_lock_t lvgl_api_lock;
|
||
|
||
/* 注:else 分支处理所有 play_sticker(非音乐/非哨兵),统一设 last_lottie_id=0 阻止播完立即回 default */
|
||
|
||
|
||
char pending_sentinel_switch_path[128] = {0}; /* NOTIFY_SENTINEL_DO_SWITCH 时使用 */
|
||
char g_current_lottie_path[128] = {0};
|
||
|
||
|
||
/* music_listen 总播放遍数(每个大循环 intro 之后);2 表示连播两遍 */
|
||
#define MUSIC_LISTEN_TOTAL_PASSES 8
|
||
#if (MUSIC_LISTEN_TOTAL_PASSES < 1)
|
||
#error "MUSIC_LISTEN_TOTAL_PASSES must be >= 1"
|
||
#endif
|
||
#define CHANGE_ACTION_QUEUE_LEN 8
|
||
|
||
|
||
static int64_t last_time = 0;
|
||
static int64_t now = 0;
|
||
|
||
extern uint8_t g_current_brightness;
|
||
extern struct stat file_stat;
|
||
extern int current_page_idx;
|
||
extern const char *cmd_phoneme[5];
|
||
extern lv_obj_t *lottie;
|
||
extern lv_obj_t *current_lottie;
|
||
extern uint8_t *canvas_fb;
|
||
|
||
extern qspi_amoled_vendor_config_t vendor_config;
|
||
|
||
#define LOTTIE_TARGET_FPS 30
|
||
|
||
#if EXAMPLE_USE_TOUCH
|
||
extern esp_lcd_touch_handle_t tp;
|
||
#endif
|
||
/******************************************************* functions declaration ************************************************************************/
|
||
|
||
// 外部函数声明
|
||
extern void show_random_fortune_result(void);
|
||
extern void perform_draw(void);
|
||
extern volatile bool is_playing_music;
|
||
|
||
extern void toggle_sleep_mode(bool enter_sleep);
|
||
extern volatile bool is_system_sleeping;
|
||
extern void load_timeout_from_nvs(void);
|
||
extern void auto_sleep_checker_cb(lv_timer_t *timer);
|
||
/******************************************************* functions definition ************************************************************************/
|
||
|
||
|
||
//给change_task 投递一条动作指令 确保最新的指令能进去并通知任务处理
|
||
bool change_task_post_action(uint16_t action_id)
|
||
{
|
||
if (g_change_action_queue == NULL)
|
||
{
|
||
ESP_LOGW(TAG_LVGL, "post action failed: g_change_action_queue is NULL (action=0x%04X)", action_id);
|
||
return false;
|
||
}
|
||
|
||
BaseType_t qret = xQueueSend(g_change_action_queue, &action_id, 0);
|
||
if (qret != pdPASS)
|
||
{
|
||
uint16_t dropped = 0;
|
||
(void)xQueueReceive(g_change_action_queue, &dropped, 0);
|
||
qret = xQueueSend(g_change_action_queue, &action_id, 0);
|
||
ESP_LOGW(TAG_LVGL,
|
||
"action queue full, drop oldest=0x%04X enqueue newest=0x%04X ret=%d",
|
||
dropped, action_id, (int)qret);
|
||
}
|
||
|
||
if (change_task_handle != NULL)
|
||
{
|
||
(void)xTaskNotify(change_task_handle, (uint32_t)NOTIFY_ACTION_QUEUE_READY, eSetValueWithOverwrite);
|
||
}
|
||
return (qret == pdPASS);
|
||
}
|
||
|
||
/**
|
||
* default / calling / music_listen 等在 switch 里常设为无限循环且 completed_cb=NULL,
|
||
* lottie_anim_completed_cb 不会跑,BLE 侧 pending 无法被消费;remapping 对未知 id(如 0x0000)
|
||
* 回落到 default.json 时还会把 g_ble_play_sticker_active 永久置 true,后续指令只能进 pending。
|
||
*/
|
||
static void ble_flush_pending_on_idle_infinite_lottie(const char *file_path)
|
||
{
|
||
if (g_ble_play_sticker_pending_valid && change_task_handle)
|
||
{
|
||
uint16_t next_action_id = g_ble_play_sticker_pending_action_id;
|
||
uint8_t next_direction = g_ble_play_sticker_pending_direction;
|
||
g_ble_play_sticker_pending_valid = false;
|
||
g_ble_play_sticker_pending_action_id = 0;
|
||
g_ble_play_sticker_pending_direction = 0x00;
|
||
g_ble_play_sticker_active = true;
|
||
|
||
ESP_LOGI("BLE_STICKER_GUARD",
|
||
"idle_inf_loop: consume pending play_sticker=0x%04X dir=0x%02X (no lottie completed_cb)",
|
||
next_action_id, next_direction);
|
||
current_emoji_action_id = 0;
|
||
(void)change_task_post_action(next_action_id);
|
||
if (next_direction <= 0x07 && !lvgl_lottie_should_skip_play_sticker_motor(next_action_id, next_direction))
|
||
(void)motor_post_play_sticker_direction(next_direction);
|
||
return;
|
||
}
|
||
|
||
if (file_path && strstr(file_path, "/default.json") != NULL)
|
||
g_ble_play_sticker_active = false;
|
||
}
|
||
|
||
//LCD 刷新完成回调,通知 LVGL 一帧 flush 已结束。
|
||
bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
|
||
{
|
||
last_time = now;
|
||
now = esp_timer_get_time();
|
||
lv_display_t *disp = (lv_display_t *)user_ctx;
|
||
lv_display_flush_ready(disp);
|
||
return false;
|
||
}
|
||
|
||
//LVGL 刷新回调函数 刷新好一部分画面之后发给屏幕
|
||
static void example_lvgl_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
|
||
{
|
||
panel_handle = lv_display_get_user_data(disp);
|
||
int offsetx1 = area->x1;
|
||
int offsetx2 = area->x2;
|
||
int offsety1 = area->y1;
|
||
int offsety2 = area->y2;
|
||
esp_err_t ret;
|
||
|
||
#if LV_COLOR_DEPTH == 16
|
||
lv_draw_sw_rgb565_swap(px_map, (offsetx2 + 1 - offsetx1) * (offsety2 + 1 - offsety1));
|
||
ret = esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, px_map);
|
||
#elif LV_COLOR_DEPTH == 24
|
||
ret = esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, px_map);
|
||
#endif
|
||
if (ret != ESP_OK)
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "draw_bitmap failed (%s), manually completing flush to prevent UI freeze", esp_err_to_name(ret));
|
||
lv_display_flush_ready(disp);
|
||
}
|
||
}
|
||
|
||
//将刷新区域对齐到偶数边界,满足硬件/驱动要求。
|
||
static void example_lvgl_rounder_cb(lv_event_t *e)
|
||
{
|
||
lv_area_t *area = lv_event_get_param(e);
|
||
|
||
uint16_t x1 = area->x1;
|
||
uint16_t x2 = area->x2;
|
||
uint16_t y1 = area->y1;
|
||
uint16_t y2 = area->y2;
|
||
area->x1 = (x1 >> 1) << 1;
|
||
area->y1 = (y1 >> 1) << 1;
|
||
area->x2 = ((x2 >> 1) << 1) + 1;
|
||
area->y2 = ((y2 >> 1) << 1) + 1;
|
||
}
|
||
|
||
#if EXAMPLE_USE_TOUCH
|
||
extern bool is_anim_paused;
|
||
|
||
//触摸输入读取回调;同时处理休眠唤醒、动画暂停/恢复、活跃时间刷新。
|
||
static void example_lvgl_touch_cb(lv_indev_t *indev, lv_indev_data_t *data)
|
||
{
|
||
esp_lcd_touch_handle_t tp = (esp_lcd_touch_handle_t)lv_indev_get_user_data(indev);
|
||
esp_lcd_touch_point_data_t point_data;
|
||
uint8_t tp_cnt = 0;
|
||
|
||
esp_lcd_touch_read_data(tp);
|
||
esp_err_t err = esp_lcd_touch_get_data(tp, &point_data, &tp_cnt, 1);
|
||
|
||
if (err == ESP_OK && tp_cnt > 0)
|
||
{
|
||
data->point.x = point_data.x;
|
||
data->point.y = point_data.y;
|
||
data->state = LV_INDEV_STATE_PRESSED;
|
||
|
||
/* 如果处于”系统休眠”,点击屏幕触发唤醒并切回默认表情 */
|
||
bool woke_up = false;
|
||
if (is_system_sleeping)
|
||
{
|
||
/* 先切回默认页(屏尚黑,无动画),再开屏,避免休眠界残影 */
|
||
back2default = true;
|
||
ui_change_page(0, LV_SCR_LOAD_ANIM_NONE);
|
||
toggle_sleep_mode(false);
|
||
/* 重置输入设备状态,清除唤醒触摸残留,保证下次手势能被正确识别 */
|
||
lv_indev_reset(indev, NULL);
|
||
woke_up = true;
|
||
}
|
||
|
||
/* 任何触摸都刷新自动休眠活跃时间,避免唤醒后立即再次休眠 */
|
||
system_keep_alive();
|
||
ui_reset_idle_timer();
|
||
|
||
/* 刚唤醒时不要立刻暂停动画,避免看不到默认表情播放 */
|
||
if (!woke_up && !is_anim_paused && current_lottie != NULL)
|
||
{
|
||
lv_anim_t *a = lv_lottie_get_anim(current_lottie);
|
||
if (a)
|
||
{
|
||
lv_anim_pause(a);
|
||
is_anim_paused = true;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
data->state = LV_INDEV_STATE_RELEASED;
|
||
|
||
if (is_anim_paused && current_lottie != NULL)
|
||
{
|
||
lv_anim_t *a = lv_lottie_get_anim(current_lottie);
|
||
if (a)
|
||
{
|
||
lv_anim_resume(a);
|
||
is_anim_paused = false;
|
||
// ESP_LOGI(TAG_LVGL, "抬起:恢复渲染");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//周期递增 LVGL tick(时间基准)。
|
||
static void example_increase_lvgl_tick(void *arg)
|
||
{
|
||
/* 告诉 LVGL 已经过去了多少毫秒 */
|
||
lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
|
||
}
|
||
|
||
//LVGL 主循环任务:执行 ui_cmd_drain + lv_timer_handler。
|
||
static void example_lvgl_port_task(void *arg)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "Starting LVGL task");
|
||
uint32_t time_till_next_ms = 0;
|
||
|
||
if (canvas_fb == NULL)
|
||
{
|
||
canvas_fb = heap_caps_malloc(LOTTIE_ANIM_WIDTH * LOTTIE_ANIM_HEIGHT * 4, MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA);
|
||
if (canvas_fb == NULL)
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "Failed to allocate canvas_fb buffer");
|
||
return;
|
||
}
|
||
}
|
||
lv_obj_t * ui_Screen_Lottie = lv_obj_create(NULL);
|
||
lv_obj_remove_flag(ui_Screen_Lottie, LV_OBJ_FLAG_SCROLLABLE);
|
||
lv_obj_set_style_bg_color(ui_Screen_Lottie, lv_color_black(), 0);
|
||
lv_obj_set_style_bg_opa(ui_Screen_Lottie, LV_OPA_COVER, 0);
|
||
new_lottie = lv_lottie_create(ui_Screen_Lottie);
|
||
lv_lottie_set_src_data(new_lottie, lottie_data, lottie_data_size);
|
||
lv_lottie_set_buffer(new_lottie, LOTTIE_ANIM_WIDTH, LOTTIE_ANIM_HEIGHT, canvas_fb);
|
||
lv_anim_t *anim = lv_lottie_get_anim(new_lottie);
|
||
lv_anim_set_repeat_count(anim, LV_ANIM_REPEAT_INFINITE);
|
||
lv_screen_load(ui_Screen_Lottie);
|
||
|
||
while (1)
|
||
{
|
||
|
||
if (last_time != 0) {
|
||
int64_t delta = now - last_time; // 单位 us
|
||
float fps = 1000000.0f / delta /6;
|
||
ESP_LOGI(TAG_LVGL, "FPS %.2f delta=%lld us", fps, delta);
|
||
}
|
||
_lock_acquire(&lvgl_api_lock);
|
||
/* 执行来自其它任务的 UI 更新命令(必须在 LVGL 线程上下文执行) */
|
||
//ui_cmd_drain();
|
||
time_till_next_ms = lv_timer_handler();
|
||
_lock_release(&lvgl_api_lock);
|
||
// 如果触发任务看门狗超时
|
||
time_till_next_ms = MAX(time_till_next_ms, EXAMPLE_LVGL_TASK_MIN_DELAY_MS);
|
||
// 如果 lvgl 显示尚未准备好
|
||
time_till_next_ms = MIN(time_till_next_ms, EXAMPLE_LVGL_TASK_MAX_DELAY_MS);
|
||
usleep(1000 * time_till_next_ms);
|
||
}
|
||
}
|
||
//初始化 LVGL 创建显示 缓冲 触摸输入 tick 定时器 LVGL 任务
|
||
esp_err_t app_lvgl_init(void)
|
||
{
|
||
/* OTA/other shutdown may set this flag; always reset before re-init */
|
||
lvgl_deinitialized = false;
|
||
/* lv_deinit() 会清掉 LVGL timer,重建后允许重新创建自动休眠检查 timer */
|
||
g_auto_sleep_checker_inited = false;
|
||
ESP_LOGI(TAG_LVGL, "Initialize LVGL library");
|
||
ESP_LOGW(TAG_LVGL, "PATCH_MARKER: ui_stability_guards + extflash_switch_guard");
|
||
lv_init();
|
||
|
||
ui_cmd_init();
|
||
ESP_ERROR_CHECK(ui_dispatch_init());
|
||
|
||
// 使用内部 SRAM + DMA 标志,避免 SPI DMA 分配 bounce buffer 导致内部 SRAM 耗尽
|
||
// 条带高度必须与 config.h 中 EXAMPLE_LVGL_BUF_HEIGHT 一致(screen_init QSPI max_transfer_size 同源)
|
||
size_t draw_buffer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LVGL_BUF_HEIGHT * sizeof(lv_color_t);
|
||
void *buf1 = heap_caps_malloc(draw_buffer_sz, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||
if (!buf1) {
|
||
ESP_LOGE(TAG_LVGL, "buf1 DMA alloc failed, fallback to SPIRAM");
|
||
buf1 = heap_caps_malloc(draw_buffer_sz, MALLOC_CAP_SPIRAM);
|
||
}
|
||
assert(buf1);
|
||
lvgl_draw_buf1 = buf1;
|
||
void *buf2 = heap_caps_malloc(draw_buffer_sz, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||
if (!buf2) {
|
||
ESP_LOGE(TAG_LVGL, "buf2 DMA alloc failed, fallback to SPIRAM");
|
||
buf2 = heap_caps_malloc(draw_buffer_sz, MALLOC_CAP_SPIRAM);
|
||
}
|
||
assert(buf2);
|
||
lvgl_draw_buf2 = buf2; // 双缓冲模式使用 buf2
|
||
ESP_LOGI(TAG_LVGL, "Register display driver to LVGL (double buffer mode)");
|
||
|
||
lv_display_t *disp = lv_display_create(512, 410);
|
||
lv_display_set_buffers(disp, buf1, buf2, draw_buffer_sz, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||
lv_display_set_user_data(disp, panel_handle);
|
||
lv_display_set_color_format(disp, LV_COLOR_FORMAT);
|
||
lv_display_set_flush_cb(disp, example_lvgl_flush_cb);
|
||
lv_display_add_event_cb(disp, example_lvgl_rounder_cb, LV_EVENT_INVALIDATE_AREA, disp);
|
||
|
||
ESP_LOGI(TAG_LVGL, "Install LVGL tick timer");
|
||
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_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
|
||
ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));
|
||
lvgl_tick_timer_handle = lvgl_tick_timer;
|
||
|
||
ESP_LOGI(TAG_LVGL, "Register io panel event callback for LVGL flush ready notification");
|
||
|
||
const esp_lcd_panel_io_callbacks_t cbs = {
|
||
.on_color_trans_done = example_notify_lvgl_flush_ready,
|
||
};
|
||
|
||
/* Register done callback */
|
||
ESP_ERROR_CHECK(esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, disp));
|
||
uint32_t internal_sram_total = heap_caps_get_total_size(MALLOC_CAP_INTERNAL);
|
||
uint32_t internal_sram_free = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||
uint32_t internal_sram_used = internal_sram_total - internal_sram_free;
|
||
ESP_LOGI(TAG_LVGL, "Internal SRAM - Total: %" PRIu32 " bytes, Free: %" PRIu32 " bytes, Used: %" PRIu32 " bytes", internal_sram_total, internal_sram_free, internal_sram_used);
|
||
/*
|
||
#if EXAMPLE_USE_TOUCH
|
||
lv_indev_t *indev = lv_indev_create();
|
||
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
|
||
lv_indev_set_display(indev, disp);
|
||
lv_indev_set_read_cb(indev, example_lvgl_touch_cb);
|
||
lv_indev_set_user_data(indev, tp);
|
||
#endif
|
||
*/
|
||
ESP_LOGI(TAG_LVGL, "Create LVGL task");
|
||
|
||
lvgl_task_stack = heap_caps_malloc(LVGL_TASK_STACK_SIZE, MALLOC_CAP_SPIRAM);
|
||
ESP_LOGI(TAG_LVGL,"Stack buffer: %p, size bytes: %d\n", lvgl_task_stack, LVGL_TASK_STACK_SIZE);
|
||
lvgl_task_handle = xTaskCreateStaticPinnedToCore(example_lvgl_port_task, "LVGL", LVGL_TASK_STACK_SIZE, NULL, EXAMPLE_LVGL_TASK_PRIORITY, lvgl_task_stack, &lvgl_task_tcb, 1);
|
||
|
||
return ESP_OK;
|
||
}
|
||
|
||
//为WIFI /OTA 场景释放LVGL资源和显示资源,回收内存并停止相关任务
|
||
void lvgl_deinit_for_wifi(void)
|
||
{
|
||
if (lvgl_deinitialized)
|
||
return;
|
||
lvgl_deinitialized = true;
|
||
|
||
ESP_LOGW(TAG_LVGL, "=== WiFi连接前: 释放LVGL及显示资源以腾出内部SRAM ===");
|
||
|
||
uint32_t free_before = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||
ESP_LOGI(TAG_LVGL, "释放前内部SRAM剩余: %" PRIu32 " bytes", free_before);
|
||
|
||
_lock_acquire(&lvgl_api_lock);
|
||
|
||
if (change_task_handle)
|
||
{
|
||
vTaskDelete(change_task_handle);
|
||
change_task_handle = NULL;
|
||
}
|
||
|
||
if (lvgl_task_handle)
|
||
{
|
||
vTaskDelete(lvgl_task_handle);
|
||
lvgl_task_handle = NULL;
|
||
}
|
||
|
||
_lock_release(&lvgl_api_lock);
|
||
|
||
if (lvgl_tick_timer_handle)
|
||
{
|
||
esp_timer_stop(lvgl_tick_timer_handle);
|
||
esp_timer_delete(lvgl_tick_timer_handle);
|
||
lvgl_tick_timer_handle = NULL;
|
||
}
|
||
|
||
ui_font_runtime_deinit();
|
||
|
||
/* Fully teardown LVGL core/timers/disp objects.
|
||
* Otherwise re-init may redraw with stale display/buffers and corrupt heap. */
|
||
lv_deinit();
|
||
|
||
vTaskDelay(pdMS_TO_TICKS(100));
|
||
|
||
/* Reset LVGL-related globals so our guards can safely short-circuit. */
|
||
ui_Screen_Lottie = NULL;
|
||
lottie = NULL;
|
||
current_lottie = NULL;
|
||
clear_music_preload();
|
||
if (canvas_fb)
|
||
{
|
||
heap_caps_free(canvas_fb);
|
||
canvas_fb = NULL;
|
||
}
|
||
|
||
if (panel_handle)
|
||
{
|
||
esp_lcd_panel_disp_on_off(panel_handle, false);
|
||
vTaskDelay(pdMS_TO_TICKS(50));
|
||
}
|
||
|
||
if (panel_handle)
|
||
{
|
||
esp_lcd_panel_del(panel_handle);
|
||
panel_handle = NULL;
|
||
}
|
||
if (io_handle)
|
||
{
|
||
esp_lcd_panel_io_del(io_handle);
|
||
io_handle = NULL;
|
||
}
|
||
|
||
spi_bus_free(LCD_HOST);
|
||
|
||
if (lvgl_task_stack)
|
||
{
|
||
heap_caps_free(lvgl_task_stack);
|
||
lvgl_task_stack = NULL;
|
||
}
|
||
if (change_task_stack)
|
||
{
|
||
heap_caps_free(change_task_stack);
|
||
change_task_stack = NULL;
|
||
}
|
||
if (lvgl_draw_buf1)
|
||
{
|
||
heap_caps_free(lvgl_draw_buf1);
|
||
lvgl_draw_buf1 = NULL;
|
||
}
|
||
if (lvgl_draw_buf2)
|
||
{
|
||
heap_caps_free(lvgl_draw_buf2);
|
||
lvgl_draw_buf2 = NULL;
|
||
}
|
||
|
||
/* 清空路径缓存:deinit 后 panel/change_task 已为 NULL,若仍保留旧路径,
|
||
* request_play_lottie_path 会因 strcmp 与 g_current_lottie_path 一致而“跳过通知”,
|
||
* 主任务 finalize 却看到句柄为空,误以为需整段重建。 */
|
||
g_play_lottie_path[0] = '\0';
|
||
pending_sentinel_switch_path[0] = '\0';
|
||
lvgl_clear_current_lottie_path();
|
||
|
||
uint32_t free_after = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||
ESP_LOGW(TAG_LVGL, "=== LVGL资源释放完成 ===");
|
||
ESP_LOGI(TAG_LVGL, "释放后内部SRAM剩余: %" PRIu32 " bytes (回收 %" PRIu32 " bytes)",
|
||
free_after, free_after - free_before);
|
||
}
|
||
|
||
|
||
//动画播放完之后的统一回调:处理首显亮屏、音乐恢复 pending指令持续 回默认/结果页等等
|
||
void lottie_anim_completed_cb(lv_anim_t *anim)//当前正在运行的动画指针 动画跑完之后调用这个回调函数
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "[TS] lottie_anim_completed_cb enter t=%lums", (unsigned long)esp_log_timestamp());
|
||
if(anim == NULL || anim->var == NULL) {
|
||
ESP_LOGW(TAG_LVGL, "lottie_anim_completed_cb: anim or var is null");
|
||
return;
|
||
}
|
||
|
||
if(current_lottie == NULL || !lv_obj_is_valid(current_lottie)) {
|
||
ESP_LOGW(TAG_LVGL, "lottie_anim_completed_cb: current_lottie invalid, skip");
|
||
return;
|
||
}
|
||
|
||
bool heap_ok_before = heap_caps_check_integrity_all(true);
|
||
if(!heap_ok_before) {
|
||
ESP_LOGE(TAG_LVGL, "Heap integrity failed before lottie_anim_completed_cb");
|
||
}
|
||
|
||
ESP_LOGI(TAG_LVGL,
|
||
"lottie_anim_completed_cb called (hidden=%d visible=%d active_screen=%p lottie_screen=%p is_ui_mode=%d last_lottie_id=%d)",
|
||
(int)lv_obj_has_flag(current_lottie, LV_OBJ_FLAG_HIDDEN),
|
||
(int)lv_obj_is_visible(current_lottie),
|
||
(void *)lv_screen_active(),
|
||
(void *)ui_Screen_Lottie,
|
||
(int)is_ui_mode,
|
||
last_lottie_id);
|
||
|
||
/* Debug: 动画结束时也采样 canvas_fb,验证最终帧是否写入缓冲区 */
|
||
if (canvas_fb != NULL)
|
||
{
|
||
const uint32_t *u32 = (const uint32_t *)canvas_fb;
|
||
uint32_t s0 = u32[0];
|
||
uint32_t idx = (LOTTIE_ANIM_WIDTH * LOTTIE_ANIM_HEIGHT) / 4;
|
||
if (idx == 0) idx = 1;
|
||
uint32_t s1 = u32[idx];
|
||
ESP_LOGI(TAG_LVGL,
|
||
"[EMOJI_DEBUG] canvas_fb sample on completed: path=%s s0=0x%08X s1=0x%08X",
|
||
g_current_lottie_path, (unsigned)s0, (unsigned)s1);
|
||
}
|
||
|
||
if (first_display)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "开始渐变亮屏");
|
||
first_display = false;
|
||
|
||
// 1. 加载亮度配置
|
||
load_brightness_from_nvs();
|
||
|
||
// 2. 应用亮度 (在创建显示驱动后)
|
||
// if (panel_handle)
|
||
// {
|
||
// panel_qspi_amoled_set_brightness(panel_handle, g_current_brightness);
|
||
// }
|
||
// ESP_ERROR_CHECK(panel_qspi_amoled_set_brightness(panel_handle, 255));
|
||
|
||
lv_anim_t brightness_anim;
|
||
lv_anim_init(&brightness_anim);
|
||
lv_anim_set_var(&brightness_anim, panel_handle);
|
||
lv_anim_set_exec_cb(&brightness_anim, (lv_anim_exec_xcb_t)panel_qspi_amoled_set_brightness);
|
||
lv_anim_set_values(&brightness_anim, 0, g_current_brightness);
|
||
lv_anim_set_time(&brightness_anim, 1000); // 渐变时间1秒
|
||
lv_anim_set_path_cb(&brightness_anim, lv_anim_path_ease_out);
|
||
lv_anim_start(&brightness_anim);
|
||
ESP_LOGI(TAG_LVGL, "亮度渐变动画已启动:0 -> %d", g_current_brightness);
|
||
|
||
// back2default = true;
|
||
bool heap_ok_after_first = heap_caps_check_integrity_all(true);
|
||
if(!heap_ok_after_first) {
|
||
ESP_LOGE(TAG_LVGL, "Heap integrity failed after first-display branch");
|
||
}
|
||
return;
|
||
}
|
||
|
||
(void)anim; // 标记未使用参数,避免编译器警告
|
||
|
||
/* 通话中插播表情时挂起的挂断:插播播完后再回默认(须先于音乐/通话恢复分支) */
|
||
if (lvgl_lottie_completed_try_deferred_hangup())
|
||
{
|
||
return;
|
||
}
|
||
|
||
/* 持续播放音乐时被其他指令打断:该指令播完后切回音乐循环(在 LVGL 回调中不能持锁,通知 change_task 执行) */
|
||
if (resume_music_loop_after_oneshot)
|
||
{
|
||
resume_music_loop_after_oneshot = false;
|
||
/* 插播期间 BLE 可能已下发 0x01/0x02 等侧向;恢复 music_listen 前补物理回中,避免头停在侧向 */
|
||
(void)motor_post_play_sticker_direction(0x0Au);
|
||
if (change_task_handle)
|
||
xTaskNotify(change_task_handle, (uint32_t)NOTIFY_RESUME_MUSIC_LOOP, eSetValueWithOverwrite);
|
||
ESP_LOGI(TAG_LVGL, "音乐插播: 播完,通知恢复到此前播放态");
|
||
bool heap_ok_after_resume = heap_caps_check_integrity_all(true);
|
||
if(!heap_ok_after_resume) {
|
||
ESP_LOGE(TAG_LVGL, "Heap integrity failed after resume-music branch");
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (resume_calling_loop_after_oneshot)
|
||
{
|
||
resume_calling_loop_after_oneshot = false;
|
||
if (change_task_handle)
|
||
xTaskNotify(change_task_handle, (uint32_t)NOTIFY_RESUME_CALLING_LOOP, eSetValueWithOverwrite);
|
||
ESP_LOGI(TAG_LVGL, "通话插播: 播完,通知恢复到通话循环段");
|
||
bool heap_ok_after_call_resume = heap_caps_check_integrity_all(true);
|
||
if (!heap_ok_after_call_resume) {
|
||
ESP_LOGE(TAG_LVGL, "Heap integrity failed after resume-calling branch");
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (lvgl_lottie_completed_try_resume_ai_respond_loop())
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (lvgl_lottie_completed_try_start_ai_respond_loop())
|
||
{
|
||
return;
|
||
}
|
||
|
||
/* BLE play_sticker 单槽覆盖队列:当前动画播完后,优先切到最后一条待播指令 */
|
||
if (g_ble_play_sticker_pending_valid && change_task_handle)
|
||
{
|
||
uint16_t next_action_id = g_ble_play_sticker_pending_action_id;
|
||
uint8_t next_direction = g_ble_play_sticker_pending_direction;
|
||
g_ble_play_sticker_pending_valid = false;
|
||
g_ble_play_sticker_pending_action_id = 0;
|
||
g_ble_play_sticker_pending_direction = 0x00;
|
||
g_ble_play_sticker_active = true; /* 继续处于 BLE 播放态,直到最终回默认 */
|
||
|
||
ESP_LOGI("BLE_STICKER_GUARD",
|
||
"completed_cb: consume pending play_sticker=0x%04X dir=0x%02X",
|
||
next_action_id, next_direction);
|
||
/* pending 回灌若与当前 action_id 相同,需要放行一次,避免被去抖吞掉后卡在 active=true */
|
||
current_emoji_action_id = 0;
|
||
(void)change_task_post_action(next_action_id);
|
||
|
||
/* 单槽队列补发电机方向:00~07 都执行对应转向动作(左右切换时自动先回中) */
|
||
if (next_direction <= 0x07 && !lvgl_lottie_should_skip_play_sticker_motor(next_action_id, next_direction))
|
||
(void)motor_post_play_sticker_direction(next_direction);
|
||
return;
|
||
}
|
||
|
||
// 判断是否需要切换回默认动画
|
||
if (last_lottie_id == 0)
|
||
{
|
||
/* 特殊事件(星座运势、抽签)需要跳过 last_lottie_id==0 检查 */
|
||
if (g_current_emoji_event == emoji_event_horoscope ||
|
||
g_current_emoji_event == emoji_event_bless)
|
||
{
|
||
// ESP_LOGI(TAG_LVGL, "【抽签调试】特殊事件 0x%04X,跳过 last_lottie_id==0 检查,继续执行", (unsigned int)g_current_emoji_event);
|
||
// 不返回,继续执行后续逻辑
|
||
}
|
||
else
|
||
{
|
||
/* play_sticker 会故意 last_lottie_id=0 以保持表情且不立刻 back2default;
|
||
* 单次播完仍会进本分支,此处需清 g_ble_play_sticker_active,否则 IMU 幸运等一直被挡 */
|
||
if (g_ble_play_sticker_active)
|
||
{
|
||
ESP_LOGI("BLE_STICKER_GUARD",
|
||
"completed_cb: CLEAR g_ble_play_sticker_active (last_lottie_id==0, BLE play_sticker 单次播完)");
|
||
g_ble_play_sticker_active = false;
|
||
}
|
||
bool heap_ok_after_default = heap_caps_check_integrity_all(true);
|
||
if(!heap_ok_after_default) {
|
||
ESP_LOGE(TAG_LVGL, "Heap integrity failed on default-animation branch");
|
||
}
|
||
return; // 当前就是默认动画,不需要切换
|
||
}
|
||
}
|
||
|
||
// 根据事件类型调用对应的结果显示函数
|
||
// ESP_LOGI(TAG_LVGL, "【抽签调试】动画完成回调: g_current_emoji_event=0x%04X, last_lottie_id=%d",
|
||
// (unsigned int)g_current_emoji_event, last_lottie_id);
|
||
|
||
if (g_current_emoji_event == emoji_event_horoscope)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "星座运势动画播放完成,显示结果界面");
|
||
show_random_fortune_result();
|
||
g_current_emoji_event = 0; // 清除事件标志
|
||
bool heap_ok_after_horoscope = heap_caps_check_integrity_all(true);
|
||
if(!heap_ok_after_horoscope) {
|
||
ESP_LOGE(TAG_LVGL, "Heap integrity failed after horoscope result");
|
||
}
|
||
return; // 不回到默认表情
|
||
}
|
||
else if (g_current_emoji_event == emoji_event_bless)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "抽签动画播放完成,显示结果界面");
|
||
perform_draw();
|
||
g_current_emoji_event = 0; // 清除事件标志
|
||
bool heap_ok_after_sortition = heap_caps_check_integrity_all(true);
|
||
if(!heap_ok_after_sortition) {
|
||
ESP_LOGE(TAG_LVGL, "Heap integrity failed after sortition result");
|
||
}
|
||
return; // 不回到默认表情
|
||
}
|
||
|
||
back2default = true;
|
||
bool heap_ok_after = heap_caps_check_integrity_all(true);
|
||
if(!heap_ok_after) {
|
||
ESP_LOGE(TAG_LVGL, "Heap integrity failed after lottie_anim_completed_cb");
|
||
}
|
||
}
|
||
//创建独立lottie 屏 初始化页面与字体 ,加载默认表情 注册自动休眠检测
|
||
void lottie_init(void)
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "lottie_init");
|
||
|
||
// 1. 创建独立的屏幕对象
|
||
ui_Screen_Lottie = lv_obj_create(NULL);
|
||
lv_obj_remove_flag(ui_Screen_Lottie, LV_OBJ_FLAG_SCROLLABLE);
|
||
|
||
// 2. 设置黑色背景
|
||
lv_obj_set_style_bg_color(ui_Screen_Lottie, lv_color_black(), 0);
|
||
lv_obj_set_style_bg_opa(ui_Screen_Lottie, LV_OPA_COVER, 0);
|
||
|
||
/* Ensure runtime fonts are loaded before creating GUI screens. */
|
||
ui_font_runtime_init();
|
||
ui_pages_create(); // 创建其他页面
|
||
/* BLE 的 date/time 可能早于页面创建到达,这里在 UI 就绪后补刷一次缓存值 */
|
||
ble_datetime_flush_cached_to_ui();
|
||
|
||
/* BLE 的天气可能早于页面创建到达,这里在 UI 就绪后补刷一次缓存值 */
|
||
ble_weather_flush_cached_to_ui();
|
||
|
||
// 给当前屏幕注册手势... (这里要注意,可能需要给 ui_Screen_Lottie 也注册,或者全局注册)
|
||
// 建议给 ui_Screen_Lottie 也注册一下手势,否则在动画页没法下滑
|
||
lv_obj_add_event_cb(ui_Screen_Lottie, ui_event_gesture_cb, LV_EVENT_GESTURE, NULL);
|
||
|
||
// 3. 初始加载这个独立屏幕
|
||
lv_screen_load(ui_Screen_Lottie);
|
||
|
||
/* 若上次已切换到 A/B/C/D,开机直接使用该系列的 default.json */
|
||
char cur_pack = emoji_storage_get_using_pack();
|
||
/* 注意:调用方已持有锁,必须先释放再切,避免死锁;亮度渐变移到循环外执行 */
|
||
_lock_release(&lvgl_api_lock);
|
||
if (cur_pack == 'A' || cur_pack == 'B' || cur_pack == 'C' || cur_pack == 'D')
|
||
{
|
||
char pack_default[48];
|
||
snprintf(pack_default, sizeof(pack_default), "/extflash/%c/default.json", cur_pack);
|
||
struct stat st;
|
||
if (stat(pack_default, &st) == 0)
|
||
{
|
||
switch_lottie_animation_cross_path(pack_default);
|
||
}
|
||
else
|
||
{
|
||
switch_lottie_animation(0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
switch_lottie_animation(0);
|
||
}
|
||
/* first_display:默认表情首帧就绪后由 schedule_first_display_clear_after_default_ready() 清除 */
|
||
|
||
/* 注册自动休眠巡检(1s 一次),支撑“30s/5min/10min”超时休眠 */
|
||
if (!g_auto_sleep_checker_inited)
|
||
{
|
||
lv_timer_t *sleep_checker = lv_timer_create(auto_sleep_checker_cb, 1000, NULL);
|
||
if (sleep_checker != NULL)
|
||
{
|
||
g_auto_sleep_checker_inited = true;
|
||
ESP_LOGI(TAG_LVGL, "自动休眠检查 timer 已创建 (1s)");
|
||
}
|
||
else
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "自动休眠检查 timer 创建失败");
|
||
}
|
||
}
|
||
|
||
_lock_acquire(&lvgl_api_lock);
|
||
}
|
||
|
||
/** 默认表情无限循环无 completed_cb:在 LVGL 下一拍渲染后再清 first_display,表示首帧已就绪 */
|
||
static void first_display_clear_after_default_ready_cb(lv_timer_t *t)
|
||
{
|
||
(void)t;
|
||
if (first_display) {
|
||
first_display = false;
|
||
}
|
||
}
|
||
|
||
static void schedule_first_display_clear_after_default_ready(void)
|
||
{
|
||
if (!first_display) {
|
||
return;
|
||
}
|
||
lv_timer_t *tm = lv_timer_create(first_display_clear_after_default_ready_cb, 1, NULL);
|
||
if (tm == NULL) {
|
||
ESP_LOGW(TAG_LVGL, "first_display 清除定时器创建失败,立即清除");
|
||
first_display = false;
|
||
return;
|
||
}
|
||
lv_timer_set_repeat_count(tm, 1);
|
||
lv_timer_set_auto_delete(tm, true);
|
||
}
|
||
|
||
//切换动画
|
||
void switch_lottie_animation(int anim_index)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "Free heap before switch: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||
|
||
/* During OTA we may temporarily deinit LVGL; IMU/BMI must not touch LVGL then. */
|
||
if (lvgl_deinitialized || ui_Screen_Lottie == NULL)
|
||
return;
|
||
|
||
const char *file_path = lottie_files[anim_index];
|
||
struct stat file_stat;
|
||
if (stat(file_path, &file_stat) != 0)
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "Lottie file not found: %s", file_path);
|
||
return;
|
||
}
|
||
|
||
/* 先创建并配置新 lottie,再删除旧的,避免 IMU 触发切换时黑屏 */
|
||
lv_obj_t *old_lottie = current_lottie;
|
||
lv_obj_t *new_lottie = NULL;
|
||
|
||
if (canvas_fb == NULL)
|
||
{
|
||
canvas_fb = heap_caps_malloc(LOTTIE_ANIM_WIDTH * LOTTIE_ANIM_HEIGHT * 4, MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA);
|
||
if (canvas_fb == NULL)
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "Failed to allocate canvas_fb buffer");
|
||
return;
|
||
}
|
||
}
|
||
|
||
_lock_acquire(&lvgl_api_lock);
|
||
new_lottie = lv_lottie_create(ui_Screen_Lottie);
|
||
if (new_lottie == NULL)
|
||
{
|
||
_lock_release(&lvgl_api_lock);
|
||
ESP_LOGE(TAG_LVGL, "Failed to create Lottie object");
|
||
return;
|
||
}
|
||
|
||
lv_lottie_set_buffer(new_lottie, LOTTIE_ANIM_WIDTH, LOTTIE_ANIM_HEIGHT, canvas_fb);
|
||
lv_obj_align(new_lottie, LV_ALIGN_CENTER, 4, 0);
|
||
if (strncmp(file_path, "/extflash/", 10) == 0)
|
||
extflash_lock();
|
||
lv_lottie_set_src_file(new_lottie, file_path);
|
||
if (strncmp(file_path, "/extflash/", 10) == 0)
|
||
extflash_unlock();
|
||
lv_anim_t *anim = lv_lottie_get_anim(new_lottie);
|
||
if (anim)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] lottie anim loaded: path=%s raw_duration=%ld", file_path, (long)anim->duration);
|
||
anim->duration = anim->duration * 2;
|
||
if (first_display)
|
||
{
|
||
/* 开机时 anim_index==0 为默认表情,循环播放;亮屏逻辑在 lottie_init 中统一执行 */
|
||
if (anim_index == 0)
|
||
{
|
||
anim->repeat_cnt = LV_ANIM_REPEAT_INFINITE;
|
||
anim->completed_cb = NULL;
|
||
}
|
||
else
|
||
{
|
||
anim->repeat_cnt = 0;
|
||
anim->completed_cb = lottie_anim_completed_cb;
|
||
}
|
||
}
|
||
else if (anim_index == 0 || anim_index == music_listen_emojo || anim_index == music_listen_emojo)
|
||
{
|
||
anim->repeat_cnt = LV_ANIM_REPEAT_INFINITE;
|
||
anim->completed_cb = NULL;
|
||
}
|
||
else
|
||
{
|
||
anim->repeat_cnt = 0;
|
||
anim->completed_cb = lottie_anim_completed_cb;
|
||
}
|
||
}
|
||
|
||
/* 新 lottie 已就绪,删除旧的(无黑屏) */
|
||
if (old_lottie != NULL && lv_obj_is_valid(old_lottie))
|
||
{
|
||
if (old_lottie == g_music_preload_lottie)
|
||
{
|
||
if (g_music_preload_fb)
|
||
{
|
||
heap_caps_free(g_music_preload_fb);
|
||
g_music_preload_fb = NULL;
|
||
}
|
||
g_music_preload_lottie = NULL;
|
||
g_music_preload_path[0] = '\0';
|
||
g_music_preload_ready = false;
|
||
}
|
||
lv_anim_t *old_anim = lv_lottie_get_anim(old_lottie);
|
||
if (old_anim)
|
||
lv_anim_del(old_anim, NULL);
|
||
lv_obj_del(old_lottie);
|
||
}
|
||
current_lottie = new_lottie;
|
||
|
||
_lock_release(&lvgl_api_lock);
|
||
|
||
last_lottie_id = anim_index;
|
||
strncpy(g_current_lottie_path, file_path, sizeof(g_current_lottie_path) - 1);
|
||
g_current_lottie_path[sizeof(g_current_lottie_path) - 1] = '\0';
|
||
ESP_LOGI(TAG_LVGL, "Switched to animation: %s", file_path);
|
||
ESP_LOGI(TAG_LVGL, "Free heap after switch: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||
|
||
if (anim_index == 0) {
|
||
schedule_first_display_clear_after_default_ready();
|
||
}
|
||
}
|
||
//获取当前播放动画路径
|
||
const char *lvgl_get_current_lottie_path(void)
|
||
{
|
||
return g_current_lottie_path;
|
||
}
|
||
//清空当前播放路径缓存
|
||
void lvgl_clear_current_lottie_path(void)
|
||
{
|
||
g_current_lottie_path[0] = '\0';
|
||
}
|
||
//请求按路径播放动画
|
||
void request_play_lottie_path(const char *path)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] request_play_lottie_path 被调用, path=%s", path ? path : "NULL");
|
||
if (path == NULL)
|
||
{
|
||
ESP_LOGW(TAG_LVGL, "[EMOJI_DEBUG] request_play_lottie_path: path 为 NULL, 直接返回");
|
||
return;
|
||
}
|
||
strncpy(g_play_lottie_path, path, sizeof(g_play_lottie_path) - 1);
|
||
g_play_lottie_path[sizeof(g_play_lottie_path) - 1] = '\0';
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] g_play_lottie_path 已设置: %s", g_play_lottie_path);
|
||
|
||
if(g_current_lottie_path[0] != '\0' && strcmp(g_current_lottie_path, g_play_lottie_path) == 0) {
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] 目标路径与当前播放一致,跳过通知");
|
||
return;
|
||
}
|
||
|
||
if (change_task_handle)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] 发送 NOTIFY_PLAY_BY_PATH (0x%04X) 到 change_task", NOTIFY_PLAY_BY_PATH);
|
||
BaseType_t ret = xTaskNotify(change_task_handle, (uint32_t)NOTIFY_PLAY_BY_PATH, eSetValueWithOverwrite);
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] xTaskNotify 返回: %s", ret == pdPASS ? "pdPASS" : "pdFAIL");
|
||
}
|
||
else
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "[EMOJI_DEBUG] change_task_handle 为 NULL! 无法发送通知");
|
||
}
|
||
}
|
||
//按任意路径切动画的内部实现(包含 文件校验 fallback 并发保护)
|
||
static void switch_lottie_animation_cross_path_internal(const char *emoji_path)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] switch_lottie_animation_cross_path 被调用, emoji_path=%s", emoji_path ? emoji_path : "NULL");
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] Free heap before switch: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||
|
||
/* During OTA we may temporarily deinit LVGL; change_task/IMU must not touch LVGL then. */
|
||
if (lvgl_deinitialized || ui_Screen_Lottie == NULL)
|
||
return;
|
||
|
||
if(emoji_path == NULL || emoji_path[0] == '\0') {
|
||
ESP_LOGW(TAG_LVGL, "[EMOJI_DEBUG] 空路径,跳过切换");
|
||
return;
|
||
}
|
||
|
||
if(g_lottie_switch_in_progress) {
|
||
ESP_LOGW(TAG_LVGL, "[EMOJI_DEBUG] 切换进行中,忽略本次请求: %s", emoji_path);
|
||
return;
|
||
}
|
||
|
||
/* 解压进行中时延后动画切换,避免与 NAND 写竞争 */
|
||
if (extflash_is_extracting()) {
|
||
ESP_LOGW(TAG_LVGL, "[EMOJI_DEBUG] 解压进行中,跳过本次切换: %s", emoji_path);
|
||
return;
|
||
}
|
||
g_lottie_switch_in_progress = true;
|
||
|
||
const char *file_path = emoji_path;
|
||
struct stat file_stat;
|
||
bool fell_back_to_default = false;
|
||
const bool is_extflash = (strncmp(file_path, "/extflash/", 10) == 0);
|
||
|
||
if (is_extflash) extflash_lock();
|
||
if (stat(file_path, &file_stat) != 0)
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "[EMOJI_DEBUG] Lottie 文件不存在: %s (errno=%d)", file_path, errno);
|
||
file_path = default_emoji_path;
|
||
fell_back_to_default = true;
|
||
if (stat(file_path, &file_stat) != 0)
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "[EMOJI_DEBUG] 默认动画文件也不存在: %s", file_path);
|
||
if (is_extflash) extflash_unlock();
|
||
g_lottie_switch_in_progress = false;
|
||
return;
|
||
}
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] 文件缺失,回落到默认动画: %s", file_path);
|
||
}
|
||
else
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] 文件存在: %s, 大小=%ld bytes", file_path, (long)file_stat.st_size);
|
||
}
|
||
|
||
/* 不跳过相同路径:用户再次发送同一指令时需重播动画,播完后的最后一帧不算“正在播放” */
|
||
|
||
/* 先创建并配置新 lottie,再删除旧的,避免切换时黑屏 */
|
||
lv_obj_t *old_lottie = current_lottie;
|
||
lv_obj_t *new_lottie = NULL;
|
||
lv_anim_t *anim = NULL;
|
||
bool music_listen_promoted = false;
|
||
|
||
if (canvas_fb == NULL)
|
||
{
|
||
canvas_fb = heap_caps_malloc(LOTTIE_BUF_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA);
|
||
if (canvas_fb == NULL)
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "Failed to allocate canvas_fb buffer");
|
||
if (is_extflash) extflash_unlock();
|
||
g_lottie_switch_in_progress = false;
|
||
return;
|
||
}
|
||
ESP_LOGI(TAG_LVGL, "Allocated canvas_fb: %d bytes", LOTTIE_BUF_SIZE);
|
||
}
|
||
if (is_extflash) extflash_unlock();
|
||
|
||
_lock_acquire(&lvgl_api_lock);
|
||
|
||
const bool promote_listen = (!fell_back_to_default && g_music_preload_ready && g_music_preload_lottie != NULL &&
|
||
lv_obj_is_valid(g_music_preload_lottie) && strcmp(file_path, g_music_preload_path) == 0 &&
|
||
strstr(file_path, "music_listen") != NULL);
|
||
|
||
if (promote_listen) {
|
||
new_lottie = g_music_preload_lottie;
|
||
lv_obj_remove_flag(new_lottie, LV_OBJ_FLAG_HIDDEN);
|
||
lv_lottie_set_buffer(new_lottie, LOTTIE_ANIM_WIDTH, LOTTIE_ANIM_HEIGHT, canvas_fb);
|
||
uint8_t *obsolete_preload_fb = g_music_preload_fb;
|
||
g_music_preload_lottie = NULL;
|
||
g_music_preload_fb = NULL;
|
||
g_music_preload_ready = false;
|
||
g_music_preload_path[0] = '\0';
|
||
if (obsolete_preload_fb)
|
||
heap_caps_free(obsolete_preload_fb);
|
||
lv_obj_align(new_lottie, LV_ALIGN_CENTER, 4, 0);
|
||
music_listen_promoted = true;
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] music_listen promoted from preload (no re-parse): %s", file_path);
|
||
}
|
||
else {
|
||
new_lottie = lv_lottie_create(ui_Screen_Lottie);
|
||
if (new_lottie == NULL && file_path != default_emoji_path && stat(default_emoji_path, &file_stat) == 0)
|
||
{
|
||
file_path = default_emoji_path;
|
||
new_lottie = lv_lottie_create(ui_Screen_Lottie);
|
||
}
|
||
if (new_lottie == NULL)
|
||
{
|
||
_lock_release(&lvgl_api_lock);
|
||
ESP_LOGE(TAG_LVGL, "Failed to create Lottie object");
|
||
g_lottie_switch_in_progress = false;
|
||
return;
|
||
}
|
||
lv_lottie_set_buffer(new_lottie, LOTTIE_ANIM_WIDTH, LOTTIE_ANIM_HEIGHT, canvas_fb);
|
||
lv_obj_align(new_lottie, LV_ALIGN_CENTER, 4, 0);
|
||
|
||
if (is_extflash) {
|
||
extflash_lock();
|
||
}
|
||
lv_lottie_set_src_file(new_lottie, file_path);
|
||
if (is_extflash) extflash_unlock();
|
||
}
|
||
|
||
anim = lv_lottie_get_anim(new_lottie);
|
||
if (anim)
|
||
{
|
||
ESP_LOGI(TAG_LVGL,
|
||
"[EMOJI_DEBUG] lottie loaded: path=%s duration(ms)=%ld end_value(frames)=%ld act_time(ms)=%ld start_value=%ld hidden=%d visible=%d promoted=%d active_screen=%p lottie_screen=%p page_idx=%d is_ui_mode=%d",
|
||
file_path,
|
||
(long)anim->duration,
|
||
(long)anim->end_value,
|
||
(long)anim->act_time,
|
||
(long)anim->start_value,
|
||
(int)lv_obj_has_flag(new_lottie, LV_OBJ_FLAG_HIDDEN),
|
||
(int)lv_obj_is_visible(new_lottie),
|
||
(int)music_listen_promoted,
|
||
(void *)lv_screen_active(),
|
||
(void *)ui_Screen_Lottie,
|
||
current_page_idx,
|
||
(int)is_ui_mode);
|
||
if (anim->duration <= 0 || anim->end_value <= 0)
|
||
{
|
||
ESP_LOGE(TAG_LVGL, "[EMOJI_DEBUG] lottie parse seems invalid (duration=%ld, end_value=%ld): %s",
|
||
(long)anim->duration, (long)anim->end_value, file_path);
|
||
}
|
||
if (!music_listen_promoted)
|
||
anim->duration = anim->duration * 2;
|
||
if (first_display)
|
||
{
|
||
/* 开机时若是默认表情也循环播放,亮屏逻辑在 lottie_init 中统一执行 */
|
||
if (strstr(file_path, "/default.json") != NULL)
|
||
{
|
||
anim->repeat_cnt = LV_ANIM_REPEAT_INFINITE;
|
||
anim->completed_cb = NULL;
|
||
}
|
||
else
|
||
{
|
||
anim->repeat_cnt = 0;
|
||
anim->completed_cb = lottie_anim_completed_cb;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* 任意表情包的默认动画(路径含 /default.json)以及音乐/通话等循环播放;guard/protect(0x0015/16) 与其它表情一致只播一遍 */
|
||
if ((strstr(file_path, "/default.json") != NULL) ||
|
||
(strstr(file_path, "music_listen") != NULL) ||
|
||
(strstr(file_path, "music2") != NULL) ||
|
||
(strstr(file_path, "calling") != NULL))
|
||
{
|
||
anim->repeat_cnt = LV_ANIM_REPEAT_INFINITE;
|
||
anim->completed_cb = NULL;
|
||
}
|
||
else
|
||
{
|
||
anim->repeat_cnt = 0;
|
||
anim->completed_cb = lottie_anim_completed_cb;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 新 lottie 已就绪,删除旧的 */
|
||
if (old_lottie != NULL && lv_obj_is_valid(old_lottie))
|
||
{
|
||
if (old_lottie == g_music_preload_lottie)
|
||
{
|
||
if (g_music_preload_fb)
|
||
{
|
||
heap_caps_free(g_music_preload_fb);
|
||
g_music_preload_fb = NULL;
|
||
}
|
||
g_music_preload_lottie = NULL;
|
||
g_music_preload_path[0] = '\0';
|
||
g_music_preload_ready = false;
|
||
}
|
||
lv_anim_t *old_anim = lv_lottie_get_anim(old_lottie);
|
||
if (old_anim)
|
||
lv_anim_del(old_anim, NULL);
|
||
lv_obj_del(old_lottie);
|
||
}
|
||
current_lottie = new_lottie;
|
||
|
||
/* music_listen:解锁前钳到 40%~75% 并立刻渲染区间首帧,避免解锁后先刷第 0 帧(常被误认为 default 待机脸) */
|
||
if (anim != NULL && strstr(file_path, "music_listen") != NULL) {
|
||
int32_t total = anim->end_value;
|
||
int32_t start_frame = (int32_t)(0.4f * (float)total);
|
||
int32_t end_frame = (int32_t)(0.75f * (float)total);
|
||
if (start_frame < 0) start_frame = 0;
|
||
if (end_frame > total) end_frame = total;
|
||
if (start_frame < end_frame) {
|
||
anim->start_value = start_frame;
|
||
anim->end_value = end_frame;
|
||
anim->act_time = 0;
|
||
anim->duration = (end_frame - start_frame) * 1000 / LOTTIE_TARGET_FPS;
|
||
anim->repeat_cnt = LV_ANIM_REPEAT_INFINITE;
|
||
anim->completed_cb = NULL;
|
||
anim->current_value = start_frame;
|
||
if (anim->exec_cb) anim->exec_cb(anim->var, start_frame);
|
||
}
|
||
}
|
||
|
||
_lock_release(&lvgl_api_lock);
|
||
|
||
strncpy(g_current_lottie_path, file_path, sizeof(g_current_lottie_path) - 1);
|
||
g_current_lottie_path[sizeof(g_current_lottie_path) - 1] = '\0';
|
||
g_lottie_switch_in_progress = false;
|
||
|
||
if (fell_back_to_default)
|
||
{
|
||
/* 缺文件时直接显示默认待机,不应继续占用 BLE 播放态,否则后续指令会一直 pending。 */
|
||
g_ble_play_sticker_active = false;
|
||
g_ble_play_sticker_pending_valid = false;
|
||
g_ble_play_sticker_pending_action_id = 0;
|
||
g_ble_play_sticker_pending_direction = 0x00;
|
||
/* 否则 current_emoji_action_id 仍为本次指令,default 又常无限循环无 completed_cb,去抖会永久丢弃同 action_id */
|
||
current_emoji_action_id = 0;
|
||
}
|
||
|
||
/* 非循环动画(如 welcome-left)播完后需回默认,设置 last_lottie_id 供 completed_cb 触发 back2default */
|
||
if (strstr(file_path, "/default.json") == NULL &&
|
||
strstr(file_path, "music_listen") == NULL && strstr(file_path, "music2") == NULL &&
|
||
strstr(file_path, "calling") == NULL)
|
||
last_lottie_id = 1; /* 非 0 即可,completed_cb 会设 back2default */
|
||
else
|
||
last_lottie_id = 0;
|
||
|
||
if (last_lottie_id == 0 && file_path &&
|
||
(strstr(file_path, "/default.json") != NULL || g_ble_play_sticker_pending_valid))
|
||
ble_flush_pending_on_idle_infinite_lottie(file_path);
|
||
|
||
ESP_LOGI(TAG_LVGL, "Switched to animation: %s", file_path);
|
||
ESP_LOGI(TAG_LVGL, "Free heap after switch: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||
|
||
if (strstr(file_path, "/default.json") != NULL) {
|
||
schedule_first_display_clear_after_default_ready();
|
||
}
|
||
}
|
||
//对外入口:非change_task 上下文时先入队,再由change_task 执行切换
|
||
void switch_lottie_animation_cross_path(const char *emoji_path)
|
||
{
|
||
if (emoji_path == NULL || emoji_path[0] == '\0') {
|
||
return;
|
||
}
|
||
|
||
TaskHandle_t cur = xTaskGetCurrentTaskHandle();
|
||
if (change_task_handle != NULL && cur != change_task_handle && g_lottie_switch_queue != NULL) {
|
||
lottie_switch_req_t req = {0};
|
||
strncpy(req.path, emoji_path, sizeof(req.path) - 1);
|
||
req.path[sizeof(req.path) - 1] = '\0';
|
||
xQueueOverwrite(g_lottie_switch_queue, &req);
|
||
xTaskNotify(change_task_handle, (uint32_t)NOTIFY_SWITCH_BY_QUEUE, eSetValueWithOverwrite);
|
||
ESP_LOGI(TAG_LVGL, "[EMOJI_DEBUG] 外部上下文请求已入队: %s", req.path);
|
||
return;
|
||
}
|
||
|
||
switch_lottie_animation_cross_path_internal(emoji_path);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/* ==================== change_task 重构辅助函数 ==================== */
|
||
|
||
/** 清理所有播放状态(音乐、KTV、哨兵、BLE队列) */
|
||
|
||
|
||
|
||
/* ==================== 重构后的 change_task ==================== */
|
||
|
||
volatile uint16_t remapping_index = 0;
|
||
|
||
/** 「中」:音乐/通话/AI/哨兵等内部通知在切 Lottie 时与 BLE 队列一致,重置待机随机计时 */
|
||
static bool change_task_internal_notify_resets_random_idle(uint32_t bits)
|
||
{
|
||
switch (bits) {
|
||
case NOTIFY_PLAY_BY_PATH:
|
||
case NOTIFY_MUSIC_INTRO_DONE:
|
||
case NOTIFY_RESUME_MUSIC_LOOP:
|
||
case NOTIFY_SENTINEL_DO_SWITCH:
|
||
case NOTIFY_RESUME_CALLING_LOOP:
|
||
case NOTIFY_START_AI_RESPOND_LOOP:
|
||
case NOTIFY_RESUME_AI_RESPOND_LOOP:
|
||
return true;
|
||
default:
|
||
return false;
|
||
}
|
||
}
|
||
|
||
static void change_task(void *arg)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "Starting Change task");
|
||
|
||
static int last_active_page = 0;
|
||
static uint32_t random_check_counter = 0;
|
||
|
||
// 初始化
|
||
_lock_acquire(&lvgl_api_lock);
|
||
lottie_init();
|
||
_lock_release(&lvgl_api_lock);
|
||
|
||
/* 亮度渐变:lv_anim 必须在 LVGL 线程互斥域内注册,否则与 lv_timer_handler 竞态,易表现为“一跳到位” */
|
||
_lock_acquire(&lvgl_api_lock);
|
||
lv_anim_t brightness_anim;
|
||
lv_anim_init(&brightness_anim);
|
||
lv_anim_set_var(&brightness_anim, panel_handle);
|
||
lv_anim_set_exec_cb(&brightness_anim, (lv_anim_exec_xcb_t)panel_qspi_amoled_set_brightness);
|
||
lv_anim_set_values(&brightness_anim, 0, g_current_brightness);
|
||
lv_anim_set_time(&brightness_anim, 1000);
|
||
lv_anim_set_path_cb(&brightness_anim, lv_anim_path_ease_out);
|
||
lv_anim_start(&brightness_anim);
|
||
_lock_release(&lvgl_api_lock);
|
||
ESP_LOGI(TAG_LVGL, "渐变亮屏已启动:0 -> %d", g_current_brightness);
|
||
|
||
while (1)
|
||
{
|
||
uint32_t bits = 0;
|
||
BaseType_t notify_ret = pdFAIL;
|
||
bool from_change_action_queue = false;
|
||
// 优先从队列取(BLE play_sticker / pending 回灌 / idle 补消费)
|
||
uint16_t queued_action = 0;
|
||
if (g_change_action_queue && xQueueReceive(g_change_action_queue, &queued_action, 0) == pdTRUE)
|
||
{
|
||
bits = (uint32_t)queued_action;
|
||
notify_ret = pdPASS;
|
||
from_change_action_queue = true;
|
||
}
|
||
else
|
||
{
|
||
notify_ret = xTaskNotifyWait(0, ULONG_MAX, &bits, pdMS_TO_TICKS(100));
|
||
}
|
||
|
||
if (notify_ret != pdPASS)
|
||
{
|
||
// 检查回默认标记
|
||
if (back2default)
|
||
{
|
||
ESP_LOGI("recv_change_task", "[TS] change_task back2default branch t=%lums", (unsigned long)esp_log_timestamp());
|
||
back2default = false;
|
||
reset_all_playback_state();
|
||
switch_to_default_emoji();
|
||
_lock_acquire(&lvgl_api_lock);
|
||
last_lottie_id = 0;
|
||
(void)motor_post_cmd(0x0Au);
|
||
if (last_active_page != 0)
|
||
{
|
||
ui_change_page(last_active_page, LV_SCR_LOAD_ANIM_FADE_ON);
|
||
last_active_page = 0;
|
||
}
|
||
_lock_release(&lvgl_api_lock);
|
||
}
|
||
// 随机待机动画 2min一次
|
||
else if (last_lottie_id == 0 && !first_display && !is_ui_mode)
|
||
{
|
||
random_check_counter++;
|
||
if (random_check_counter >= 1091) //1091*100ms=109.1s=1.818min
|
||
{
|
||
random_check_counter = 0;
|
||
uint16_t n = esp_random() %19;
|
||
random_emoji(n);
|
||
}
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(10));
|
||
continue;
|
||
}
|
||
ESP_LOGI("recv_change_task", "收到通知: 0x%04X", (unsigned int)bits);
|
||
|
||
// 记录事件类型(用于回调)
|
||
if (bits < 0xFFF0) // 不是内部命令
|
||
{
|
||
g_current_emoji_event = bits;
|
||
remapping_index = bits;
|
||
}
|
||
|
||
/* ========== 第一层:内部命令 ========== */
|
||
if (handle_internal_commands(bits, &last_active_page)) {
|
||
if (change_task_internal_notify_resets_random_idle(bits)) {
|
||
random_check_counter = 0;
|
||
}
|
||
continue;
|
||
}
|
||
|
||
/* ========== 第二层:普通表情指令 ========== */
|
||
uint16_t action_id = (uint16_t)bits;
|
||
const bool is_ai_stop_cmd_in_loop =
|
||
(action_id == emoji_event_AI_respond) && lvgl_lottie_ai_respond_loop_active_for_ble();
|
||
|
||
/* BLE 队列投递:在去抖前重置待机随机计时(去抖未实际播放也重置) */
|
||
if (from_change_action_queue) {
|
||
random_check_counter = 0;
|
||
}
|
||
|
||
// 相同指令去抖
|
||
// if (action_id == current_emoji_action_id && ! g_allow_same_action_replay_once)
|
||
if ((action_id == current_emoji_action_id) && !is_ai_stop_cmd_in_loop)
|
||
{
|
||
ESP_LOGI(TAG_LVGL, "表情去抖: 已在播放 0x%04X,忽略", action_id);
|
||
continue;
|
||
}
|
||
current_emoji_action_id = action_id;
|
||
// g_allow_same_action_replay_once = false;
|
||
|
||
// 停止音乐
|
||
if (handle_stop_music(action_id, &last_active_page))
|
||
continue;
|
||
|
||
// 获取表情路径(支持 A/B/C/D 包)
|
||
char *path_result = remapping(action_id);
|
||
static char pack_path_buf[80];
|
||
const char *path_to_play = path_result;
|
||
|
||
char cur_pack = emoji_storage_get_using_pack();
|
||
if (cur_pack == 'A' || cur_pack == 'B' || cur_pack == 'C' || cur_pack == 'D')
|
||
{
|
||
const char *basename = strrchr(path_result, '/');
|
||
basename = basename ? (basename + 1) : path_result;
|
||
snprintf(pack_path_buf, sizeof(pack_path_buf), "/extflash/%c/%s", cur_pack, basename);
|
||
struct stat st;
|
||
if (stat(pack_path_buf, &st) == 0)
|
||
path_to_play = pack_path_buf;
|
||
}
|
||
|
||
ESP_LOGI("recv_change_task", "表情路径: %s", path_to_play);
|
||
|
||
if (!path_to_play || !path_to_play[0])
|
||
{
|
||
ESP_LOGE("recv_change_task", "无效路径,跳过");
|
||
current_emoji_action_id = 0;
|
||
continue;
|
||
}
|
||
|
||
// 特殊模式处理
|
||
if (handle_play_music(action_id, path_to_play, &last_active_page))
|
||
continue;
|
||
|
||
if (handle_sentinel_mode(action_id, path_to_play, &last_active_page))
|
||
continue;
|
||
|
||
|
||
handle_normal_sticker(action_id, path_to_play, &last_active_page);
|
||
|
||
vTaskDelay(pdMS_TO_TICKS(10));
|
||
}
|
||
}
|
||
|
||
|
||
esp_err_t app_change_init(void)
|
||
{
|
||
if (g_lottie_switch_queue == NULL) {
|
||
g_lottie_switch_queue = xQueueCreate(1, sizeof(lottie_switch_req_t));
|
||
}
|
||
if (g_change_action_queue == NULL) {
|
||
g_change_action_queue = xQueueCreate(CHANGE_ACTION_QUEUE_LEN, sizeof(uint16_t));
|
||
}
|
||
change_task_stack = heap_caps_malloc(CHANGE_TASK_STACK_SIZE, MALLOC_CAP_SPIRAM);
|
||
// 静态任务创建函数
|
||
change_task_handle = xTaskCreateStaticPinnedToCore(change_task, "CHANGE", CHANGE_TASK_STACK_SIZE, NULL, CHANGE_TASK_PRIORITY, change_task_stack, &change_task_tcb, 1); // 1
|
||
|
||
return ESP_OK;
|
||
}
|
||
|
||
void random_emoji(uint16_t n)
|
||
{
|
||
switch (n)
|
||
{
|
||
case 0:
|
||
switch_lottie_animation(liuliuliu_emojo);
|
||
break;
|
||
case 1:
|
||
switch_lottie_animation(calm_down_emojo);
|
||
break;
|
||
|
||
case 2:
|
||
switch_lottie_animation(love_emojo);
|
||
break;
|
||
case 3:
|
||
switch_lottie_animation(sing_emojo);
|
||
break;
|
||
|
||
case 4:
|
||
switch_lottie_animation(eating_emojo);
|
||
break;
|
||
case 5:
|
||
switch_lottie_animation(cheer_emojo);
|
||
break;
|
||
case 6:
|
||
switch_lottie_animation(money_emojo);
|
||
break;
|
||
case 7:
|
||
switch_lottie_animation(like_emojo);
|
||
break;
|
||
case 8:
|
||
switch_lottie_animation(shy_emojo);
|
||
break;
|
||
case 9:
|
||
switch_lottie_animation(curious_emojo);
|
||
break;
|
||
case 10:
|
||
switch_lottie_animation(holiday_emojo);
|
||
break;
|
||
case 11:
|
||
switch_lottie_animation(happy_emojo);
|
||
break;
|
||
case 12:
|
||
switch_lottie_animation(cry_emojo);
|
||
break;
|
||
case 13:
|
||
switch_lottie_animation(becool_emojo);
|
||
break;
|
||
case 14:
|
||
switch_lottie_animation(boring_emojo);
|
||
break;
|
||
case 15:
|
||
switch_lottie_animation(thinking_emojo);
|
||
break;
|
||
// case 16:
|
||
// switch_lottie_animation(sing_emojo);
|
||
// break;
|
||
// case 17:
|
||
// switch_lottie_animation(break_emojo);
|
||
// break;
|
||
// case 18:
|
||
// switch_lottie_animation(money_emojo);
|
||
// break;
|
||
default:
|
||
switch_lottie_animation(default_emojo);
|
||
break;
|
||
}
|
||
}
|