ba5e47bc77
1. 应用界面增加了返回主页的按钮 2. 修复了gif渲染内存泄漏的严重bug 3. 将PetDao当中的cJSON API替换为cpp_json,完美通过测试 4. 整合已经实现的各种上层建筑,实现了一个宠物对话基本业务应用,用于样品测试展示用 5. 重构了音频播放类,使其更modern,更加便于移植和拓展
394 lines
11 KiB
Markdown
394 lines
11 KiB
Markdown
### 如你所见,这只是一个临时文件
|
|
|
|
|
|
|
|
```c++
|
|
// 描述了每个驱动的启动顺序
|
|
#include "ST77916.h"
|
|
#include "PCF85063.h"
|
|
#include "QMI8658.h"
|
|
#include "SD_MMC.h"
|
|
#include "Wireless.h"
|
|
#include "TCA9554PWR.h"
|
|
#include "LVGL_Example.h"
|
|
#include "BAT_Driver.h"
|
|
#include "PWR_Key.h"
|
|
#include "PCM5101.h"
|
|
#include "MIC_Speech.h"
|
|
|
|
void Driver_Loop(void *parameter)
|
|
{
|
|
Wireless_Init();
|
|
while(1)
|
|
{
|
|
QMI8658_Loop();
|
|
PCF85063_Loop();
|
|
BAT_Get_Volts();
|
|
PWR_Loop();
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
}
|
|
vTaskDelete(NULL);
|
|
}
|
|
void Driver_Init(void)
|
|
{
|
|
PWR_Init();
|
|
BAT_Init();
|
|
I2C_Init();
|
|
EXIO_Init(); // Example Initialize EXIO
|
|
Flash_Searching();
|
|
PCF85063_Init();
|
|
QMI8658_Init();
|
|
xTaskCreatePinnedToCore(
|
|
Driver_Loop,
|
|
"Other Driver task",
|
|
4096,
|
|
NULL,
|
|
3,
|
|
NULL,
|
|
0);
|
|
}
|
|
void app_main(void)
|
|
{
|
|
Driver_Init();
|
|
|
|
SD_Init();
|
|
LCD_Init();
|
|
Audio_Init();
|
|
MIC_Speech_init();
|
|
// Play_Music("/sdcard","AAA.mp3");
|
|
LVGL_Init(); // returns the screen object
|
|
|
|
// /********************* Demo *********************/
|
|
// Lvgl_Example1();
|
|
// lv_demo_widgets();
|
|
lv_demo_keypad_encoder();
|
|
// lv_demo_benchmark();
|
|
// lv_demo_stress();
|
|
// lv_demo_music();
|
|
|
|
while (1) {
|
|
// raise the task priority of LVGL and/or reduce the handler period can improve the performance
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
// The task running lv_timer_handler should have lower priority than that running `lv_tick_inc`
|
|
lv_timer_handler();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
```c++
|
|
// esp idf提供的pthread库的使用,主要服务于C++
|
|
|
|
/* pthread/std::thread example
|
|
|
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
|
|
|
Unless required by applicable law or agreed to in writing, this
|
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
CONDITIONS OF ANY KIND, either express or implied.
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <thread>
|
|
#include <chrono>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <esp_pthread.h>
|
|
#include <freertos/FreeRTOS.h>
|
|
#include <freertos/task.h>
|
|
#include <esp_log.h>
|
|
|
|
using namespace std::chrono;
|
|
|
|
const auto sleep_time = seconds {
|
|
5
|
|
};
|
|
|
|
void print_thread_info(const char *extra = nullptr)
|
|
{
|
|
std::stringstream ss;
|
|
if (extra) {
|
|
ss << extra;
|
|
}
|
|
ss << "Core id: " << xPortGetCoreID()
|
|
<< ", prio: " << uxTaskPriorityGet(nullptr)
|
|
<< ", minimum free stack: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
|
|
ESP_LOGI(pcTaskGetName(nullptr), "%s", ss.str().c_str());
|
|
}
|
|
|
|
void thread_func_inherited()
|
|
{
|
|
while (true) {
|
|
print_thread_info("This is the INHERITING thread with the same parameters as our parent, including name. ");
|
|
std::this_thread::sleep_for(sleep_time);
|
|
}
|
|
}
|
|
|
|
void spawn_another_thread()
|
|
{
|
|
// Create a new thread, it will inherit our configuration
|
|
std::thread inherits(thread_func_inherited);
|
|
|
|
while (true) {
|
|
print_thread_info();
|
|
std::this_thread::sleep_for(sleep_time);
|
|
}
|
|
}
|
|
|
|
void thread_func_any_core()
|
|
{
|
|
while (true) {
|
|
print_thread_info("This thread (with the default name) may run on any core.");
|
|
std::this_thread::sleep_for(sleep_time);
|
|
}
|
|
}
|
|
|
|
void thread_func()
|
|
{
|
|
while (true) {
|
|
print_thread_info();
|
|
std::this_thread::sleep_for(sleep_time);
|
|
}
|
|
}
|
|
|
|
esp_pthread_cfg_t create_config(const char *name, int core_id, int stack, int prio)
|
|
{
|
|
auto cfg = esp_pthread_get_default_config();
|
|
cfg.thread_name = name;
|
|
cfg.pin_to_core = core_id;
|
|
cfg.stack_size = stack;
|
|
cfg.prio = prio;
|
|
return cfg;
|
|
}
|
|
|
|
extern "C" void app_main(void)
|
|
{
|
|
// Create a thread using default values that can run on any core
|
|
auto cfg = esp_pthread_get_default_config();
|
|
esp_pthread_set_cfg(&cfg);
|
|
std::thread any_core(thread_func_any_core);
|
|
|
|
// Create a thread on core 0 that spawns another thread, they will both have the same name etc.
|
|
cfg = create_config("Thread 1", 0, 3 * 1024, 5);
|
|
cfg.inherit_cfg = true;
|
|
esp_pthread_set_cfg(&cfg);
|
|
std::thread thread_1(spawn_another_thread);
|
|
|
|
// Create a thread on core 1.
|
|
cfg = create_config("Thread 2", 1, 3 * 1024, 5);
|
|
esp_pthread_set_cfg(&cfg);
|
|
std::thread thread_2(thread_func);
|
|
|
|
// Let the main task do something too
|
|
while (true) {
|
|
std::stringstream ss;
|
|
ss << "core id: " << xPortGetCoreID()
|
|
<< ", prio: " << uxTaskPriorityGet(nullptr)
|
|
<< ", minimum free stack: " << uxTaskGetStackHighWaterMark(nullptr) << " bytes.";
|
|
ESP_LOGI(pcTaskGetName(nullptr), "%s", ss.str().c_str());
|
|
std::this_thread::sleep_for(sleep_time);
|
|
}
|
|
}
|
|
```
|
|
|
|
|
|
|
|
```c++
|
|
#include "WebSocketManager.h"
|
|
#include "cJSON.h"
|
|
|
|
// JSON数据回调示例
|
|
void onJsonData(cJSON* json) {
|
|
// 处理接收到的JSON数据
|
|
cJSON* type = cJSON_GetObjectItem(json, "type");
|
|
if (type && cJSON_IsString(type)) {
|
|
ESP_LOGI("App", "Received message type: %s", type->valuestring);
|
|
|
|
if (strcmp(type->valuestring, "sensor_data") == 0) {
|
|
cJSON* value = cJSON_GetObjectItem(json, "value");
|
|
if (value && cJSON_IsNumber(value)) {
|
|
ESP_LOGI("App", "Sensor value: %.2f", value->valuedouble);
|
|
}
|
|
}
|
|
}
|
|
|
|
cJSON_Delete(json);
|
|
}
|
|
|
|
// 事件回调示例
|
|
void onWebSocketEvent(WebSocketEvent event, const std::string& message) {
|
|
switch (event) {
|
|
case WebSocketEvent::CONNECTED:
|
|
ESP_LOGI("App", "WebSocket connected: %s", message.c_str());
|
|
break;
|
|
case WebSocketEvent::DISCONNECTED:
|
|
ESP_LOGI("App", "WebSocket disconnected: %s", message.c_str());
|
|
break;
|
|
case WebSocketEvent::DATA_RECEIVED:
|
|
ESP_LOGI("App", "Received raw data: %s", message.c_str());
|
|
break;
|
|
case WebSocketEvent::ERROR:
|
|
ESP_LOGE("App", "WebSocket error: %s", message.c_str());
|
|
break;
|
|
}
|
|
}
|
|
|
|
extern "C" void app_main() {
|
|
// 初始化WiFi
|
|
WifiConnectors* wifi = WifiConnectors::getInstance();
|
|
|
|
// 连接WiFi(在实际应用中应该在单独线程中进行)
|
|
ThreadConfig wifi_config;
|
|
wifi_config.name = "WiFi_Connector";
|
|
|
|
auto wifi_thread = ThreadManager::createSingletonThread<WifiConnectors>(
|
|
wifi_config, &WifiConnectors::connectWifi, "Your_SSID", "Your_Password");
|
|
|
|
wifi_thread.join();
|
|
|
|
// 获取WebSocket管理器实例
|
|
WebSocketManager* ws = WebSocketManager::getInstance();
|
|
|
|
// 配置WebSocket
|
|
WebSocketConfig config;
|
|
config.uri = "ws://your-websocket-server.com/ws";
|
|
config.auto_reconnect = true;
|
|
config.reconnect_interval = 5000;
|
|
config.heartbeat_interval = 30000;
|
|
config.max_reconnect_attempts = 10;
|
|
|
|
// 初始化WebSocket管理器
|
|
if (!ws->initialize(config)) {
|
|
ESP_LOGE("App", "Failed to initialize WebSocket manager");
|
|
return;
|
|
}
|
|
|
|
// 设置回调
|
|
ws->setJsonCallback(onJsonData);
|
|
ws->setEventCallback(onWebSocketEvent);
|
|
|
|
// 连接WebSocket
|
|
if (!ws->connect()) {
|
|
ESP_LOGE("App", "Failed to connect WebSocket");
|
|
return;
|
|
}
|
|
|
|
// 等待连接建立
|
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
|
|
|
// 发送JSON数据
|
|
cJSON* json = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(json, "type", "greeting");
|
|
cJSON_AddStringToObject(json, "message", "Hello from ESP32!");
|
|
cJSON_AddNumberToObject(json, "timestamp", esp_log_timestamp());
|
|
|
|
ws->sendJson(json);
|
|
|
|
// 保持运行
|
|
while (true) {
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
// 可以在这里发送其他数据或处理业务逻辑
|
|
if (ws->isConnected()) {
|
|
cJSON* status = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(status, "type", "status");
|
|
cJSON_AddNumberToObject(status, "free_heap", esp_get_free_heap_size());
|
|
|
|
ws->sendJson(status);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
|
|
```c++
|
|
// 有关lvgl_cpp的部分控件使用
|
|
/* LVGL 已经初始化,屏幕驱动已注册 */
|
|
auto scr = lvgl_cpp::Screen{}; // RAII,离开作用域自动 del
|
|
lv_scr_load(scr.raw()); // 让 LVGL 把它当活动屏幕
|
|
|
|
lvgl_cpp::Image img(scr);
|
|
img.bin("pic_no_alp_swap.bin", 720, 720)
|
|
.center();
|
|
|
|
/* 1. 创建按钮 */
|
|
/* 1. 黑色文字样式 */
|
|
static lvgl_cpp::Style txt_style;
|
|
txt_style.text_color(lv_color_black());
|
|
|
|
/* 2. 按钮 */
|
|
lvgl_cpp::Button btn{scr};
|
|
btn.size(150, 60).pos(40, 40);
|
|
/* 3. 先创建 Label 对象并保存,再链式调 */
|
|
lvgl_cpp::Label lbl{btn}; // 一定要存实例
|
|
lbl.text("Click Me")
|
|
.add_style(&txt_style.s, LV_PART_MAIN); // 样式作用到文字本身
|
|
/* 3. 注册点击事件 */
|
|
btn.on(LV_EVENT_CLICKED, [](lv_event_t*){
|
|
lvgl_cpp::Toast::show("Saved successfully !");
|
|
/* 2. 警告,3 s,顶部 */
|
|
lvgl_cpp::Toast::show("SD card missing", lvgl_cpp::Toast::Type::WARN, 3000, LV_ALIGN_TOP_MID, 20);
|
|
|
|
/* 3. 错误,1.5 s,底部右侧 */
|
|
lvgl_cpp::Toast::show("Network error", lvgl_cpp::Toast::Type::ERROR, 1500, LV_ALIGN_BOTTOM_RIGHT, -30);
|
|
ESP_LOGI("BTN", "pressed");
|
|
});
|
|
|
|
/* 1. 消息框 */
|
|
const char* btns[] = {"Yes", "No", ""};
|
|
auto mbox = lvgl_cpp::MsgBox::create("Hint", "Delete file ?", btns);
|
|
|
|
/* 3. 进度条(双向 + 动画) */
|
|
lvgl_cpp::Bar bar(scr);
|
|
bar.range(0, 100)
|
|
.start_value(20) // 左端
|
|
.value(80, LV_ANIM_ON) // 右端带动画
|
|
.anim_time(500)
|
|
.size(200, 15)
|
|
.align(LV_ALIGN_CENTER, nullptr, 0, 40);
|
|
|
|
/* 4. 折线:画一个 △ */
|
|
std::vector<lv_point_t> triangle = {{0,0}, {40,0}, {20,40}, {0,0}};
|
|
lvgl_cpp::Line line(scr);
|
|
line.points(triangle)
|
|
.y_invert(false)
|
|
.align(LV_ALIGN_CENTER, nullptr, 0, 100);
|
|
|
|
lvgl_cpp::Battery bat(scr);
|
|
bat.size(60, 30) // 手机经典尺寸
|
|
.percent(true) // 显示 50%
|
|
.onRead([]() -> uint8_t { // 替换成你的 ADC/INA219 回调
|
|
static uint8_t v = 100;
|
|
if (v) --v;
|
|
return v;
|
|
})
|
|
.align(LV_ALIGN_TOP_RIGHT, -10, 10); // 九宫格对齐
|
|
|
|
/* 3. 日期时间 */
|
|
lvgl_cpp::DateTime dt(scr);
|
|
dt.format("%m/%d %a %H:%M")
|
|
.onRead([](char* buf, size_t len){
|
|
/* 这里用 SNTP / RTC 填充,示例直接给假时间 */
|
|
snprintf(buf, len, "06/25 Tue 14:30");
|
|
})
|
|
.align(LV_ALIGN_BOTTOM_MID, nullptr, 0, -10);
|
|
|
|
|
|
lvgl_cpp::ColorPicker cp(scr);
|
|
cp.size(120, 120)
|
|
.align(LV_ALIGN_BOTTOM_MID, nullptr, 0, -20)
|
|
.on(LV_EVENT_VALUE_CHANGED, [&](lv_event_t*){
|
|
lv_color_t c = cp.color();
|
|
ESP_LOGI("CP", "rgb=%d,%d,%d", c.ch.red, c.ch.green_h, c.ch.blue);
|
|
});
|
|
|
|
|
|
``` |