commit
6dcc64459f
@ -4,7 +4,7 @@
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(PROJECT_VER "0.8.3")
|
||||
set(PROJECT_VER "0.9.0")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(xiaozhi)
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
- Wi-Fi 配网
|
||||
- 支持 BOOT 键唤醒和打断
|
||||
- 离线语音唤醒(乐鑫方案)
|
||||
- 流式语音对话(WebSocket 协议)
|
||||
- 流式语音对话(WebSocket 或 UDP 协议)
|
||||
- 支持国语、粤语、英语、日语、韩语 5 种语言识别(SenseVoice 方案)
|
||||
- 声纹识别(识别是谁在喊 AI 的名字,[3D Speaker 项目](https://github.com/modelscope/3D-Speaker))
|
||||
- 使用大模型 TTS(火山引擎与 CosyVoice 方案)
|
||||
|
||||
@ -1,23 +1,26 @@
|
||||
set(SOURCES "audio_codec.cc"
|
||||
set(SOURCES "audio_codecs/audio_codec.cc"
|
||||
"audio_codecs/no_audio_codec.cc"
|
||||
"audio_codecs/box_audio_codec.cc"
|
||||
"display.cc"
|
||||
"display/display.cc"
|
||||
"display/no_display.cc"
|
||||
"display/st7789_display.cc"
|
||||
"display/ssd1306_display.cc"
|
||||
"board.cc"
|
||||
"protocol.cc"
|
||||
"protocols/protocol.cc"
|
||||
"protocols/mqtt_protocol.cc"
|
||||
"protocols/websocket_protocol.cc"
|
||||
"system_info.cc"
|
||||
"application.cc"
|
||||
"button.cc"
|
||||
"led.cc"
|
||||
"ota.cc"
|
||||
"settings.cc"
|
||||
"main.cc"
|
||||
)
|
||||
set(INCLUDE_DIRS ".")
|
||||
|
||||
set(INCLUDE_DIRS "." "display" "audio_codecs" "protocols")
|
||||
|
||||
# 字体
|
||||
file(GLOB FONT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/fonts/*.c)
|
||||
list(APPEND SOURCES ${FONT_SOURCES})
|
||||
list(APPEND INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/fonts)
|
||||
|
||||
# 添加板级公共文件
|
||||
file(GLOB BOARD_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/boards/common/*.cc)
|
||||
|
||||
@ -2,8 +2,9 @@
|
||||
#include "system_info.h"
|
||||
#include "ml307_ssl_transport.h"
|
||||
#include "audio_codec.h"
|
||||
#include "protocols/mqtt_protocol.h"
|
||||
#include "protocols/websocket_protocol.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "websocket_protocol.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <esp_log.h>
|
||||
@ -43,23 +44,29 @@ Application::~Application() {
|
||||
}
|
||||
|
||||
void Application::CheckNewVersion() {
|
||||
auto& board = Board::GetInstance();
|
||||
auto display = board.GetDisplay();
|
||||
// Check if there is a new firmware version available
|
||||
ota_.SetPostData(Board::GetInstance().GetJson());
|
||||
ota_.SetPostData(board.GetJson());
|
||||
|
||||
while (true) {
|
||||
if (ota_.CheckVersion()) {
|
||||
if (ota_.HasNewVersion()) {
|
||||
// Wait for the chat state to be idle
|
||||
while (chat_state_ != kChatStateIdle) {
|
||||
vTaskDelay(100);
|
||||
}
|
||||
do {
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
} while (GetChatState() != kChatStateIdle);
|
||||
|
||||
SetChatState(kChatStateUpgrading);
|
||||
ota_.StartUpgrade([](int progress, size_t speed) {
|
||||
|
||||
display->SetIcon(FONT_AWESOME_DOWNLOAD);
|
||||
display->SetStatus("新版本 " + ota_.GetFirmwareVersion());
|
||||
board.GetAudioCodec()->EnableOutput(false);
|
||||
|
||||
ota_.StartUpgrade([display](int progress, size_t speed) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "Upgrading...\n %d%% %zuKB/s", progress, speed / 1024);
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetText(buffer);
|
||||
snprintf(buffer, sizeof(buffer), "%d%% %zuKB/s", progress, speed / 1024);
|
||||
display->SetStatus(buffer);
|
||||
});
|
||||
|
||||
// If upgrade success, the device will reboot and never reach here
|
||||
@ -67,6 +74,7 @@ void Application::CheckNewVersion() {
|
||||
SetChatState(kChatStateIdle);
|
||||
} else {
|
||||
ota_.MarkCurrentVersionValid();
|
||||
display->ShowNotification("版本 " + ota_.GetCurrentVersion());
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -79,7 +87,7 @@ void Application::CheckNewVersion() {
|
||||
void Application::Alert(const std::string&& title, const std::string&& message) {
|
||||
ESP_LOGW(TAG, "Alert: %s, %s", title.c_str(), message.c_str());
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->ShowNotification(std::string(title + "\n" + message));
|
||||
display->ShowNotification(message);
|
||||
|
||||
if (message == "PIN is not ready") {
|
||||
PlayLocalFile(p3_err_pin_start, p3_err_pin_end - p3_err_pin_start);
|
||||
@ -137,7 +145,6 @@ void Application::Start() {
|
||||
|
||||
/* Setup the display */
|
||||
auto display = board.GetDisplay();
|
||||
display->SetupUI();
|
||||
|
||||
/* Setup the audio codec */
|
||||
auto codec = board.GetAudioCodec();
|
||||
@ -230,9 +237,9 @@ void Application::Start() {
|
||||
auto builtin_led = Board::GetInstance().GetBuiltinLed();
|
||||
if (chat_state_ == kChatStateListening) {
|
||||
if (speaking) {
|
||||
builtin_led->SetRed(32);
|
||||
builtin_led->SetRed(HIGH_BRIGHTNESS);
|
||||
} else {
|
||||
builtin_led->SetRed(8);
|
||||
builtin_led->SetRed(LOW_BRIGHTNESS);
|
||||
}
|
||||
builtin_led->TurnOn();
|
||||
}
|
||||
@ -269,7 +276,7 @@ void Application::Start() {
|
||||
#endif
|
||||
|
||||
// Initialize the protocol
|
||||
display->SetText("Starting protocol...");
|
||||
display->SetStatus("初始化协议");
|
||||
#ifdef CONFIG_CONNECTION_TYPE_WEBSOCKET
|
||||
protocol_ = new WebsocketProtocol();
|
||||
#else
|
||||
@ -294,7 +301,7 @@ void Application::Start() {
|
||||
});
|
||||
board.SetPowerSaveMode(true);
|
||||
});
|
||||
protocol_->OnIncomingJson([this](const cJSON* root) {
|
||||
protocol_->OnIncomingJson([this, display](const cJSON* root) {
|
||||
// Parse JSON data
|
||||
auto type = cJSON_GetObjectItem(root, "type");
|
||||
if (strcmp(type->valuestring, "tts") == 0) {
|
||||
@ -315,28 +322,30 @@ void Application::Start() {
|
||||
} else if (strcmp(state->valuestring, "sentence_start") == 0) {
|
||||
auto text = cJSON_GetObjectItem(root, "text");
|
||||
if (text != NULL) {
|
||||
ESP_LOGI(TAG, ">> %s", text->valuestring);
|
||||
ESP_LOGI(TAG, "<< %s", text->valuestring);
|
||||
display->SetChatMessage("assistant", text->valuestring);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(type->valuestring, "stt") == 0) {
|
||||
auto text = cJSON_GetObjectItem(root, "text");
|
||||
if (text != NULL) {
|
||||
ESP_LOGI(TAG, ">> %s", text->valuestring);
|
||||
display->SetChatMessage("user", text->valuestring);
|
||||
}
|
||||
} else if (strcmp(type->valuestring, "llm") == 0) {
|
||||
auto emotion = cJSON_GetObjectItem(root, "emotion");
|
||||
if (emotion != NULL) {
|
||||
ESP_LOGD(TAG, "EMOTION: %s", emotion->valuestring);
|
||||
display->SetEmotion(emotion->valuestring);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Blink the LED to indicate the device is running
|
||||
display->SetStatus("待命");
|
||||
builtin_led->SetGreen();
|
||||
builtin_led->BlinkOnce();
|
||||
|
||||
SetChatState(kChatStateIdle);
|
||||
display->UpdateDisplay();
|
||||
}
|
||||
|
||||
void Application::Schedule(std::function<void()> callback) {
|
||||
@ -394,7 +403,8 @@ void Application::SetChatState(ChatState state) {
|
||||
case kChatStateUnknown:
|
||||
case kChatStateIdle:
|
||||
builtin_led->TurnOff();
|
||||
display->SetText("I'm\nIdle.");
|
||||
display->SetStatus("待命");
|
||||
display->SetEmotion("neutral");
|
||||
#ifdef CONFIG_USE_AFE_SR
|
||||
audio_processor_.Stop();
|
||||
#endif
|
||||
@ -402,12 +412,13 @@ void Application::SetChatState(ChatState state) {
|
||||
case kChatStateConnecting:
|
||||
builtin_led->SetBlue();
|
||||
builtin_led->TurnOn();
|
||||
display->SetText("I'm\nConnecting...");
|
||||
display->SetStatus("连接中...");
|
||||
break;
|
||||
case kChatStateListening:
|
||||
builtin_led->SetRed();
|
||||
builtin_led->TurnOn();
|
||||
display->SetText("I'm\nListening...");
|
||||
display->SetStatus("聆听中...");
|
||||
display->SetEmotion("neutral");
|
||||
#ifdef CONFIG_USE_AFE_SR
|
||||
audio_processor_.Start();
|
||||
#endif
|
||||
@ -415,7 +426,7 @@ void Application::SetChatState(ChatState state) {
|
||||
case kChatStateSpeaking:
|
||||
builtin_led->SetGreen();
|
||||
builtin_led->TurnOn();
|
||||
display->SetText("I'm\nSpeaking...");
|
||||
display->SetStatus("说话中...");
|
||||
#ifdef CONFIG_USE_AFE_SR
|
||||
audio_processor_.Stop();
|
||||
#endif
|
||||
|
||||
@ -23,6 +23,8 @@ public:
|
||||
virtual ~AudioCodec();
|
||||
|
||||
virtual void SetOutputVolume(int volume);
|
||||
virtual void EnableInput(bool enable);
|
||||
virtual void EnableOutput(bool enable);
|
||||
|
||||
void Start();
|
||||
void OnInputData(std::function<void(std::vector<int16_t>&& data)> callback);
|
||||
@ -67,8 +69,6 @@ protected:
|
||||
|
||||
virtual int Read(int16_t* dest, int samples) = 0;
|
||||
virtual int Write(const int16_t* data, int samples) = 0;
|
||||
virtual void EnableInput(bool enable);
|
||||
virtual void EnableOutput(bool enable);
|
||||
};
|
||||
|
||||
#endif // _AUDIO_CODEC_H
|
||||
@ -22,8 +22,6 @@ private:
|
||||
|
||||
virtual int Read(int16_t* dest, int samples) override;
|
||||
virtual int Write(const int16_t* data, int samples) override;
|
||||
virtual void EnableInput(bool enable) override;
|
||||
virtual void EnableOutput(bool enable) override;
|
||||
|
||||
public:
|
||||
BoxAudioCodec(void* i2c_master_handle, int input_sample_rate, int output_sample_rate,
|
||||
@ -32,6 +30,8 @@ public:
|
||||
virtual ~BoxAudioCodec();
|
||||
|
||||
virtual void SetOutputVolume(int volume) override;
|
||||
virtual void EnableInput(bool enable) override;
|
||||
virtual void EnableOutput(bool enable) override;
|
||||
};
|
||||
|
||||
#endif // _BOX_AUDIO_CODEC_H
|
||||
|
||||
@ -48,13 +48,13 @@ private:
|
||||
volume = 100;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification("Volume\n" + std::to_string(volume));
|
||||
GetDisplay()->ShowNotification("音量 " + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_up_button_.OnLongPress([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
codec->SetOutputVolume(100);
|
||||
GetDisplay()->ShowNotification("Volume\n100");
|
||||
GetDisplay()->ShowNotification("最大音量");
|
||||
});
|
||||
|
||||
volume_down_button_.OnClick([this]() {
|
||||
@ -64,13 +64,13 @@ private:
|
||||
volume = 0;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification("Volume\n" + std::to_string(volume));
|
||||
GetDisplay()->ShowNotification("音量 " + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_down_button_.OnLongPress([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
codec->SetOutputVolume(0);
|
||||
GetDisplay()->ShowNotification("Volume\n0");
|
||||
GetDisplay()->ShowNotification("已静音");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -48,13 +48,13 @@ private:
|
||||
volume = 100;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification("Volume\n" + std::to_string(volume));
|
||||
GetDisplay()->ShowNotification("音量 " + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_up_button_.OnLongPress([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
codec->SetOutputVolume(100);
|
||||
GetDisplay()->ShowNotification("Volume\n100");
|
||||
GetDisplay()->ShowNotification("最大音量");
|
||||
});
|
||||
|
||||
volume_down_button_.OnClick([this]() {
|
||||
@ -64,13 +64,13 @@ private:
|
||||
volume = 0;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification("Volume\n" + std::to_string(volume));
|
||||
GetDisplay()->ShowNotification("音量 " + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_down_button_.OnLongPress([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
codec->SetOutputVolume(0);
|
||||
GetDisplay()->ShowNotification("Volume\n0");
|
||||
GetDisplay()->ShowNotification("已静音");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -41,6 +41,7 @@ public:
|
||||
virtual Mqtt* CreateMqtt() = 0;
|
||||
virtual Udp* CreateUdp() = 0;
|
||||
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) = 0;
|
||||
virtual const char* GetNetworkStateIcon() = 0;
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging);
|
||||
virtual std::string GetJson();
|
||||
virtual void SetPowerSaveMode(bool enabled) = 0;
|
||||
@ -11,7 +11,9 @@
|
||||
#define BLINK_TASK_STOPPED_BIT BIT0
|
||||
#define BLINK_TASK_RUNNING_BIT BIT1
|
||||
|
||||
#define DEFAULT_BRIGHTNESS 16
|
||||
#define DEFAULT_BRIGHTNESS 4
|
||||
#define HIGH_BRIGHTNESS 16
|
||||
#define LOW_BRIGHTNESS 2
|
||||
|
||||
class Led {
|
||||
public:
|
||||
@ -1,5 +1,6 @@
|
||||
#include "ml307_board.h"
|
||||
#include "application.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_timer.h>
|
||||
@ -34,7 +35,7 @@ Ml307Board::Ml307Board(gpio_num_t tx_pin, gpio_num_t rx_pin, size_t rx_buffer_si
|
||||
|
||||
void Ml307Board::StartNetwork() {
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetText(std::string("Starting modem"));
|
||||
display->SetStatus("初始化模块");
|
||||
modem_.SetDebug(false);
|
||||
modem_.SetBaudRate(921600);
|
||||
|
||||
@ -54,7 +55,7 @@ void Ml307Board::StartNetwork() {
|
||||
void Ml307Board::WaitForNetworkReady() {
|
||||
auto& application = Application::GetInstance();
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetText(std::string("Wait for network\n"));
|
||||
display->SetStatus("等待网络...");
|
||||
int result = modem_.WaitForNetworkReady();
|
||||
if (result == -1) {
|
||||
application.Alert("Error", "PIN is not ready");
|
||||
@ -103,6 +104,29 @@ bool Ml307Board::GetNetworkState(std::string& network_name, int& signal_quality,
|
||||
return signal_quality != -1;
|
||||
}
|
||||
|
||||
const char* Ml307Board::GetNetworkStateIcon() {
|
||||
if (!modem_.network_ready()) {
|
||||
return FONT_AWESOME_SIGNAL_OFF;
|
||||
}
|
||||
int csq = modem_.GetCsq();
|
||||
if (csq == -1) {
|
||||
return FONT_AWESOME_SIGNAL_OFF;
|
||||
} else if (csq >= 0 && csq <= 9) {
|
||||
return FONT_AWESOME_SIGNAL_1;
|
||||
} else if (csq >= 10 && csq <= 14) {
|
||||
return FONT_AWESOME_SIGNAL_2;
|
||||
} else if (csq >= 15 && csq <= 19) {
|
||||
return FONT_AWESOME_SIGNAL_3;
|
||||
} else if (csq >= 20 && csq <= 24) {
|
||||
return FONT_AWESOME_SIGNAL_4;
|
||||
} else if (csq >= 25 && csq <= 31) {
|
||||
return FONT_AWESOME_SIGNAL_FULL;
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "Invalid CSQ: %d", csq);
|
||||
return FONT_AWESOME_SIGNAL_OFF;
|
||||
}
|
||||
|
||||
std::string Ml307Board::GetBoardJson() {
|
||||
// Set the board type for OTA
|
||||
std::string board_type = BOARD_TYPE;
|
||||
|
||||
@ -20,6 +20,7 @@ public:
|
||||
virtual Mqtt* CreateMqtt() override;
|
||||
virtual Udp* CreateUdp() override;
|
||||
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) override;
|
||||
virtual const char* GetNetworkStateIcon() override;
|
||||
virtual void SetPowerSaveMode(bool enabled) override;
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "wifi_board.h"
|
||||
#include "application.h"
|
||||
#include "system_info.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
@ -38,7 +39,7 @@ void WifiBoard::StartNetwork() {
|
||||
|
||||
// Try to connect to WiFi, if failed, launch the WiFi configuration AP
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
display->SetText(std::string("Connect to WiFi\n") + wifi_station.GetSsid());
|
||||
display->SetStatus(std::string("正在连接 ") + wifi_station.GetSsid());
|
||||
wifi_station.Start();
|
||||
if (!wifi_station.IsConnected()) {
|
||||
builtin_led->SetBlue();
|
||||
@ -46,10 +47,18 @@ void WifiBoard::StartNetwork() {
|
||||
auto& wifi_ap = WifiConfigurationAp::GetInstance();
|
||||
wifi_ap.SetSsidPrefix("Xiaozhi");
|
||||
wifi_ap.Start();
|
||||
|
||||
// 播报配置 WiFi 的提示
|
||||
application.Alert("Info", "Configuring WiFi");
|
||||
|
||||
// 显示 WiFi 配置 AP 的 SSID 和 Web 服务器 URL
|
||||
display->SetText(wifi_ap.GetSsid() + "\n" + wifi_ap.GetWebServerUrl());
|
||||
std::string hint = "请在手机上连接热点 ";
|
||||
hint += wifi_ap.GetSsid();
|
||||
hint += ",然后打开浏览器访问 ";
|
||||
hint += wifi_ap.GetWebServerUrl();
|
||||
|
||||
display->SetStatus(hint);
|
||||
|
||||
// Wait forever until reset after configuration
|
||||
while (true) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
@ -103,6 +112,24 @@ bool WifiBoard::GetNetworkState(std::string& network_name, int& signal_quality,
|
||||
return signal_quality != -1;
|
||||
}
|
||||
|
||||
const char* WifiBoard::GetNetworkStateIcon() {
|
||||
if (wifi_config_mode_) {
|
||||
return FONT_AWESOME_WIFI;
|
||||
}
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
if (!wifi_station.IsConnected()) {
|
||||
return FONT_AWESOME_WIFI_OFF;
|
||||
}
|
||||
int8_t rssi = wifi_station.GetRssi();
|
||||
if (rssi >= -55) {
|
||||
return FONT_AWESOME_WIFI;
|
||||
} else if (rssi >= -65) {
|
||||
return FONT_AWESOME_WIFI_FAIR;
|
||||
} else {
|
||||
return FONT_AWESOME_WIFI_WEAK;
|
||||
}
|
||||
}
|
||||
|
||||
std::string WifiBoard::GetBoardJson() {
|
||||
// Set the board type for OTA
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
|
||||
@ -17,6 +17,7 @@ public:
|
||||
virtual Mqtt* CreateMqtt() override;
|
||||
virtual Udp* CreateUdp() override;
|
||||
virtual bool GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) override;
|
||||
virtual const char* GetNetworkStateIcon() override;
|
||||
virtual void SetPowerSaveMode(bool enabled) override;
|
||||
};
|
||||
|
||||
|
||||
@ -91,13 +91,13 @@ private:
|
||||
volume = 100;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification("Volume\n" + std::to_string(volume));
|
||||
GetDisplay()->ShowNotification("音量 " + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_up_button_.OnLongPress([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
codec->SetOutputVolume(100);
|
||||
GetDisplay()->ShowNotification("Volume\n100");
|
||||
GetDisplay()->ShowNotification("最大音量");
|
||||
});
|
||||
|
||||
volume_down_button_.OnClick([this]() {
|
||||
@ -107,13 +107,13 @@ private:
|
||||
volume = 0;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification("Volume\n" + std::to_string(volume));
|
||||
GetDisplay()->ShowNotification("音量 " + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_down_button_.OnLongPress([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
codec->SetOutputVolume(0);
|
||||
GetDisplay()->ShowNotification("Volume\n0");
|
||||
GetDisplay()->ShowNotification("已静音");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -86,6 +86,10 @@ private:
|
||||
Application::GetInstance().ToggleChatState();
|
||||
});
|
||||
|
||||
boot_button_.OnLongPress([this]() {
|
||||
axp2101_->PowerOff();
|
||||
});
|
||||
|
||||
volume_up_button_.OnClick([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
auto volume = codec->output_volume() + 10;
|
||||
@ -93,13 +97,13 @@ private:
|
||||
volume = 100;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification("Volume\n" + std::to_string(volume));
|
||||
GetDisplay()->ShowNotification("音量 " + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_up_button_.OnLongPress([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
codec->SetOutputVolume(100);
|
||||
GetDisplay()->ShowNotification("Volume\n100");
|
||||
GetDisplay()->ShowNotification("最大音量");
|
||||
});
|
||||
|
||||
volume_down_button_.OnClick([this]() {
|
||||
@ -109,13 +113,13 @@ private:
|
||||
volume = 0;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification("Volume\n" + std::to_string(volume));
|
||||
GetDisplay()->ShowNotification("音量 " + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_down_button_.OnLongPress([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
codec->SetOutputVolume(0);
|
||||
GetDisplay()->ShowNotification("Volume\n0");
|
||||
GetDisplay()->ShowNotification("已静音");
|
||||
});
|
||||
}
|
||||
|
||||
@ -160,7 +164,6 @@ public:
|
||||
virtual bool GetBatteryLevel(int &level, bool& charging) override {
|
||||
level = axp2101_->GetBatteryLevel();
|
||||
charging = axp2101_->IsCharging();
|
||||
ESP_LOGI(TAG, "Battery level: %d, Charging: %d", level, charging);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
136
main/display.cc
136
main/display.cc
@ -1,136 +0,0 @@
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "display.h"
|
||||
#include "board.h"
|
||||
#include "application.h"
|
||||
|
||||
#define TAG "Display"
|
||||
|
||||
void Display::SetupUI() {
|
||||
if (disp_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Setting up UI");
|
||||
Lock();
|
||||
label_ = lv_label_create(lv_disp_get_scr_act(disp_));
|
||||
// lv_obj_set_style_text_font(label_, font_, 0);
|
||||
lv_obj_set_style_text_color(label_, lv_color_black(), 0);
|
||||
lv_label_set_text(label_, "Initializing...");
|
||||
lv_obj_set_width(label_, disp_->driver->hor_res);
|
||||
lv_obj_set_height(label_, disp_->driver->ver_res);
|
||||
|
||||
notification_ = lv_label_create(lv_disp_get_scr_act(disp_));
|
||||
// lv_obj_set_style_text_font(notification_, font_, 0);
|
||||
lv_obj_set_style_text_color(notification_, lv_color_black(), 0);
|
||||
lv_label_set_text(notification_, "Notification\nTest");
|
||||
lv_obj_set_width(notification_, disp_->driver->hor_res);
|
||||
lv_obj_set_height(notification_, disp_->driver->ver_res);
|
||||
lv_obj_set_style_opa(notification_, LV_OPA_MIN, 0);
|
||||
Unlock();
|
||||
|
||||
// Create a timer to update the display every 10 seconds
|
||||
esp_timer_create_args_t update_display_timer_args = {
|
||||
.callback = [](void *arg) {
|
||||
Display* display = static_cast<Display*>(arg);
|
||||
display->UpdateDisplay();
|
||||
},
|
||||
.arg = this,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "UpdateDisplay",
|
||||
.skip_unhandled_events = false,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_timer_create(&update_display_timer_args, &update_display_timer_));
|
||||
ESP_ERROR_CHECK(esp_timer_start_periodic(update_display_timer_, 10 * 1000000));
|
||||
}
|
||||
|
||||
Display::~Display() {
|
||||
if (notification_timer_ != nullptr) {
|
||||
esp_timer_stop(notification_timer_);
|
||||
esp_timer_delete(notification_timer_);
|
||||
}
|
||||
if (update_display_timer_ != nullptr) {
|
||||
esp_timer_stop(update_display_timer_);
|
||||
esp_timer_delete(update_display_timer_);
|
||||
}
|
||||
if (label_ != nullptr) {
|
||||
lv_obj_del(label_);
|
||||
lv_obj_del(notification_);
|
||||
}
|
||||
if (font_ != nullptr) {
|
||||
lv_font_free(font_);
|
||||
}
|
||||
}
|
||||
|
||||
void Display::SetText(const std::string &text) {
|
||||
if (label_ != nullptr) {
|
||||
text_ = text;
|
||||
Lock();
|
||||
// Change the text of the label
|
||||
lv_label_set_text(label_, text_.c_str());
|
||||
Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void Display::ShowNotification(const std::string &text) {
|
||||
if (notification_ != nullptr) {
|
||||
Lock();
|
||||
lv_label_set_text(notification_, text.c_str());
|
||||
lv_obj_set_style_opa(notification_, LV_OPA_MAX, 0);
|
||||
lv_obj_set_style_opa(label_, LV_OPA_MIN, 0);
|
||||
Unlock();
|
||||
|
||||
if (notification_timer_ != nullptr) {
|
||||
esp_timer_stop(notification_timer_);
|
||||
esp_timer_delete(notification_timer_);
|
||||
}
|
||||
|
||||
esp_timer_create_args_t timer_args = {
|
||||
.callback = [](void *arg) {
|
||||
Display *display = static_cast<Display*>(arg);
|
||||
display->Lock();
|
||||
lv_obj_set_style_opa(display->notification_, LV_OPA_MIN, 0);
|
||||
lv_obj_set_style_opa(display->label_, LV_OPA_MAX, 0);
|
||||
display->Unlock();
|
||||
},
|
||||
.arg = this,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "Notification Timer",
|
||||
.skip_unhandled_events = false,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_timer_create(&timer_args, ¬ification_timer_));
|
||||
ESP_ERROR_CHECK(esp_timer_start_once(notification_timer_, 3000000));
|
||||
}
|
||||
}
|
||||
|
||||
void Display::UpdateDisplay() {
|
||||
auto chat_state = Application::GetInstance().GetChatState();
|
||||
if (chat_state == kChatStateIdle) {
|
||||
std::string text;
|
||||
auto& board = Board::GetInstance();
|
||||
std::string network_name;
|
||||
int signal_quality;
|
||||
std::string signal_quality_text;
|
||||
if (!board.GetNetworkState(network_name, signal_quality, signal_quality_text)) {
|
||||
text = "No network";
|
||||
} else {
|
||||
text = network_name + "\n" + signal_quality_text;
|
||||
if (std::abs(signal_quality) != 99) {
|
||||
text += " (" + std::to_string(signal_quality) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
int battery_level;
|
||||
bool charging;
|
||||
if (board.GetBatteryLevel(battery_level, charging)) {
|
||||
text += "\nPower " + std::to_string(battery_level) + "%";
|
||||
if (charging) {
|
||||
text += " (Charging)";
|
||||
}
|
||||
}
|
||||
SetText(text);
|
||||
}
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
class Display {
|
||||
public:
|
||||
virtual ~Display();
|
||||
|
||||
void SetupUI();
|
||||
void SetText(const std::string &text);
|
||||
void ShowNotification(const std::string &text);
|
||||
|
||||
void UpdateDisplay();
|
||||
|
||||
int width() const { return width_; }
|
||||
int height() const { return height_; }
|
||||
|
||||
protected:
|
||||
lv_disp_t *disp_ = nullptr;
|
||||
lv_font_t *font_ = nullptr;
|
||||
lv_obj_t *label_ = nullptr;
|
||||
lv_obj_t *notification_ = nullptr;
|
||||
esp_timer_handle_t notification_timer_ = nullptr;
|
||||
esp_timer_handle_t update_display_timer_ = nullptr;
|
||||
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
|
||||
std::string text_;
|
||||
|
||||
virtual void Lock() = 0;
|
||||
virtual void Unlock() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
192
main/display/display.cc
Normal file
192
main/display/display.cc
Normal file
@ -0,0 +1,192 @@
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "display.h"
|
||||
#include "board.h"
|
||||
#include "application.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "audio_codec.h"
|
||||
|
||||
#define TAG "Display"
|
||||
|
||||
Display::Display() {
|
||||
// Notification timer
|
||||
esp_timer_create_args_t notification_timer_args = {
|
||||
.callback = [](void *arg) {
|
||||
Display *display = static_cast<Display*>(arg);
|
||||
DisplayLockGuard lock(display);
|
||||
lv_obj_add_flag(display->notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(display->status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
},
|
||||
.arg = this,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "Notification Timer",
|
||||
.skip_unhandled_events = false,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_timer_create(¬ification_timer_args, ¬ification_timer_));
|
||||
|
||||
// Update display timer
|
||||
esp_timer_create_args_t update_display_timer_args = {
|
||||
.callback = [](void *arg) {
|
||||
Display *display = static_cast<Display*>(arg);
|
||||
display->Update();
|
||||
},
|
||||
.arg = this,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "Update Display Timer",
|
||||
.skip_unhandled_events = false,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_timer_create(&update_display_timer_args, &update_timer_));
|
||||
ESP_ERROR_CHECK(esp_timer_start_periodic(update_timer_, 1000000));
|
||||
}
|
||||
|
||||
Display::~Display() {
|
||||
esp_timer_stop(notification_timer_);
|
||||
esp_timer_stop(update_timer_);
|
||||
esp_timer_delete(notification_timer_);
|
||||
esp_timer_delete(update_timer_);
|
||||
|
||||
if (network_label_ != nullptr) {
|
||||
lv_obj_del(network_label_);
|
||||
lv_obj_del(notification_label_);
|
||||
lv_obj_del(status_label_);
|
||||
lv_obj_del(mute_label_);
|
||||
lv_obj_del(battery_label_);
|
||||
}
|
||||
}
|
||||
|
||||
void Display::SetStatus(const std::string &status) {
|
||||
if (status_label_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
DisplayLockGuard lock(this);
|
||||
lv_label_set_text(status_label_, status.c_str());
|
||||
}
|
||||
|
||||
void Display::ShowNotification(const std::string ¬ification, int duration_ms) {
|
||||
if (notification_label_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
DisplayLockGuard lock(this);
|
||||
lv_label_set_text(notification_label_, notification.c_str());
|
||||
lv_obj_clear_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
esp_timer_stop(notification_timer_);
|
||||
ESP_ERROR_CHECK(esp_timer_start_once(notification_timer_, duration_ms * 1000));
|
||||
}
|
||||
|
||||
void Display::Update() {
|
||||
if (mute_label_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& board = Board::GetInstance();
|
||||
auto codec = board.GetAudioCodec();
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
// 如果静音状态改变,则更新图标
|
||||
if (codec->output_volume() == 0 && !muted_) {
|
||||
muted_ = true;
|
||||
lv_label_set_text(mute_label_, FONT_AWESOME_VOLUME_MUTE);
|
||||
} else if (codec->output_volume() > 0 && muted_) {
|
||||
muted_ = false;
|
||||
lv_label_set_text(mute_label_, "");
|
||||
}
|
||||
|
||||
// 更新电池图标
|
||||
int battery_level;
|
||||
bool charging;
|
||||
const char* icon = nullptr;
|
||||
if (board.GetBatteryLevel(battery_level, charging)) {
|
||||
if (charging) {
|
||||
icon = FONT_AWESOME_BATTERY_CHARGING;
|
||||
} else {
|
||||
const char* levels[] = {
|
||||
FONT_AWESOME_BATTERY_EMPTY, // 0-19%
|
||||
FONT_AWESOME_BATTERY_1, // 20-39%
|
||||
FONT_AWESOME_BATTERY_2, // 40-59%
|
||||
FONT_AWESOME_BATTERY_3, // 60-79%
|
||||
FONT_AWESOME_BATTERY_FULL, // 80-99%
|
||||
FONT_AWESOME_BATTERY_FULL, // 100%
|
||||
};
|
||||
icon = levels[battery_level / 20];
|
||||
}
|
||||
if (battery_icon_ != icon) {
|
||||
battery_icon_ = icon;
|
||||
lv_label_set_text(battery_label_, battery_icon_);
|
||||
}
|
||||
}
|
||||
|
||||
// 仅在聊天状态为空闲时,更新网络图标
|
||||
auto chat_state = Application::GetInstance().GetChatState();
|
||||
if (chat_state == kChatStateIdle || chat_state == kChatStateUnknown) {
|
||||
icon = board.GetNetworkStateIcon();
|
||||
if (network_icon_ != icon) {
|
||||
network_icon_ = icon;
|
||||
lv_label_set_text(network_label_, network_icon_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Display::SetEmotion(const std::string &emotion) {
|
||||
if (emotion_label_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct Emotion {
|
||||
const char* icon;
|
||||
const char* text;
|
||||
};
|
||||
|
||||
static const std::vector<Emotion> emotions = {
|
||||
{FONT_AWESOME_EMOJI_NEUTRAL, "neutral"},
|
||||
{FONT_AWESOME_EMOJI_HAPPY, "happy"},
|
||||
{FONT_AWESOME_EMOJI_LAUGHING, "laughing"},
|
||||
{FONT_AWESOME_EMOJI_FUNNY, "funny"},
|
||||
{FONT_AWESOME_EMOJI_SAD, "sad"},
|
||||
{FONT_AWESOME_EMOJI_ANGRY, "angry"},
|
||||
{FONT_AWESOME_EMOJI_CRYING, "crying"},
|
||||
{FONT_AWESOME_EMOJI_LOVING, "loving"},
|
||||
{FONT_AWESOME_EMOJI_EMBARRASSED, "embarrassed"},
|
||||
{FONT_AWESOME_EMOJI_SURPRISED, "surprised"},
|
||||
{FONT_AWESOME_EMOJI_SHOCKED, "shocked"},
|
||||
{FONT_AWESOME_EMOJI_THINKING, "thinking"},
|
||||
{FONT_AWESOME_EMOJI_WINKING, "winking"},
|
||||
{FONT_AWESOME_EMOJI_COOL, "cool"},
|
||||
{FONT_AWESOME_EMOJI_RELAXED, "relaxed"},
|
||||
{FONT_AWESOME_EMOJI_DELICIOUS, "delicious"},
|
||||
{FONT_AWESOME_EMOJI_KISSY, "kissy"},
|
||||
{FONT_AWESOME_EMOJI_CONFIDENT, "confident"},
|
||||
{FONT_AWESOME_EMOJI_SLEEPY, "sleepy"},
|
||||
{FONT_AWESOME_EMOJI_SILLY, "silly"},
|
||||
{FONT_AWESOME_EMOJI_CONFUSED, "confused"}
|
||||
};
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
|
||||
// 查找匹配的表情
|
||||
auto it = std::find_if(emotions.begin(), emotions.end(),
|
||||
[&emotion](const Emotion& e) { return e.text == emotion; });
|
||||
|
||||
// 如果找到匹配的表情就显示对应图标,否则显示默认的neutral表情
|
||||
if (it != emotions.end()) {
|
||||
lv_label_set_text(emotion_label_, it->icon);
|
||||
} else {
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_EMOJI_NEUTRAL);
|
||||
}
|
||||
}
|
||||
|
||||
void Display::SetIcon(const char* icon) {
|
||||
if (emotion_label_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
DisplayLockGuard lock(this);
|
||||
lv_label_set_text(emotion_label_, icon);
|
||||
}
|
||||
|
||||
void Display::SetChatMessage(const std::string &role, const std::string &content) {
|
||||
}
|
||||
64
main/display/display.h
Normal file
64
main/display/display.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
class Display {
|
||||
public:
|
||||
Display();
|
||||
virtual ~Display();
|
||||
|
||||
virtual void SetStatus(const std::string &status);
|
||||
virtual void ShowNotification(const std::string ¬ification, int duration_ms = 3000);
|
||||
virtual void SetEmotion(const std::string &emotion);
|
||||
virtual void SetChatMessage(const std::string &role, const std::string &content);
|
||||
virtual void SetIcon(const char* icon);
|
||||
|
||||
int width() const { return width_; }
|
||||
int height() const { return height_; }
|
||||
|
||||
protected:
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
|
||||
lv_disp_t *disp_ = nullptr;
|
||||
|
||||
lv_obj_t *emotion_label_ = nullptr;
|
||||
lv_obj_t *network_label_ = nullptr;
|
||||
lv_obj_t *status_label_ = nullptr;
|
||||
lv_obj_t *notification_label_ = nullptr;
|
||||
lv_obj_t *mute_label_ = nullptr;
|
||||
lv_obj_t *battery_label_ = nullptr;
|
||||
const char* battery_icon_ = nullptr;
|
||||
const char* network_icon_ = nullptr;
|
||||
bool muted_ = false;
|
||||
|
||||
esp_timer_handle_t notification_timer_ = nullptr;
|
||||
esp_timer_handle_t update_timer_ = nullptr;
|
||||
|
||||
friend class DisplayLockGuard;
|
||||
virtual void Lock() = 0;
|
||||
virtual void Unlock() = 0;
|
||||
|
||||
virtual void Update();
|
||||
};
|
||||
|
||||
|
||||
class DisplayLockGuard {
|
||||
public:
|
||||
DisplayLockGuard(Display *display) : display_(display) {
|
||||
display_->Lock();
|
||||
}
|
||||
~DisplayLockGuard() {
|
||||
display_->Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
Display *display_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,4 +1,5 @@
|
||||
#include "ssd1306_display.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
@ -8,6 +9,10 @@
|
||||
|
||||
#define TAG "Ssd1306Display"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_14_1);
|
||||
LV_FONT_DECLARE(font_awesome_30_1);
|
||||
LV_FONT_DECLARE(font_awesome_14_1);
|
||||
|
||||
Ssd1306Display::Ssd1306Display(void* i2c_master_handle, int width, int height, bool mirror_x, bool mirror_y)
|
||||
: mirror_x_(mirror_x), mirror_y_(mirror_y) {
|
||||
width_ = width;
|
||||
@ -85,9 +90,33 @@ Ssd1306Display::Ssd1306Display(void* i2c_master_handle, int width, int height, b
|
||||
};
|
||||
|
||||
disp_ = lvgl_port_add_disp(&display_cfg);
|
||||
|
||||
if (disp_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to add display");
|
||||
return;
|
||||
}
|
||||
|
||||
if (height_ == 64) {
|
||||
SetupUI_128x64();
|
||||
} else {
|
||||
SetupUI_128x32();
|
||||
}
|
||||
}
|
||||
|
||||
Ssd1306Display::~Ssd1306Display() {
|
||||
if (content_ != nullptr) {
|
||||
lv_obj_del(content_);
|
||||
}
|
||||
if (status_bar_ != nullptr) {
|
||||
lv_obj_del(status_bar_);
|
||||
}
|
||||
if (side_bar_ != nullptr) {
|
||||
lv_obj_del(side_bar_);
|
||||
}
|
||||
if (container_ != nullptr) {
|
||||
lv_obj_del(container_);
|
||||
}
|
||||
|
||||
if (panel_ != nullptr) {
|
||||
esp_lcd_panel_del(panel_);
|
||||
}
|
||||
@ -104,3 +133,134 @@ void Ssd1306Display::Lock() {
|
||||
void Ssd1306Display::Unlock() {
|
||||
lvgl_port_unlock();
|
||||
}
|
||||
|
||||
void Ssd1306Display::SetupUI_128x64() {
|
||||
DisplayLockGuard lock(this);
|
||||
|
||||
auto screen = lv_disp_get_scr_act(disp_);
|
||||
lv_obj_set_style_text_font(screen, &font_puhui_14_1, 0);
|
||||
lv_obj_set_style_text_color(screen, lv_color_black(), 0);
|
||||
|
||||
/* Container */
|
||||
container_ = lv_obj_create(screen);
|
||||
lv_obj_set_size(container_, LV_HOR_RES, LV_VER_RES);
|
||||
lv_obj_set_flex_flow(container_, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_all(container_, 0, 0);
|
||||
lv_obj_set_style_border_width(container_, 0, 0);
|
||||
lv_obj_set_style_pad_row(container_, 0, 0);
|
||||
|
||||
/* Status bar */
|
||||
status_bar_ = lv_obj_create(container_);
|
||||
lv_obj_set_size(status_bar_, LV_HOR_RES, 18);
|
||||
lv_obj_set_style_radius(status_bar_, 0, 0);
|
||||
|
||||
/* Content */
|
||||
content_ = lv_obj_create(container_);
|
||||
lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_obj_set_style_radius(status_bar_, 0, 0);
|
||||
lv_obj_set_width(content_, LV_HOR_RES);
|
||||
lv_obj_set_flex_grow(content_, 1);
|
||||
|
||||
emotion_label_ = lv_label_create(content_);
|
||||
lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_1, 0);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP);
|
||||
lv_obj_center(emotion_label_);
|
||||
|
||||
/* Status bar */
|
||||
lv_obj_set_flex_flow(status_bar_, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_all(status_bar_, 0, 0);
|
||||
lv_obj_set_style_border_width(status_bar_, 0, 0);
|
||||
lv_obj_set_style_pad_column(status_bar_, 0, 0);
|
||||
|
||||
network_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(network_label_, "");
|
||||
lv_obj_set_style_text_font(network_label_, &font_awesome_14_1, 0);
|
||||
|
||||
notification_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_flex_grow(notification_label_, 1);
|
||||
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_label_set_text(notification_label_, "通知");
|
||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
status_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_flex_grow(status_label_, 1);
|
||||
lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||
lv_label_set_text(status_label_, "正在初始化");
|
||||
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||
|
||||
mute_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(mute_label_, "");
|
||||
lv_obj_set_style_text_font(mute_label_, &font_awesome_14_1, 0);
|
||||
|
||||
battery_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(battery_label_, "");
|
||||
lv_obj_set_style_text_font(battery_label_, &font_awesome_14_1, 0);
|
||||
}
|
||||
|
||||
void Ssd1306Display::SetupUI_128x32() {
|
||||
DisplayLockGuard lock(this);
|
||||
|
||||
auto screen = lv_disp_get_scr_act(disp_);
|
||||
lv_obj_set_style_text_font(screen, &font_puhui_14_1, 0);
|
||||
|
||||
/* Container */
|
||||
container_ = lv_obj_create(screen);
|
||||
lv_obj_set_size(container_, LV_HOR_RES, LV_VER_RES);
|
||||
lv_obj_set_flex_flow(container_, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_all(container_, 0, 0);
|
||||
lv_obj_set_style_border_width(container_, 0, 0);
|
||||
lv_obj_set_style_pad_column(container_, 0, 0);
|
||||
|
||||
/* Left side */
|
||||
side_bar_ = lv_obj_create(container_);
|
||||
lv_obj_set_flex_grow(side_bar_, 1);
|
||||
lv_obj_set_flex_flow(side_bar_, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_all(side_bar_, 0, 0);
|
||||
lv_obj_set_style_border_width(side_bar_, 0, 0);
|
||||
lv_obj_set_style_radius(side_bar_, 0, 0);
|
||||
lv_obj_set_style_pad_row(side_bar_, 0, 0);
|
||||
|
||||
/* Emotion label on the right side */
|
||||
content_ = lv_obj_create(container_);
|
||||
lv_obj_set_size(content_, 32, 32);
|
||||
lv_obj_set_style_pad_all(content_, 0, 0);
|
||||
lv_obj_set_style_border_width(content_, 0, 0);
|
||||
lv_obj_set_style_radius(content_, 0, 0);
|
||||
|
||||
emotion_label_ = lv_label_create(content_);
|
||||
lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_1, 0);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP);
|
||||
lv_obj_center(emotion_label_);
|
||||
|
||||
/* Status bar */
|
||||
status_bar_ = lv_obj_create(side_bar_);
|
||||
lv_obj_set_size(status_bar_, LV_SIZE_CONTENT, 16);
|
||||
lv_obj_set_style_radius(status_bar_, 0, 0);
|
||||
lv_obj_set_flex_flow(status_bar_, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_all(status_bar_, 0, 0);
|
||||
lv_obj_set_style_border_width(status_bar_, 0, 0);
|
||||
lv_obj_set_style_pad_column(status_bar_, 0, 0);
|
||||
|
||||
network_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(network_label_, "");
|
||||
lv_obj_set_style_text_font(network_label_, &font_awesome_14_1, 0);
|
||||
|
||||
mute_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(mute_label_, "");
|
||||
lv_obj_set_style_text_font(mute_label_, &font_awesome_14_1, 0);
|
||||
|
||||
battery_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(battery_label_, "");
|
||||
lv_obj_set_style_text_font(battery_label_, &font_awesome_14_1, 0);
|
||||
|
||||
status_label_ = lv_label_create(side_bar_);
|
||||
lv_obj_set_flex_grow(status_label_, 1);
|
||||
lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||
lv_label_set_text(status_label_, "正在初始化");
|
||||
|
||||
notification_label_ = lv_label_create(side_bar_);
|
||||
lv_obj_set_flex_grow(notification_label_, 1);
|
||||
lv_label_set_text(notification_label_, "通知");
|
||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
|
||||
@ -13,9 +13,17 @@ private:
|
||||
bool mirror_x_ = false;
|
||||
bool mirror_y_ = false;
|
||||
|
||||
lv_obj_t* status_bar_ = nullptr;
|
||||
lv_obj_t* content_ = nullptr;
|
||||
lv_obj_t* container_ = nullptr;
|
||||
lv_obj_t* side_bar_ = nullptr;
|
||||
|
||||
virtual void Lock() override;
|
||||
virtual void Unlock() override;
|
||||
|
||||
void SetupUI_128x64();
|
||||
void SetupUI_128x32();
|
||||
|
||||
public:
|
||||
Ssd1306Display(void* i2c_master_handle, int width, int height, bool mirror_x = false, bool mirror_y = false);
|
||||
~Ssd1306Display();
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "st7789_display.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
@ -9,6 +10,10 @@
|
||||
#define TAG "St7789Display"
|
||||
#define LCD_LEDC_CH LEDC_CHANNEL_0
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_14_1);
|
||||
LV_FONT_DECLARE(font_awesome_30_1);
|
||||
LV_FONT_DECLARE(font_awesome_14_1);
|
||||
|
||||
St7789Display::St7789Display(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel,
|
||||
gpio_num_t backlight_pin, bool backlight_output_invert,
|
||||
int width, int height, bool mirror_x, bool mirror_y, bool swap_xy)
|
||||
@ -61,9 +66,24 @@ St7789Display::St7789Display(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_h
|
||||
disp_ = lvgl_port_add_disp(&display_cfg);
|
||||
|
||||
SetBacklight(100);
|
||||
|
||||
SetupUI();
|
||||
}
|
||||
|
||||
St7789Display::~St7789Display() {
|
||||
if (content_ != nullptr) {
|
||||
lv_obj_del(content_);
|
||||
}
|
||||
if (status_bar_ != nullptr) {
|
||||
lv_obj_del(status_bar_);
|
||||
}
|
||||
if (side_bar_ != nullptr) {
|
||||
lv_obj_del(side_bar_);
|
||||
}
|
||||
if (container_ != nullptr) {
|
||||
lv_obj_del(container_);
|
||||
}
|
||||
|
||||
if (panel_ != nullptr) {
|
||||
esp_lcd_panel_del(panel_);
|
||||
}
|
||||
@ -127,3 +147,66 @@ void St7789Display::Lock() {
|
||||
void St7789Display::Unlock() {
|
||||
lvgl_port_unlock();
|
||||
}
|
||||
|
||||
void St7789Display::SetupUI() {
|
||||
DisplayLockGuard lock(this);
|
||||
|
||||
auto screen = lv_disp_get_scr_act(disp_);
|
||||
lv_obj_set_style_text_font(screen, &font_puhui_14_1, 0);
|
||||
lv_obj_set_style_text_color(screen, lv_color_black(), 0);
|
||||
|
||||
/* Container */
|
||||
container_ = lv_obj_create(screen);
|
||||
lv_obj_set_size(container_, LV_HOR_RES, LV_VER_RES);
|
||||
lv_obj_set_flex_flow(container_, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_all(container_, 0, 0);
|
||||
lv_obj_set_style_border_width(container_, 0, 0);
|
||||
lv_obj_set_style_pad_row(container_, 0, 0);
|
||||
|
||||
/* Status bar */
|
||||
status_bar_ = lv_obj_create(container_);
|
||||
lv_obj_set_size(status_bar_, LV_HOR_RES, 18);
|
||||
lv_obj_set_style_radius(status_bar_, 0, 0);
|
||||
|
||||
/* Content */
|
||||
content_ = lv_obj_create(container_);
|
||||
lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_obj_set_style_radius(content_, 0, 0);
|
||||
lv_obj_set_width(content_, LV_HOR_RES);
|
||||
lv_obj_set_flex_grow(content_, 1);
|
||||
|
||||
emotion_label_ = lv_label_create(content_);
|
||||
lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_1, 0);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP);
|
||||
lv_obj_center(emotion_label_);
|
||||
|
||||
/* Status bar */
|
||||
lv_obj_set_flex_flow(status_bar_, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_all(status_bar_, 0, 0);
|
||||
lv_obj_set_style_border_width(status_bar_, 0, 0);
|
||||
lv_obj_set_style_pad_column(status_bar_, 0, 0);
|
||||
|
||||
network_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(network_label_, "");
|
||||
lv_obj_set_style_text_font(network_label_, &font_awesome_14_1, 0);
|
||||
|
||||
notification_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_flex_grow(notification_label_, 1);
|
||||
lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_label_set_text(notification_label_, "通知");
|
||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
status_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_flex_grow(status_label_, 1);
|
||||
lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||
lv_label_set_text(status_label_, "正在初始化");
|
||||
lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0);
|
||||
|
||||
mute_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(mute_label_, "");
|
||||
lv_obj_set_style_text_font(mute_label_, &font_awesome_14_1, 0);
|
||||
|
||||
battery_label_ = lv_label_create(status_bar_);
|
||||
lv_label_set_text(battery_label_, "");
|
||||
lv_obj_set_style_text_font(battery_label_, &font_awesome_14_1, 0);
|
||||
}
|
||||
|
||||
@ -16,9 +16,15 @@ private:
|
||||
bool mirror_x_ = false;
|
||||
bool mirror_y_ = false;
|
||||
bool swap_xy_ = false;
|
||||
|
||||
lv_obj_t* status_bar_ = nullptr;
|
||||
lv_obj_t* content_ = nullptr;
|
||||
lv_obj_t* container_ = nullptr;
|
||||
lv_obj_t* side_bar_ = nullptr;
|
||||
|
||||
void InitializeBacklight(gpio_num_t backlight_pin);
|
||||
void SetBacklight(uint8_t brightness);
|
||||
void SetupUI();
|
||||
|
||||
virtual void Lock() override;
|
||||
virtual void Unlock() override;
|
||||
|
||||
7515
main/fonts/GB2312.TXT
Normal file
7515
main/fonts/GB2312.TXT
Normal file
File diff suppressed because it is too large
Load Diff
565
main/fonts/font_awesome_14_1.c
Normal file
565
main/fonts/font_awesome_14_1.c
Normal file
@ -0,0 +1,565 @@
|
||||
/*******************************************************************************
|
||||
* Size: 14 px
|
||||
* Bpp: 1
|
||||
* Opts: --no-compress --no-prefilter --force-fast-kern-format --font fa-regular-400.ttf --format lvgl --lv-include lvgl.h --bpp 1 -o font_awesome_14_1.c --size 14 -r 0xf5a4,0xf118,0xf59b,0xf588,0xe384,0xf556,0xf5b3,0xf584,0xf579,0xe36b,0xe375,0xe39b,0xf4da,0xe398,0xe392,0xe372,0xf598,0xe409,0xe38d,0xe3a4,0xe36d,0xf240,0xf241,0xf242,0xf243,0xf244,0xf377,0xf376,0xf1eb,0xf6ab,0xf6aa,0xf6ac,0xf012,0xf68f,0xf68e,0xf68d,0xf68c,0xf695,0xf028,0xf6a8,0xf027,0xf6a9,0xf001,0xf00c,0xf00d,0xf011,0xf013,0xf1f8,0xf015,0xf03e,0xf044,0xf048,0xf051,0xf04b,0xf04c,0xf04d,0xf060,0xf061,0xf062,0xf063,0xf071,0xf0f3,0xf3c5,0xf0ac,0xf124,0xf7c2,0xf293,0xf075,0xe1ec,0xf007,0xe04b,0xf019
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||
#include "lvgl.h"
|
||||
#else
|
||||
#include "lvgl.h"
|
||||
#endif
|
||||
|
||||
#ifndef FONT_AWESOME_14_1
|
||||
#define FONT_AWESOME_14_1 1
|
||||
#endif
|
||||
|
||||
#if FONT_AWESOME_14_1
|
||||
|
||||
/*-----------------
|
||||
* BITMAPS
|
||||
*----------------*/
|
||||
|
||||
/*Store the image of the glyphs*/
|
||||
static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
/* U+E04B "" */
|
||||
0x2, 0x0, 0x20, 0x1f, 0x8a, 0x5, 0xad, 0x5a,
|
||||
0x5, 0xaa, 0x53, 0xf8, 0x0, 0x0, 0x0, 0x7f,
|
||||
0xec, 0x3, 0x8b, 0x1f, 0xff,
|
||||
|
||||
/* U+E1EC "" */
|
||||
0x9, 0x40, 0x25, 0x3, 0xff, 0x8, 0x4, 0xe0,
|
||||
0x1c, 0x89, 0x4e, 0x55, 0xcb, 0xd4, 0x68, 0x5b,
|
||||
0x80, 0x72, 0x1, 0xf, 0xfc, 0x9, 0x40, 0x25,
|
||||
0x0,
|
||||
|
||||
/* U+E36B "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x16, 0x32, 0xe0,
|
||||
0x2e, 0x23, 0x18, 0x8c, 0x60, 0x1, 0x87, 0x7,
|
||||
0x1c, 0x34, 0x70, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+E36D "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x10, 0x2, 0xc8,
|
||||
0xce, 0x23, 0x18, 0x0, 0x60, 0x1, 0x83, 0xc7,
|
||||
0x30, 0x34, 0x80, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+E372 "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x10, 0x2, 0x8c,
|
||||
0xc6, 0x40, 0x98, 0x0, 0x60, 0x1, 0x80, 0x26,
|
||||
0x21, 0xb4, 0x7e, 0x88, 0x2a, 0x18, 0xa0, 0x38,
|
||||
0x80,
|
||||
|
||||
/* U+E375 "" */
|
||||
0xf, 0xc0, 0xe1, 0xc7, 0x8f, 0x98, 0x6, 0xfc,
|
||||
0xee, 0x95, 0x5b, 0xd5, 0x66, 0x39, 0x80, 0x6,
|
||||
0x1c, 0x14, 0xf8, 0x88, 0x4, 0x10, 0x20, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+E384 "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x12, 0x12, 0xd8,
|
||||
0x6e, 0x80, 0x58, 0x0, 0x60, 0x1, 0x9c, 0xe7,
|
||||
0x0, 0x34, 0x78, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+E38D "" */
|
||||
0x7, 0x9c, 0x7f, 0x33, 0x1, 0xd8, 0x38, 0xc0,
|
||||
0x42, 0x3, 0xb8, 0x0, 0x60, 0x1, 0x9c, 0xe6,
|
||||
0x0, 0x1c, 0x30, 0x50, 0xc2, 0x20, 0x18, 0x60,
|
||||
0xc0, 0xfc, 0x0,
|
||||
|
||||
/* U+E392 "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x10, 0x2, 0xc0,
|
||||
0xe, 0x73, 0x98, 0x0, 0x60, 0x1, 0x80, 0x7,
|
||||
0x21, 0x34, 0x78, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+E398 "" */
|
||||
0xf, 0xc0, 0x40, 0x82, 0x1, 0x1f, 0xfe, 0xff,
|
||||
0xff, 0xf3, 0xfb, 0xcf, 0x60, 0x1, 0x80, 0x7,
|
||||
0x21, 0x34, 0x78, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+E39B "" */
|
||||
0xf, 0xc0, 0x41, 0x82, 0x81, 0x15, 0x82, 0x88,
|
||||
0xce, 0x3, 0x18, 0x0, 0x63, 0x1, 0x82, 0x7,
|
||||
0x84, 0x36, 0xf0, 0x9f, 0x4, 0x7c, 0x60, 0xee,
|
||||
0x0,
|
||||
|
||||
/* U+E3A4 "" */
|
||||
0xf, 0xc0, 0xe1, 0x87, 0x1d, 0x18, 0x76, 0xd9,
|
||||
0x4f, 0xd2, 0x3f, 0xc7, 0x76, 0x3d, 0xc3, 0xef,
|
||||
0x15, 0xa6, 0xc5, 0x8d, 0x1c, 0x1c, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+E409 "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x16, 0x32, 0xed,
|
||||
0x6e, 0x94, 0x9b, 0xde, 0x60, 0x1, 0x9f, 0xe7,
|
||||
0x7c, 0xb4, 0xe4, 0x89, 0xe4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F001 "" */
|
||||
0x0, 0xc, 0x3, 0xf0, 0x7c, 0x43, 0x1, 0x8,
|
||||
0x3c, 0x2f, 0x90, 0xf0, 0x42, 0x1, 0x8, 0x3c,
|
||||
0x21, 0x1f, 0x84, 0x62, 0xe, 0x88, 0x1, 0xc0,
|
||||
0x0,
|
||||
|
||||
/* U+F007 "" */
|
||||
0xf, 0x1, 0x98, 0x10, 0x81, 0x8, 0x10, 0x81,
|
||||
0xf8, 0xf, 0x0, 0x0, 0x1f, 0x86, 0x6, 0x40,
|
||||
0x2c, 0x3, 0x80, 0x1f, 0xff,
|
||||
|
||||
/* U+F00C "" */
|
||||
0x0, 0x10, 0x3, 0x0, 0x60, 0xc, 0xc1, 0x86,
|
||||
0x30, 0x36, 0x1, 0xc0, 0x8, 0x0,
|
||||
|
||||
/* U+F00D "" */
|
||||
0x81, 0xe1, 0x99, 0x87, 0x81, 0x81, 0xe1, 0x99,
|
||||
0x86, 0x81, 0x80,
|
||||
|
||||
/* U+F011 "" */
|
||||
0x2, 0x1, 0x11, 0x18, 0x8c, 0x84, 0x2c, 0x21,
|
||||
0xc1, 0x6, 0x8, 0x30, 0x1, 0x80, 0xa, 0x0,
|
||||
0x98, 0xc, 0x60, 0xc0, 0xf8, 0x0,
|
||||
|
||||
/* U+F012 "" */
|
||||
0x0, 0x2, 0x0, 0x4, 0x0, 0x48, 0x0, 0x90,
|
||||
0x1, 0x20, 0x22, 0x40, 0x44, 0x80, 0x89, 0x9,
|
||||
0x12, 0x12, 0x26, 0x24, 0x4c, 0x48, 0x98, 0x91,
|
||||
0x31, 0x22, 0x40,
|
||||
|
||||
/* U+F013 "" */
|
||||
0xf, 0x80, 0x44, 0x1e, 0x3c, 0xa0, 0xac, 0x21,
|
||||
0xe6, 0xcd, 0x22, 0x49, 0x32, 0xcf, 0x9e, 0x10,
|
||||
0xd4, 0x14, 0xf1, 0xe0, 0x88, 0x3, 0x80,
|
||||
|
||||
/* U+F015 "" */
|
||||
0x0, 0x0, 0x1, 0x80, 0x7, 0xc0, 0xc, 0x30,
|
||||
0x18, 0x18, 0x30, 0xc, 0x60, 0x6, 0xe0, 0x7,
|
||||
0x23, 0xc4, 0x22, 0x44, 0x22, 0x44, 0x22, 0x44,
|
||||
0x22, 0x44, 0x22, 0x44, 0x1f, 0xf8,
|
||||
|
||||
/* U+F019 "" */
|
||||
0x2, 0x0, 0x10, 0x0, 0x80, 0x4, 0x0, 0x20,
|
||||
0x19, 0x30, 0x6b, 0x1, 0xf0, 0xf7, 0x7c, 0x10,
|
||||
0x60, 0xb, 0x0, 0x58, 0x0, 0xff, 0xfc,
|
||||
|
||||
/* U+F027 "" */
|
||||
0x3, 0x0, 0x70, 0xd, 0x7, 0x90, 0xf1, 0x38,
|
||||
0x11, 0x81, 0x1f, 0x13, 0x79, 0x0, 0xd0, 0x7,
|
||||
0x0, 0x30,
|
||||
|
||||
/* U+F028 "" */
|
||||
0x0, 0x0, 0x1, 0x83, 0x1, 0xc0, 0xc1, 0xa1,
|
||||
0xa7, 0x90, 0x6f, 0x89, 0x96, 0x4, 0x4b, 0x2,
|
||||
0x25, 0xf1, 0x32, 0xbc, 0x82, 0xc3, 0x43, 0x40,
|
||||
0xe0, 0x60, 0x30, 0x60,
|
||||
|
||||
/* U+F03E "" */
|
||||
0xff, 0xfe, 0x0, 0x18, 0x0, 0x66, 0x1, 0x98,
|
||||
0x6, 0x2, 0x18, 0x1c, 0x66, 0xf9, 0xbf, 0xe6,
|
||||
0xff, 0xdf, 0xff, 0xff, 0xff,
|
||||
|
||||
/* U+F044 "" */
|
||||
0x0, 0x10, 0x1, 0xe7, 0xcc, 0xe0, 0xea, 0x85,
|
||||
0x1a, 0x8, 0xc8, 0x46, 0x22, 0x30, 0x89, 0x92,
|
||||
0x3c, 0x48, 0x81, 0x20, 0x4, 0x80, 0x11, 0xff,
|
||||
0x80,
|
||||
|
||||
/* U+F048 "" */
|
||||
0x87, 0x1e, 0xef, 0x1c, 0x38, 0x78, 0xdd, 0x8f,
|
||||
0xc,
|
||||
|
||||
/* U+F04B "" */
|
||||
0x0, 0x38, 0xb, 0x82, 0x30, 0x87, 0x20, 0x68,
|
||||
0xe, 0x3, 0x83, 0xa3, 0x89, 0x83, 0xc0, 0xc0,
|
||||
0x0,
|
||||
|
||||
/* U+F04C "" */
|
||||
0xf7, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
|
||||
0x95, 0xf7,
|
||||
|
||||
/* U+F04D "" */
|
||||
0xff, 0xe0, 0x18, 0x6, 0x1, 0x80, 0x60, 0x18,
|
||||
0x6, 0x1, 0x80, 0x7f, 0xf0,
|
||||
|
||||
/* U+F051 "" */
|
||||
0xc3, 0xc6, 0xec, 0x78, 0x70, 0xe3, 0xdd, 0xe3,
|
||||
0x84,
|
||||
|
||||
/* U+F060 "" */
|
||||
0x4, 0x0, 0xc0, 0x18, 0x3, 0x0, 0x60, 0xf,
|
||||
0xff, 0x60, 0x3, 0x0, 0x18, 0x0, 0xc0, 0x4,
|
||||
0x0,
|
||||
|
||||
/* U+F061 "" */
|
||||
0x0, 0x0, 0x30, 0x1, 0x80, 0xc, 0x0, 0x6f,
|
||||
0xff, 0x0, 0x60, 0xc, 0x1, 0x80, 0x30, 0x0,
|
||||
0x0,
|
||||
|
||||
/* U+F062 "" */
|
||||
0xe, 0x1, 0xc0, 0x54, 0x12, 0xc6, 0x4c, 0x88,
|
||||
0x81, 0x0, 0x20, 0x4, 0x0, 0x80, 0x10, 0x2,
|
||||
0x0,
|
||||
|
||||
/* U+F063 "" */
|
||||
0x4, 0x0, 0x80, 0x10, 0x2, 0x0, 0x40, 0x8,
|
||||
0x31, 0x1b, 0x26, 0x35, 0x83, 0xe0, 0x38, 0x2,
|
||||
0x0,
|
||||
|
||||
/* U+F071 "" */
|
||||
0x3, 0x0, 0x1e, 0x1, 0x48, 0x2, 0x90, 0x1a,
|
||||
0x61, 0xc8, 0x82, 0x21, 0x18, 0x6, 0x42, 0xb,
|
||||
0x8, 0x38, 0x0, 0x7f, 0xff,
|
||||
|
||||
/* U+F075 "" */
|
||||
0xf, 0xc0, 0xc0, 0xc4, 0x0, 0xb0, 0x3, 0x80,
|
||||
0x6, 0x0, 0x18, 0x0, 0x70, 0x3, 0x40, 0x9,
|
||||
0x0, 0xcf, 0xfc, 0x30, 0x0,
|
||||
|
||||
/* U+F0AC "" */
|
||||
0xf, 0xc0, 0xf3, 0xc6, 0xc9, 0x92, 0x12, 0xff,
|
||||
0xfe, 0x21, 0x18, 0x84, 0x62, 0x11, 0xff, 0xfd,
|
||||
0x21, 0x26, 0x49, 0x8f, 0x3c, 0x1f, 0xe0,
|
||||
|
||||
/* U+F0F3 "" */
|
||||
0x6, 0x0, 0xf0, 0x10, 0x82, 0x4, 0x20, 0x42,
|
||||
0x4, 0x20, 0x42, 0x4, 0x60, 0x64, 0x2, 0xff,
|
||||
0xf0, 0x0, 0xf, 0x0, 0x60,
|
||||
|
||||
/* U+F118 "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x10, 0x2, 0xc8,
|
||||
0xce, 0x23, 0x18, 0x0, 0x60, 0x1, 0x80, 0x7,
|
||||
0x21, 0x34, 0x78, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F124 "" */
|
||||
0x0, 0x20, 0xf, 0x7, 0xa1, 0xe6, 0x78, 0x4f,
|
||||
0xec, 0x2, 0xc0, 0x38, 0x3, 0x80, 0x30, 0x3,
|
||||
0x0, 0x20,
|
||||
|
||||
/* U+F1EB "" */
|
||||
0x7, 0xf8, 0xe, 0x3, 0x86, 0x0, 0x3b, 0x0,
|
||||
0x2, 0x0, 0x0, 0x0, 0xfc, 0x0, 0xc1, 0xc0,
|
||||
0x40, 0x10, 0x0, 0x0, 0x0, 0x70, 0x0, 0x1c,
|
||||
0x0, 0x2, 0x0,
|
||||
|
||||
/* U+F1F8 "" */
|
||||
0xf, 0x81, 0x88, 0xff, 0xf4, 0x2, 0x40, 0x24,
|
||||
0x2, 0x60, 0x26, 0x2, 0x60, 0x26, 0x2, 0x60,
|
||||
0x62, 0x6, 0x20, 0x63, 0xfc,
|
||||
|
||||
/* U+F240 "" */
|
||||
0x7f, 0xfc, 0x80, 0x2, 0xbf, 0xf3, 0xbf, 0xf3,
|
||||
0xbf, 0xf3, 0x80, 0x2, 0x80, 0x2, 0x7f, 0xfc,
|
||||
|
||||
/* U+F241 "" */
|
||||
0x7f, 0xfc, 0x80, 0x2, 0xbf, 0x83, 0xbf, 0x83,
|
||||
0xbf, 0x83, 0x80, 0x2, 0x80, 0x2, 0x7f, 0xfc,
|
||||
|
||||
/* U+F242 "" */
|
||||
0x7f, 0xfc, 0x80, 0x2, 0x9f, 0x3, 0x9f, 0x3,
|
||||
0x9f, 0x3, 0x80, 0x2, 0x80, 0x2, 0x7f, 0xfc,
|
||||
|
||||
/* U+F243 "" */
|
||||
0x7f, 0xfc, 0x80, 0x2, 0xb8, 0x3, 0xb8, 0x3,
|
||||
0xb8, 0x3, 0x80, 0x2, 0x80, 0x2, 0x7f, 0xfc,
|
||||
|
||||
/* U+F244 "" */
|
||||
0x7f, 0xfc, 0x80, 0x2, 0x80, 0x3, 0x80, 0x3,
|
||||
0x80, 0x3, 0x80, 0x2, 0x80, 0x2, 0x7f, 0xfc,
|
||||
|
||||
/* U+F293 "" */
|
||||
0xc, 0x7, 0x2, 0xd9, 0x36, 0xb1, 0xf0, 0x70,
|
||||
0x38, 0x7f, 0x64, 0xc2, 0xc1, 0xc0, 0xc0, 0x40,
|
||||
|
||||
/* U+F376 "" */
|
||||
0x7e, 0xdc, 0x81, 0x82, 0x83, 0x83, 0x87, 0xc3,
|
||||
0x87, 0xc3, 0x83, 0x82, 0x83, 0x2, 0x76, 0xfc,
|
||||
|
||||
/* U+F377 "" */
|
||||
0x80, 0x0, 0x30, 0x0, 0x3, 0x0, 0x0, 0x7f,
|
||||
0xf8, 0x4e, 0x1, 0x10, 0xc0, 0x64, 0x18, 0x19,
|
||||
0x3, 0x86, 0x40, 0x31, 0x10, 0x7, 0x43, 0xfe,
|
||||
0x60, 0x0, 0xc, 0x0, 0x1, 0xc0, 0x0, 0x10,
|
||||
|
||||
/* U+F3C5 "" */
|
||||
0x1e, 0x18, 0x64, 0xa, 0x31, 0x92, 0x64, 0x98,
|
||||
0xc5, 0x2, 0x40, 0x88, 0x43, 0x30, 0x48, 0x1c,
|
||||
0x3, 0x0,
|
||||
|
||||
/* U+F4DA "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x10, 0x2, 0xc8,
|
||||
0xce, 0x22, 0x98, 0x0, 0x60, 0x1, 0x80, 0x7,
|
||||
0x21, 0x34, 0x78, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F556 "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x10, 0x2, 0xc0,
|
||||
0xe, 0x73, 0x98, 0x84, 0x60, 0x1, 0x80, 0x7,
|
||||
0xc, 0x34, 0x78, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F579 "" */
|
||||
0xf, 0xc0, 0x61, 0xc2, 0x1, 0x90, 0x2, 0xdc,
|
||||
0xee, 0x94, 0x5b, 0xb5, 0x67, 0x39, 0x80, 0x7,
|
||||
0x3e, 0x34, 0x0, 0x88, 0x6, 0x18, 0x70, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F584 "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x10, 0x2, 0xc4,
|
||||
0x8e, 0x73, 0x98, 0xcc, 0x60, 0x1, 0x80, 0x7,
|
||||
0x3f, 0x34, 0x78, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F588 "" */
|
||||
0x3, 0xf0, 0x1, 0x86, 0x1, 0x80, 0x60, 0x40,
|
||||
0x8, 0x33, 0x33, 0x9, 0xce, 0x40, 0x0, 0x3,
|
||||
0x80, 0x7, 0xe0, 0x1, 0xf4, 0xfc, 0xb1, 0x1e,
|
||||
0x20, 0x60, 0x18, 0xe, 0x1c, 0x0, 0xfc, 0x0,
|
||||
|
||||
/* U+F598 "" */
|
||||
0xf, 0xc0, 0x60, 0x82, 0x1, 0x90, 0x2, 0x88,
|
||||
0x6, 0x23, 0x98, 0x0, 0x60, 0xc1, 0x83, 0x36,
|
||||
0xc, 0xf4, 0x33, 0xc8, 0xf, 0x10, 0x0, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F59B "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x10, 0xa, 0xd8,
|
||||
0x6e, 0x33, 0x19, 0x2, 0x60, 0x1, 0x8f, 0xe7,
|
||||
0x3f, 0x34, 0x78, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F5A4 "" */
|
||||
0xf, 0xc0, 0x61, 0x82, 0x1, 0x10, 0x2, 0xc8,
|
||||
0xce, 0x23, 0x18, 0x0, 0x60, 0x1, 0x80, 0x7,
|
||||
0x0, 0x34, 0x0, 0x88, 0x4, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F5B3 "" */
|
||||
0xf, 0xc0, 0x40, 0x82, 0x1, 0x10, 0x2, 0x80,
|
||||
0x6, 0x73, 0x98, 0x0, 0x65, 0xc9, 0xd7, 0x2f,
|
||||
0x5c, 0xb7, 0x3, 0x8c, 0xc, 0x18, 0x60, 0x3f,
|
||||
0x0,
|
||||
|
||||
/* U+F68C "" */
|
||||
0xf0,
|
||||
|
||||
/* U+F68D "" */
|
||||
0x8, 0x63, 0x18, 0xc4,
|
||||
|
||||
/* U+F68E "" */
|
||||
0x0, 0x80, 0x40, 0x21, 0x10, 0x8c, 0x46, 0x23,
|
||||
0x11, 0x88, 0x80,
|
||||
|
||||
/* U+F68F "" */
|
||||
0x0, 0x10, 0x1, 0x0, 0x10, 0x11, 0x1, 0x10,
|
||||
0x11, 0x9, 0x10, 0x91, 0x89, 0x18, 0x91, 0x89,
|
||||
0x18, 0x91,
|
||||
|
||||
/* U+F695 "" */
|
||||
0xc0, 0x1, 0x30, 0x0, 0x8c, 0x2, 0x43, 0x1,
|
||||
0x20, 0x60, 0x90, 0x1c, 0x48, 0x6, 0x24, 0x1,
|
||||
0xd2, 0x4, 0x39, 0x2, 0x4c, 0x91, 0x23, 0xc8,
|
||||
0x90, 0xe4, 0x48, 0x9a, 0x24, 0x44,
|
||||
|
||||
/* U+F6A8 "" */
|
||||
0x3, 0x0, 0xe, 0x0, 0x34, 0x33, 0xc8, 0x3f,
|
||||
0x13, 0x30, 0x22, 0x60, 0x44, 0xf8, 0x99, 0x79,
|
||||
0x4, 0x1a, 0x18, 0x1c, 0x0, 0x18, 0x0,
|
||||
|
||||
/* U+F6A9 "" */
|
||||
0x3, 0x0, 0xe, 0x0, 0x34, 0x3, 0xc9, 0x1f,
|
||||
0x13, 0x70, 0x23, 0xa0, 0x47, 0x78, 0x9b, 0x79,
|
||||
0x22, 0x1a, 0x0, 0x1c, 0x0, 0x18, 0x0,
|
||||
|
||||
/* U+F6AA "" */
|
||||
0xfd, 0x0,
|
||||
|
||||
/* U+F6AB "" */
|
||||
0x1f, 0x86, 0xe, 0x80, 0x20, 0x0, 0x6, 0x0,
|
||||
0xe0, 0x6, 0x0,
|
||||
|
||||
/* U+F6AC "" */
|
||||
0x80, 0x0, 0x37, 0xfc, 0xe, 0x3, 0x93, 0x0,
|
||||
0x78, 0xe0, 0x8, 0x1c, 0x0, 0x27, 0xc0, 0x39,
|
||||
0xb8, 0x10, 0x34, 0x0, 0xc, 0x0, 0x73, 0x0,
|
||||
0x38, 0xe0, 0x8, 0x18, 0x0, 0x4,
|
||||
|
||||
/* U+F7C2 "" */
|
||||
0x1f, 0xc8, 0x14, 0x96, 0x35, 0x80, 0x60, 0x18,
|
||||
0x6, 0x1, 0x80, 0x60, 0x18, 0x6, 0x1, 0x80,
|
||||
0x7f, 0xf0
|
||||
};
|
||||
|
||||
|
||||
/*---------------------
|
||||
* GLYPH DESCRIPTION
|
||||
*--------------------*/
|
||||
|
||||
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
|
||||
{.bitmap_index = 0, .adv_w = 196, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 21, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 46, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 71, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 96, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 121, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 146, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 171, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 198, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 223, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 248, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 273, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 298, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 323, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 348, .adv_w = 196, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 369, .adv_w = 196, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 383, .adv_w = 168, .box_w = 9, .box_h = 9, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 394, .adv_w = 224, .box_w = 13, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 416, .adv_w = 280, .box_w = 15, .box_h = 14, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 443, .adv_w = 224, .box_w = 13, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 466, .adv_w = 252, .box_w = 16, .box_h = 15, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 496, .adv_w = 224, .box_w = 13, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 519, .adv_w = 196, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 537, .adv_w = 280, .box_w = 17, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 565, .adv_w = 224, .box_w = 14, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 586, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 611, .adv_w = 140, .box_w = 7, .box_h = 10, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 620, .adv_w = 168, .box_w = 10, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 637, .adv_w = 140, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 647, .adv_w = 168, .box_w = 10, .box_h = 10, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 660, .adv_w = 140, .box_w = 7, .box_h = 10, .ofs_x = 1, .ofs_y = 0},
|
||||
{.bitmap_index = 669, .adv_w = 196, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 686, .adv_w = 196, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 703, .adv_w = 168, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 720, .adv_w = 168, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 737, .adv_w = 224, .box_w = 14, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 758, .adv_w = 224, .box_w = 14, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 779, .adv_w = 224, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 802, .adv_w = 196, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 823, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 848, .adv_w = 196, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 866, .adv_w = 280, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 893, .adv_w = 196, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 914, .adv_w = 252, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 930, .adv_w = 252, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 946, .adv_w = 252, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 962, .adv_w = 252, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 978, .adv_w = 252, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 994, .adv_w = 168, .box_w = 9, .box_h = 14, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 1010, .adv_w = 252, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 1026, .adv_w = 280, .box_w = 18, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1058, .adv_w = 168, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1076, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1101, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1126, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1151, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1176, .adv_w = 280, .box_w = 18, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1208, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1233, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1258, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1283, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1308, .adv_w = 280, .box_w = 1, .box_h = 4, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 1309, .adv_w = 280, .box_w = 5, .box_h = 6, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 1313, .adv_w = 280, .box_w = 9, .box_h = 9, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 1324, .adv_w = 280, .box_w = 12, .box_h = 12, .ofs_x = 1, .ofs_y = -2},
|
||||
{.bitmap_index = 1342, .adv_w = 280, .box_w = 17, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1372, .adv_w = 252, .box_w = 15, .box_h = 12, .ofs_x = 1, .ofs_y = -1},
|
||||
{.bitmap_index = 1395, .adv_w = 252, .box_w = 15, .box_h = 12, .ofs_x = 0, .ofs_y = -1},
|
||||
{.bitmap_index = 1418, .adv_w = 280, .box_w = 3, .box_h = 3, .ofs_x = 7, .ofs_y = -1},
|
||||
{.bitmap_index = 1420, .adv_w = 280, .box_w = 12, .box_h = 7, .ofs_x = 3, .ofs_y = -1},
|
||||
{.bitmap_index = 1431, .adv_w = 280, .box_w = 17, .box_h = 14, .ofs_x = 0, .ofs_y = -2},
|
||||
{.bitmap_index = 1461, .adv_w = 168, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -2}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
* CHARACTER MAPPING
|
||||
*--------------------*/
|
||||
|
||||
static const uint16_t unicode_list_0[] = {
|
||||
0x0, 0x1a1, 0x320, 0x322, 0x327, 0x32a, 0x339, 0x342,
|
||||
0x347, 0x34d, 0x350, 0x359, 0x3be, 0xfb6, 0xfbc, 0xfc1,
|
||||
0xfc2, 0xfc6, 0xfc7, 0xfc8, 0xfca, 0xfce, 0xfdc, 0xfdd,
|
||||
0xff3, 0xff9, 0xffd, 0x1000, 0x1001, 0x1002, 0x1006, 0x1015,
|
||||
0x1016, 0x1017, 0x1018, 0x1026, 0x102a, 0x1061, 0x10a8, 0x10cd,
|
||||
0x10d9, 0x11a0, 0x11ad, 0x11f5, 0x11f6, 0x11f7, 0x11f8, 0x11f9,
|
||||
0x1248, 0x132b, 0x132c, 0x137a, 0x148f, 0x150b, 0x152e, 0x1539,
|
||||
0x153d, 0x154d, 0x1550, 0x1559, 0x1568, 0x1641, 0x1642, 0x1643,
|
||||
0x1644, 0x164a, 0x165d, 0x165e, 0x165f, 0x1660, 0x1661, 0x1777
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
{
|
||||
{
|
||||
.range_start = 57419, .range_length = 6008, .glyph_id_start = 1,
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 72, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*--------------------
|
||||
* ALL CUSTOM DATA
|
||||
*--------------------*/
|
||||
|
||||
#if LVGL_VERSION_MAJOR == 8
|
||||
/*Store all the custom data of the font*/
|
||||
static lv_font_fmt_txt_glyph_cache_t cache;
|
||||
#endif
|
||||
|
||||
#if LVGL_VERSION_MAJOR >= 8
|
||||
static const lv_font_fmt_txt_dsc_t font_dsc = {
|
||||
#else
|
||||
static lv_font_fmt_txt_dsc_t font_dsc = {
|
||||
#endif
|
||||
.glyph_bitmap = glyph_bitmap,
|
||||
.glyph_dsc = glyph_dsc,
|
||||
.cmaps = cmaps,
|
||||
.kern_dsc = NULL,
|
||||
.kern_scale = 0,
|
||||
.cmap_num = 1,
|
||||
.bpp = 1,
|
||||
.kern_classes = 0,
|
||||
.bitmap_format = 0,
|
||||
#if LVGL_VERSION_MAJOR == 8
|
||||
.cache = &cache
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*-----------------
|
||||
* PUBLIC FONT
|
||||
*----------------*/
|
||||
|
||||
/*Initialize a public general font descriptor*/
|
||||
#if LVGL_VERSION_MAJOR >= 8
|
||||
const lv_font_t font_awesome_14_1 = {
|
||||
#else
|
||||
lv_font_t font_awesome_14_1 = {
|
||||
#endif
|
||||
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
|
||||
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
|
||||
.line_height = 15, /*The maximum line height required by the font*/
|
||||
.base_line = 2, /*Baseline measured from the bottom of the line*/
|
||||
#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0)
|
||||
.subpx = LV_FONT_SUBPX_NONE,
|
||||
#endif
|
||||
#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8
|
||||
.underline_position = -1,
|
||||
.underline_thickness = 1,
|
||||
#endif
|
||||
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
|
||||
#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9
|
||||
.fallback = NULL,
|
||||
#endif
|
||||
.user_data = NULL,
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /*#if FONT_AWESOME_14_1*/
|
||||
|
||||
1233
main/fonts/font_awesome_30_1.c
Normal file
1233
main/fonts/font_awesome_30_1.c
Normal file
File diff suppressed because it is too large
Load Diff
77
main/fonts/font_awesome_symbols.h
Normal file
77
main/fonts/font_awesome_symbols.h
Normal file
@ -0,0 +1,77 @@
|
||||
#ifndef FONT_AWESOME_SYMBOLS_H
|
||||
#define FONT_AWESOME_SYMBOLS_H
|
||||
|
||||
#define FONT_AWESOME_EMOJI_NEUTRAL "\xef\x96\xa4"
|
||||
#define FONT_AWESOME_EMOJI_HAPPY "\xef\x84\x98"
|
||||
#define FONT_AWESOME_EMOJI_LAUGHING "\xef\x96\x9b"
|
||||
#define FONT_AWESOME_EMOJI_FUNNY "\xef\x96\x88"
|
||||
#define FONT_AWESOME_EMOJI_SAD "\xee\x8e\x84"
|
||||
#define FONT_AWESOME_EMOJI_ANGRY "\xef\x95\x96"
|
||||
#define FONT_AWESOME_EMOJI_CRYING "\xef\x96\xb3"
|
||||
#define FONT_AWESOME_EMOJI_LOVING "\xef\x96\x84"
|
||||
#define FONT_AWESOME_EMOJI_EMBARRASSED "\xef\x95\xb9"
|
||||
#define FONT_AWESOME_EMOJI_SURPRISED "\xee\x8d\xab"
|
||||
#define FONT_AWESOME_EMOJI_SHOCKED "\xee\x8d\xb5"
|
||||
#define FONT_AWESOME_EMOJI_THINKING "\xee\x8e\x9b"
|
||||
#define FONT_AWESOME_EMOJI_WINKING "\xef\x93\x9a"
|
||||
#define FONT_AWESOME_EMOJI_COOL "\xee\x8e\x98"
|
||||
#define FONT_AWESOME_EMOJI_RELAXED "\xee\x8e\x92"
|
||||
#define FONT_AWESOME_EMOJI_DELICIOUS "\xee\x8d\xb2"
|
||||
#define FONT_AWESOME_EMOJI_KISSY "\xef\x96\x98"
|
||||
#define FONT_AWESOME_EMOJI_CONFIDENT "\xee\x90\x89"
|
||||
#define FONT_AWESOME_EMOJI_SLEEPY "\xee\x8e\x8d"
|
||||
#define FONT_AWESOME_EMOJI_SILLY "\xee\x8e\xa4"
|
||||
#define FONT_AWESOME_EMOJI_CONFUSED "\xee\x8d\xad"
|
||||
#define FONT_AWESOME_BATTERY_FULL "\xef\x89\x80"
|
||||
#define FONT_AWESOME_BATTERY_3 "\xef\x89\x81"
|
||||
#define FONT_AWESOME_BATTERY_2 "\xef\x89\x82"
|
||||
#define FONT_AWESOME_BATTERY_1 "\xef\x89\x83"
|
||||
#define FONT_AWESOME_BATTERY_EMPTY "\xef\x89\x84"
|
||||
#define FONT_AWESOME_BATTERY_SLASH "\xef\x8d\xb7"
|
||||
#define FONT_AWESOME_BATTERY_CHARGING "\xef\x8d\xb6"
|
||||
#define FONT_AWESOME_WIFI "\xef\x87\xab"
|
||||
#define FONT_AWESOME_WIFI_FAIR "\xef\x9a\xab"
|
||||
#define FONT_AWESOME_WIFI_WEAK "\xef\x9a\xaa"
|
||||
#define FONT_AWESOME_WIFI_OFF "\xef\x9a\xac"
|
||||
#define FONT_AWESOME_SIGNAL_FULL "\xef\x80\x92"
|
||||
#define FONT_AWESOME_SIGNAL_4 "\xef\x9a\x8f"
|
||||
#define FONT_AWESOME_SIGNAL_3 "\xef\x9a\x8e"
|
||||
#define FONT_AWESOME_SIGNAL_2 "\xef\x9a\x8d"
|
||||
#define FONT_AWESOME_SIGNAL_1 "\xef\x9a\x8c"
|
||||
#define FONT_AWESOME_SIGNAL_OFF "\xef\x9a\x95"
|
||||
#define FONT_AWESOME_VOLUME_HIGH "\xef\x80\xa8"
|
||||
#define FONT_AWESOME_VOLUME_MEDIUM "\xef\x9a\xa8"
|
||||
#define FONT_AWESOME_VOLUME_LOW "\xef\x80\xa7"
|
||||
#define FONT_AWESOME_VOLUME_MUTE "\xef\x9a\xa9"
|
||||
#define FONT_AWESOME_MUSIC "\xef\x80\x81"
|
||||
#define FONT_AWESOME_CHECK "\xef\x80\x8c"
|
||||
#define FONT_AWESOME_XMARK "\xef\x80\x8d"
|
||||
#define FONT_AWESOME_POWER "\xef\x80\x91"
|
||||
#define FONT_AWESOME_GEAR "\xef\x80\x93"
|
||||
#define FONT_AWESOME_TRASH "\xef\x87\xb8"
|
||||
#define FONT_AWESOME_HOME "\xef\x80\x95"
|
||||
#define FONT_AWESOME_IMAGE "\xef\x80\xbe"
|
||||
#define FONT_AWESOME_EDIT "\xef\x81\x84"
|
||||
#define FONT_AWESOME_PREV "\xef\x81\x88"
|
||||
#define FONT_AWESOME_NEXT "\xef\x81\x91"
|
||||
#define FONT_AWESOME_PLAY "\xef\x81\x8b"
|
||||
#define FONT_AWESOME_PAUSE "\xef\x81\x8c"
|
||||
#define FONT_AWESOME_STOP "\xef\x81\x8d"
|
||||
#define FONT_AWESOME_MICARROW_LEFT "\xef\x81\xa0"
|
||||
#define FONT_AWESOME_ARROW_RIGHT "\xef\x81\xa1"
|
||||
#define FONT_AWESOME_ARROW_UP "\xef\x81\xa2"
|
||||
#define FONT_AWESOME_ARROW_DOWN "\xef\x81\xa3"
|
||||
#define FONT_AWESOME_WARNING "\xef\x81\xb1"
|
||||
#define FONT_AWESOME_BELL "\xef\x83\xb3"
|
||||
#define FONT_AWESOME_LOCATION "\xef\x8f\x85"
|
||||
#define FONT_AWESOME_GLOBE "\xef\x82\xac"
|
||||
#define FONT_AWESOME_LOCATION_ARROW "\xef\x84\xa4"
|
||||
#define FONT_AWESOME_SD_CARD "\xef\x9f\x82"
|
||||
#define FONT_AWESOME_BLUETOOTH "\xef\x8a\x93"
|
||||
#define FONT_AWESOME_COMMENT "\xef\x81\xb5"
|
||||
#define FONT_AWESOME_AI_CHIP "\xee\x87\xac"
|
||||
#define FONT_AWESOME_USER "\xef\x80\x87"
|
||||
#define FONT_AWESOME_USER_ROBOT "\xee\x81\x8b"
|
||||
#define FONT_AWESOME_DOWNLOAD "\xef\x80\x99"
|
||||
|
||||
#endif
|
||||
48889
main/fonts/font_puhui_14_1.c
Normal file
48889
main/fonts/font_puhui_14_1.c
Normal file
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
||||
dependencies:
|
||||
78/esp-wifi-connect: "~1.4.0"
|
||||
78/esp-opus-encoder: "~1.1.0"
|
||||
78/esp-ml307: "~1.6.0"
|
||||
78/esp-ml307: "~1.6.3"
|
||||
espressif/led_strip: "^2.4.1"
|
||||
espressif/esp_codec_dev: "^1.3.1"
|
||||
espressif/esp-sr: "^1.9.0"
|
||||
|
||||
@ -36,8 +36,8 @@ void Ota::SetPostData(const std::string& post_data) {
|
||||
}
|
||||
|
||||
bool Ota::CheckVersion() {
|
||||
std::string current_version = esp_app_get_description()->version;
|
||||
ESP_LOGI(TAG, "Current version: %s", current_version.c_str());
|
||||
current_version_ = esp_app_get_description()->version;
|
||||
ESP_LOGI(TAG, "Current version: %s", current_version_.c_str());
|
||||
|
||||
if (check_version_url_.length() < 10) {
|
||||
ESP_LOGE(TAG, "Check version URL is not properly set");
|
||||
@ -109,7 +109,7 @@ bool Ota::CheckVersion() {
|
||||
cJSON_Delete(root);
|
||||
|
||||
// Check if the version is newer, for example, 0.1.0 is newer than 0.0.1
|
||||
has_new_version_ = IsNewVersionAvailable(current_version, firmware_version_);
|
||||
has_new_version_ = IsNewVersionAvailable(current_version_, firmware_version_);
|
||||
if (has_new_version_) {
|
||||
ESP_LOGI(TAG, "New version available: %s", firmware_version_.c_str());
|
||||
} else {
|
||||
|
||||
@ -19,10 +19,14 @@ public:
|
||||
void StartUpgrade(std::function<void(int progress, size_t speed)> callback);
|
||||
void MarkCurrentVersionValid();
|
||||
|
||||
const std::string& GetFirmwareVersion() const { return firmware_version_; }
|
||||
const std::string& GetCurrentVersion() const { return current_version_; }
|
||||
|
||||
private:
|
||||
std::string check_version_url_;
|
||||
bool has_new_version_ = false;
|
||||
bool has_mqtt_config_ = false;
|
||||
std::string current_version_;
|
||||
std::string firmware_version_;
|
||||
std::string firmware_url_;
|
||||
std::string post_data_;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user