第二部分:ESP32开发入门

1. Application::Start() 执行流程

继续上一章的内容,让我们跟踪Application::Start() 的执行流程。从提供的代码中可以看到,在 application.cc 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
void Application::Start() {
auto& board = Board::GetInstance();
SetDeviceState(kDeviceStateStarting);

/* Setup the display */
auto display = board.GetDisplay();
// ...

/* Wait for the network to be ready */
board.StartNetwork();

// Check for new firmware version or get the MQTT broker address
CheckNewVersion();

// Initialize the protocol
display->SetStatus(Lang::Strings::LOADING_PROTOCOL);

if (ota_.HasMqttConfig()) {
protocol_ = std::make_unique<MqttProtocol>();
} else if (ota_.HasWebsocketConfig()) {
protocol_ = std::make_unique<WebsocketProtocol>();
} else {
ESP_LOGW(TAG, "No protocol specified in the OTA config, using MQTT");
protocol_ = std::make_unique<MqttProtocol>();
}

// ... 协议初始化和回调设置 ...

// Wait for the new version check to finish
xEventGroupWaitBits(event_group_, CHECK_NEW_VERSION_DONE_EVENT, pdTRUE, pdFALSE, portMAX_DELAY);
SetDeviceState(kDeviceStateIdle);

if (protocol_started) {
std::string message = std::string(Lang::Strings::VERSION) + ota_.GetCurrentVersion();
display->ShowNotification(message.c_str());
display->SetChatMessage("system", "");
// Play the success sound to indicate the device is ready
ResetDecoder();
PlaySound(Lang::Sounds::P3_SUCCESS);
}

// Enter the main event loop
MainEventLoop();
}

2. MainEventLoop() 主事件循环

执行Start() 后,程序会进入 MainEventLoop():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Application::MainEventLoop() {
while (true) {
auto bits = xEventGroupWaitBits(event_group_, SCHEDULE_EVENT, pdTRUE, pdFALSE, portMAX_DELAY);

if (bits & SCHEDULE_EVENT) {
std::unique_lock<std::mutex> lock(mutex_);
std::list<std::function<void()>> tasks = std::move(main_tasks_);
lock.unlock();
for (auto& task : tasks) {
task();
}
}
}
}

主要执行流程是:

  1. 初始化设备状态为 kDeviceStateStarting
  2. 设置显示屏
  3. 启动网络
  4. 检查新版本
  5. 初始化通信协议(MQTT或WebSocket)
  6. 等待版本检查完成
  7. 设置设备状态为 kDeviceStateIdle
  8. 播放成功提示音
  9. 进入主事件循环 MainEventLoop()

在主事件循环中,程序会:

  • 等待 SCHEDULE_EVENT 事件
  • 当有新任务时,从 main_tasks_ 队列中取出任务执行
    这是一个无限循环,程序会一直在这里运行

所有的用户交互、网络通信等任务都会通过 Schedule() 函数加入到 main_tasks_ 队列中,然后在主事件循环中执行。

代码解析

这里的相关代码比较多,让我们逐一分析

初始化部分

  1. 基础初始化
1
2
auto& board = Board::GetInstance();
SetDeviceState(kDeviceStateStarting);

协议回调设置

音频处理配置(条件编译)

唤醒词检测配置(条件编译)

启动完成处理

主事件循环


本文章发布于 hjq.college,转载请注明出处。