mirror of
https://github.com/78/xiaozhi-esp32.git
synced 2026-02-14 16:08:07 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc5d724506 | ||
|
|
bba26ef69c | ||
|
|
7fcd40dbe7 | ||
|
|
48a1c5da29 |
49
.github/workflows/build.yml
vendored
49
.github/workflows/build.yml
vendored
@@ -14,10 +14,10 @@ permissions:
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
name: Determine variants to build
|
||||
name: Determine boards to build
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
variants: ${{ steps.select.outputs.variants }}
|
||||
boards: ${{ steps.select.outputs.boards }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -28,30 +28,30 @@ jobs:
|
||||
run: sudo apt-get update && sudo apt-get install -y jq
|
||||
|
||||
- id: list
|
||||
name: Get all variant list
|
||||
name: Get all board list
|
||||
run: |
|
||||
echo "all_variants=$(python scripts/release.py --list-boards --json)" >> $GITHUB_OUTPUT
|
||||
echo "all_boards=$(python scripts/release.py --list-boards --json)" >> $GITHUB_OUTPUT
|
||||
|
||||
- id: select
|
||||
name: Select variants based on changes
|
||||
name: Select boards based on changes
|
||||
env:
|
||||
ALL_VARIANTS: ${{ steps.list.outputs.all_variants }}
|
||||
ALL_BOARDS: ${{ steps.list.outputs.all_boards }}
|
||||
run: |
|
||||
EVENT_NAME="${{ github.event_name }}"
|
||||
|
||||
# push 到 main 分支,编译全部变体
|
||||
# For push to main branch, build all boards
|
||||
if [[ "$EVENT_NAME" == "push" ]]; then
|
||||
echo "variants=$ALL_VARIANTS" >> $GITHUB_OUTPUT
|
||||
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# pull_request 场景
|
||||
# For pull_request
|
||||
BASE_SHA="${{ github.event.pull_request.base.sha }}"
|
||||
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
|
||||
echo "Base: $BASE_SHA, Head: $HEAD_SHA"
|
||||
|
||||
CHANGED=$(git diff --name-only $BASE_SHA $HEAD_SHA || true)
|
||||
echo -e "Changed files:\n$CHANGED"
|
||||
echo "Changed files:\n$CHANGED"
|
||||
|
||||
NEED_ALL=0
|
||||
declare -A AFFECTED
|
||||
@@ -60,10 +60,6 @@ jobs:
|
||||
NEED_ALL=1
|
||||
fi
|
||||
|
||||
if [[ "$file" == main/boards/common/* ]]; then
|
||||
NEED_ALL=1
|
||||
fi
|
||||
|
||||
if [[ "$file" == main/boards/* ]]; then
|
||||
board=$(echo "$file" | cut -d '/' -f3)
|
||||
AFFECTED[$board]=1
|
||||
@@ -71,25 +67,24 @@ jobs:
|
||||
done <<< "$CHANGED"
|
||||
|
||||
if [[ "$NEED_ALL" -eq 1 ]]; then
|
||||
echo "variants=$ALL_VARIANTS" >> $GITHUB_OUTPUT
|
||||
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
|
||||
else
|
||||
if [[ ${#AFFECTED[@]} -eq 0 ]]; then
|
||||
echo "variants=[]" >> $GITHUB_OUTPUT
|
||||
echo "boards=[]" >> $GITHUB_OUTPUT
|
||||
else
|
||||
BOARDS_JSON=$(printf '%s\n' "${!AFFECTED[@]}" | sort -u | jq -R -s -c 'split("\n")[:-1]')
|
||||
FILTERED=$(echo "$ALL_VARIANTS" | jq -c --argjson boards "$BOARDS_JSON" 'map(select(.board as $b | $boards | index($b)))')
|
||||
echo "variants=$FILTERED" >> $GITHUB_OUTPUT
|
||||
JSON=$(printf '%s\n' "${!AFFECTED[@]}" | sort -u | jq -R -s -c 'split("\n")[:-1]')
|
||||
echo "boards=$JSON" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
|
||||
build:
|
||||
name: Build ${{ matrix.name }}
|
||||
name: Build ${{ matrix.board }}
|
||||
needs: prepare
|
||||
if: ${{ needs.prepare.outputs.variants != '[]' }}
|
||||
if: ${{ needs.prepare.outputs.boards != '[]' }}
|
||||
strategy:
|
||||
fail-fast: false # 单个变体失败不影响其它变体
|
||||
fail-fast: false # 单个 board 失败不影响其它 board
|
||||
matrix:
|
||||
include: ${{ fromJson(needs.prepare.outputs.variants) }}
|
||||
board: ${{ fromJson(needs.prepare.outputs.boards) }}
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: espressif/idf:release-v5.4
|
||||
@@ -97,15 +92,15 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build current variant
|
||||
- name: Build current board
|
||||
shell: bash
|
||||
run: |
|
||||
source $IDF_PATH/export.sh
|
||||
python scripts/release.py ${{ matrix.board }} --name ${{ matrix.name }}
|
||||
python scripts/release.py ${{ matrix.board }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: xiaozhi_${{ matrix.name }}_${{ github.sha }}.bin
|
||||
name: xiaozhi_${{ matrix.board }}_${{ github.sha }}.bin
|
||||
path: build/merged-binary.bin
|
||||
if-no-files-found: error
|
||||
if-no-files-found: error
|
||||
@@ -4,7 +4,7 @@
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(PROJECT_VER "1.9.4")
|
||||
set(PROJECT_VER "1.8.6")
|
||||
|
||||
# Add this line to disable the specific warning
|
||||
add_compile_options(-Wno-missing-field-initializers)
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
|
||||
## 大模型配置
|
||||
|
||||
如果你已经拥有一个小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
|
||||
如果你已经拥有一个的小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
|
||||
|
||||
👉 [后台操作视频教程(旧版界面)](https://www.bilibili.com/video/BV1jUCUY2EKM/)
|
||||
|
||||
|
||||
@@ -86,8 +86,6 @@ elseif(CONFIG_BOARD_TYPE_ATOMS3R_ECHO_BASE)
|
||||
set(BOARD_TYPE "atoms3r-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE)
|
||||
set(BOARD_TYPE "atoms3r-cam-m12-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOM_ECHOS3R)
|
||||
set(BOARD_TYPE "atom-echos3r")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOMMATRIX_ECHO_BASE)
|
||||
set(BOARD_TYPE "atommatrix-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_XMINI_C3_V3)
|
||||
@@ -106,8 +104,6 @@ elseif(CONFIG_BOARD_TYPE_ESP_HI)
|
||||
set(BOARD_TYPE "esp-hi")
|
||||
elseif(CONFIG_BOARD_TYPE_ECHOEAR)
|
||||
set(BOARD_TYPE "echoear")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_AUDIO_BOARD)
|
||||
set(BOARD_TYPE "waveshare-s3-audio-board")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8)
|
||||
set(BOARD_TYPE "esp32-s3-touch-amoled-1.8")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06)
|
||||
@@ -196,8 +192,6 @@ elseif(CONFIG_BOARD_TYPE_ESP32_CGC_144)
|
||||
set(BOARD_TYPE "esp32-cgc-144")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board)
|
||||
set(BOARD_TYPE "esp-s3-lcd-ev-board")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board_2)
|
||||
set(BOARD_TYPE "esp-s3-lcd-ev-board-2")
|
||||
elseif(CONFIG_BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI)
|
||||
set(BOARD_TYPE "zhengchen-1.54tft-wifi")
|
||||
elseif(CONFIG_BOARD_TYPE_MINSI_K08_DUAL)
|
||||
@@ -214,7 +208,7 @@ elseif(CONFIG_BOARD_TYPE_ELECTRON_BOT)
|
||||
set(BOARD_TYPE "electron-bot")
|
||||
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI_CAM)
|
||||
set(BOARD_TYPE "bread-compact-wifi-s3cam")
|
||||
elseif(CONFIG_BOARD_TYPE_JIUCHUAN)
|
||||
elseif(CONFIG_BOARD_TYPE_JIUCHUAN )
|
||||
set(BOARD_TYPE "jiuchuan-s3")
|
||||
elseif(CONFIG_BOARD_TYPE_LABPLUS_MPYTHON_V3)
|
||||
set(BOARD_TYPE "labplus-mpython-v3")
|
||||
@@ -398,4 +392,4 @@ spiffs_create_partition_assets(
|
||||
MMAP_FILE_SUPPORT_FORMAT ".aaf, ttf, bin"
|
||||
IMPORT_INC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -178,15 +178,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE
|
||||
bool "AtomS3R CAM/M12 + Echo Base"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATOM_ECHOS3R
|
||||
bool "AtomEchoS3R"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATOMMATRIX_ECHO_BASE
|
||||
bool "AtomMatrix + Echo Base"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_ESP32S3_AUDIO_BOARD
|
||||
bool "Waveshare ESP32-S3-Audio-Board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -309,9 +303,6 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_ESP_S3_LCD_EV_Board
|
||||
bool "乐鑫ESP S3 LCD EV Board开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_S3_LCD_EV_Board_2
|
||||
bool "乐鑫ESP S3 LCD EV Board 2开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI
|
||||
bool "征辰科技1.54(WIFI)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -428,27 +419,15 @@ endchoice
|
||||
choice DISPLAY_ESP32S3_KORVO2_V3
|
||||
depends on BOARD_TYPE_ESP32S3_KORVO2_V3
|
||||
prompt "ESP32S3_KORVO2_V3 LCD Type"
|
||||
default ESP32S3_KORVO2_V3_LCD_ST7789
|
||||
default LCD_ST7789
|
||||
help
|
||||
屏幕类型选择
|
||||
config ESP32S3_KORVO2_V3_LCD_ST7789
|
||||
config LCD_ST7789
|
||||
bool "ST7789, 分辨率240*280"
|
||||
config ESP32S3_KORVO2_V3_LCD_ILI9341
|
||||
config LCD_ILI9341
|
||||
bool "ILI9341, 分辨率240*320"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_ESP32S3_AUDIO_BOARD
|
||||
depends on BOARD_TYPE_ESP32S3_AUDIO_BOARD
|
||||
prompt "ESP32S3_AUDIO_BOARD LCD Type"
|
||||
default AUDIO_BOARD_LCD_JD9853
|
||||
help
|
||||
屏幕类型选择
|
||||
config AUDIO_BOARD_LCD_JD9853
|
||||
bool "JD9853, 分辨率320*172"
|
||||
config AUDIO_BOARD_LCD_ST7789
|
||||
bool "ST7789, 分辨率240*320"
|
||||
endchoice
|
||||
|
||||
config USE_WECHAT_MESSAGE_STYLE
|
||||
bool "Enable WeChat Message Style"
|
||||
default n
|
||||
@@ -508,10 +487,7 @@ config USE_AUDIO_PROCESSOR
|
||||
config USE_DEVICE_AEC
|
||||
bool "Enable Device-Side AEC"
|
||||
default n
|
||||
depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE || BOARD_TYPE_LICHUANG_DEV \
|
||||
|| BOARD_TYPE_ESP32S3_KORVO2_V3 || BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 || BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06 \
|
||||
|| BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 \
|
||||
|| BOARD_TYPE_ECHOEAR)
|
||||
depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE || BOARD_TYPE_LICHUANG_DEV || BOARD_TYPE_ESP32S3_KORVO2_V3 || BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 || BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06 || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC)
|
||||
help
|
||||
因为性能不够,不建议和微信聊天界面风格同时开启
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "audio_codec.h"
|
||||
#include "mqtt_protocol.h"
|
||||
#include "websocket_protocol.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "mcp_server.h"
|
||||
|
||||
@@ -13,7 +14,6 @@
|
||||
#include <cJSON.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <font_awesome.h>
|
||||
|
||||
#define TAG "Application"
|
||||
|
||||
@@ -49,7 +49,7 @@ Application::Application() {
|
||||
esp_timer_create_args_t clock_timer_args = {
|
||||
.callback = [](void* arg) {
|
||||
Application* app = (Application*)arg;
|
||||
xEventGroupSetBits(app->event_group_, MAIN_EVENT_CLOCK_TICK);
|
||||
app->OnClockTimer();
|
||||
},
|
||||
.arg = this,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
@@ -87,7 +87,7 @@ void Application::CheckNewVersion(Ota& ota) {
|
||||
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), Lang::Strings::CHECK_NEW_VERSION_FAILED, retry_delay, ota.GetCheckVersionUrl().c_str());
|
||||
Alert(Lang::Strings::ERROR, buffer, "cloud_slash", Lang::Sounds::OGG_EXCLAMATION);
|
||||
Alert(Lang::Strings::ERROR, buffer, "sad", Lang::Sounds::OGG_EXCLAMATION);
|
||||
|
||||
ESP_LOGW(TAG, "Check new version failed, retry in %d seconds (%d/%d)", retry_delay, retry_count, MAX_RETRY);
|
||||
for (int i = 0; i < retry_delay; i++) {
|
||||
@@ -103,12 +103,13 @@ void Application::CheckNewVersion(Ota& ota) {
|
||||
retry_delay = 10; // 重置重试延迟时间
|
||||
|
||||
if (ota.HasNewVersion()) {
|
||||
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "download", Lang::Sounds::OGG_UPGRADE);
|
||||
Alert(Lang::Strings::OTA_UPGRADE, Lang::Strings::UPGRADING, "happy", Lang::Sounds::OGG_UPGRADE);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
|
||||
SetDeviceState(kDeviceStateUpgrading);
|
||||
|
||||
display->SetIcon(FONT_AWESOME_DOWNLOAD);
|
||||
std::string message = std::string(Lang::Strings::NEW_VERSION) + ota.GetFirmwareVersion();
|
||||
display->SetChatMessage("system", message.c_str());
|
||||
|
||||
@@ -129,7 +130,7 @@ void Application::CheckNewVersion(Ota& ota) {
|
||||
ESP_LOGE(TAG, "Firmware upgrade failed, restarting audio service and continuing operation...");
|
||||
audio_service_.Start(); // Restart audio service
|
||||
board.SetPowerSaveMode(true); // Restore power save mode
|
||||
Alert(Lang::Strings::ERROR, Lang::Strings::UPGRADE_FAILED, "circle_xmark", Lang::Sounds::OGG_EXCLAMATION);
|
||||
Alert(Lang::Strings::ERROR, Lang::Strings::UPGRADE_FAILED, "sad", Lang::Sounds::OGG_EXCLAMATION);
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
// Continue to normal operation (don't break, just fall through)
|
||||
} else {
|
||||
@@ -194,7 +195,7 @@ void Application::ShowActivationCode(const std::string& code, const std::string&
|
||||
}};
|
||||
|
||||
// This sentence uses 9KB of SRAM, so we need to wait for it to finish
|
||||
Alert(Lang::Strings::ACTIVATION, message.c_str(), "link", Lang::Sounds::OGG_ACTIVATION);
|
||||
Alert(Lang::Strings::ACTIVATION, message.c_str(), "happy", Lang::Sounds::OGG_ACTIVATION);
|
||||
|
||||
for (const auto& digit : code) {
|
||||
auto it = std::find_if(digit_sounds.begin(), digit_sounds.end(),
|
||||
@@ -206,7 +207,7 @@ void Application::ShowActivationCode(const std::string& code, const std::string&
|
||||
}
|
||||
|
||||
void Application::Alert(const char* status, const char* message, const char* emotion, const std::string_view& sound) {
|
||||
ESP_LOGW(TAG, "Alert [%s] %s: %s", emotion, status, message);
|
||||
ESP_LOGW(TAG, "Alert %s: %s [%s]", status, message, emotion);
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->SetStatus(status);
|
||||
display->SetEmotion(emotion);
|
||||
@@ -332,9 +333,6 @@ void Application::Start() {
|
||||
/* Setup the display */
|
||||
auto display = board.GetDisplay();
|
||||
|
||||
// Print board name/version info
|
||||
display->SetChatMessage("system", SystemInfo::GetUserAgent().c_str());
|
||||
|
||||
/* Setup the audio service */
|
||||
auto codec = board.GetAudioCodec();
|
||||
audio_service_.Initialize(codec);
|
||||
@@ -352,12 +350,6 @@ void Application::Start() {
|
||||
};
|
||||
audio_service_.SetCallbacks(callbacks);
|
||||
|
||||
// Start the main event loop task with priority 3
|
||||
xTaskCreate([](void* arg) {
|
||||
((Application*)arg)->MainEventLoop();
|
||||
vTaskDelete(NULL);
|
||||
}, "main_event_loop", 2048 * 4, this, 3, &main_event_loop_task_handle_);
|
||||
|
||||
/* Start the clock timer to update the status bar */
|
||||
esp_timer_start_periodic(clock_timer_handle_, 1000000);
|
||||
|
||||
@@ -386,10 +378,6 @@ void Application::Start() {
|
||||
protocol_ = std::make_unique<MqttProtocol>();
|
||||
}
|
||||
|
||||
protocol_->OnConnected([this]() {
|
||||
DismissAlert();
|
||||
});
|
||||
|
||||
protocol_->OnNetworkError([this](const std::string& message) {
|
||||
last_error_message_ = message;
|
||||
xEventGroupSetBits(event_group_, MAIN_EVENT_ERROR);
|
||||
@@ -505,8 +493,6 @@ void Application::Start() {
|
||||
});
|
||||
bool protocol_started = protocol_->Start();
|
||||
|
||||
// Print heap stats
|
||||
SystemInfo::PrintHeapStats();
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
|
||||
has_server_time_ = ota.HasServerTime();
|
||||
@@ -517,6 +503,23 @@ void Application::Start() {
|
||||
// Play the success sound to indicate the device is ready
|
||||
audio_service_.PlaySound(Lang::Sounds::OGG_SUCCESS);
|
||||
}
|
||||
|
||||
// Print heap stats
|
||||
SystemInfo::PrintHeapStats();
|
||||
}
|
||||
|
||||
void Application::OnClockTimer() {
|
||||
clock_ticks_++;
|
||||
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->UpdateStatusBar();
|
||||
|
||||
// Print the debug info every 10 seconds
|
||||
if (clock_ticks_ % 10 == 0) {
|
||||
// SystemInfo::PrintTaskCpuUsage(pdMS_TO_TICKS(1000));
|
||||
// SystemInfo::PrintTaskList();
|
||||
SystemInfo::PrintHeapStats();
|
||||
}
|
||||
}
|
||||
|
||||
// Add a async task to MainLoop
|
||||
@@ -532,17 +535,18 @@ void Application::Schedule(std::function<void()> callback) {
|
||||
// If other tasks need to access the websocket or chat state,
|
||||
// they should use Schedule to call this function
|
||||
void Application::MainEventLoop() {
|
||||
// Raise the priority of the main event loop to avoid being interrupted by background tasks (which has priority 2)
|
||||
vTaskPrioritySet(NULL, 3);
|
||||
|
||||
while (true) {
|
||||
auto bits = xEventGroupWaitBits(event_group_, MAIN_EVENT_SCHEDULE |
|
||||
MAIN_EVENT_SEND_AUDIO |
|
||||
MAIN_EVENT_WAKE_WORD_DETECTED |
|
||||
MAIN_EVENT_VAD_CHANGE |
|
||||
MAIN_EVENT_CLOCK_TICK |
|
||||
MAIN_EVENT_ERROR, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
|
||||
if (bits & MAIN_EVENT_ERROR) {
|
||||
SetDeviceState(kDeviceStateIdle);
|
||||
Alert(Lang::Strings::ERROR, last_error_message_.c_str(), "circle_xmark", Lang::Sounds::OGG_EXCLAMATION);
|
||||
Alert(Lang::Strings::ERROR, last_error_message_.c_str(), "sad", Lang::Sounds::OGG_EXCLAMATION);
|
||||
}
|
||||
|
||||
if (bits & MAIN_EVENT_SEND_AUDIO) {
|
||||
@@ -572,19 +576,6 @@ void Application::MainEventLoop() {
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
if (bits & MAIN_EVENT_CLOCK_TICK) {
|
||||
clock_ticks_++;
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
display->UpdateStatusBar();
|
||||
|
||||
// Print the debug info every 10 seconds
|
||||
if (clock_ticks_ % 10 == 0) {
|
||||
// SystemInfo::PrintTaskCpuUsage(pdMS_TO_TICKS(1000));
|
||||
// SystemInfo::PrintTaskList();
|
||||
SystemInfo::PrintHeapStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,20 +734,11 @@ bool Application::CanEnterSleepMode() {
|
||||
}
|
||||
|
||||
void Application::SendMcpMessage(const std::string& payload) {
|
||||
if (protocol_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure you are using main thread to send MCP message
|
||||
if (xTaskGetCurrentTaskHandle() == main_event_loop_task_handle_) {
|
||||
ESP_LOGI(TAG, "Send MCP message in main thread");
|
||||
protocol_->SendMcpMessage(payload);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Send MCP message in sub thread");
|
||||
Schedule([this, payload = std::move(payload)]() {
|
||||
Schedule([this, payload]() {
|
||||
if (protocol_) {
|
||||
protocol_->SendMcpMessage(payload);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Application::SetAecMode(AecMode mode) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "protocol.h"
|
||||
@@ -16,15 +17,12 @@
|
||||
#include "audio_service.h"
|
||||
#include "device_state_event.h"
|
||||
|
||||
|
||||
#define MAIN_EVENT_SCHEDULE (1 << 0)
|
||||
#define MAIN_EVENT_SEND_AUDIO (1 << 1)
|
||||
#define MAIN_EVENT_WAKE_WORD_DETECTED (1 << 2)
|
||||
#define MAIN_EVENT_VAD_CHANGE (1 << 3)
|
||||
#define MAIN_EVENT_ERROR (1 << 4)
|
||||
#define MAIN_EVENT_CHECK_NEW_VERSION_DONE (1 << 5)
|
||||
#define MAIN_EVENT_CLOCK_TICK (1 << 6)
|
||||
|
||||
|
||||
enum AecMode {
|
||||
kAecOff,
|
||||
@@ -82,27 +80,12 @@ private:
|
||||
bool aborted_ = false;
|
||||
int clock_ticks_ = 0;
|
||||
TaskHandle_t check_new_version_task_handle_ = nullptr;
|
||||
TaskHandle_t main_event_loop_task_handle_ = nullptr;
|
||||
|
||||
void OnWakeWordDetected();
|
||||
void CheckNewVersion(Ota& ota);
|
||||
void ShowActivationCode(const std::string& code, const std::string& message);
|
||||
void OnClockTimer();
|
||||
void SetListeningMode(ListeningMode mode);
|
||||
};
|
||||
|
||||
|
||||
class TaskPriorityReset {
|
||||
public:
|
||||
TaskPriorityReset(BaseType_t priority) {
|
||||
original_priority_ = uxTaskPriorityGet(NULL);
|
||||
vTaskPrioritySet(NULL, priority);
|
||||
}
|
||||
~TaskPriorityReset() {
|
||||
vTaskPrioritySet(NULL, original_priority_);
|
||||
}
|
||||
|
||||
private:
|
||||
BaseType_t original_priority_;
|
||||
};
|
||||
|
||||
#endif // _APPLICATION_H_
|
||||
|
||||
@@ -100,18 +100,18 @@ void AudioService::Start() {
|
||||
|
||||
#if CONFIG_USE_AUDIO_PROCESSOR
|
||||
/* Start the audio input task */
|
||||
xTaskCreate([](void* arg) {
|
||||
xTaskCreatePinnedToCore([](void* arg) {
|
||||
AudioService* audio_service = (AudioService*)arg;
|
||||
audio_service->AudioInputTask();
|
||||
vTaskDelete(NULL);
|
||||
}, "audio_input", 2048 * 3, this, 8, &audio_input_task_handle_);
|
||||
}, "audio_input", 2048 * 3, this, 8, &audio_input_task_handle_, 1);
|
||||
|
||||
/* Start the audio output task */
|
||||
xTaskCreate([](void* arg) {
|
||||
AudioService* audio_service = (AudioService*)arg;
|
||||
audio_service->AudioOutputTask();
|
||||
vTaskDelete(NULL);
|
||||
}, "audio_output", 2048 * 2, this, 4, &audio_output_task_handle_);
|
||||
}, "audio_output", 2048 * 2, this, 3, &audio_output_task_handle_);
|
||||
#else
|
||||
/* Start the audio input task */
|
||||
xTaskCreate([](void* arg) {
|
||||
@@ -125,7 +125,7 @@ void AudioService::Start() {
|
||||
AudioService* audio_service = (AudioService*)arg;
|
||||
audio_service->AudioOutputTask();
|
||||
vTaskDelete(NULL);
|
||||
}, "audio_output", 2048, this, 4, &audio_output_task_handle_);
|
||||
}, "audio_output", 2048, this, 3, &audio_output_task_handle_);
|
||||
#endif
|
||||
|
||||
/* Start the opus codec task */
|
||||
@@ -540,12 +540,6 @@ void AudioService::SetCallbacks(AudioServiceCallbacks& callbacks) {
|
||||
}
|
||||
|
||||
void AudioService::PlaySound(const std::string_view& ogg) {
|
||||
if (!codec_->output_enabled()) {
|
||||
esp_timer_stop(audio_power_timer_);
|
||||
esp_timer_start_periodic(audio_power_timer_, AUDIO_POWER_CHECK_INTERVAL_MS * 1000);
|
||||
codec_->EnableOutput(true);
|
||||
}
|
||||
|
||||
const uint8_t* buf = reinterpret_cast<const uint8_t*>(ogg.data());
|
||||
size_t size = ogg.size();
|
||||
size_t offset = 0;
|
||||
|
||||
@@ -64,7 +64,7 @@ BoxAudioCodec::BoxAudioCodec(void* i2c_master_handle, int input_sample_rate, int
|
||||
|
||||
es7210_codec_cfg_t es7210_cfg = {};
|
||||
es7210_cfg.ctrl_if = in_ctrl_if_;
|
||||
es7210_cfg.mic_selected = ES7210_SEL_MIC1 | ES7210_SEL_MIC2 | ES7210_SEL_MIC3 | ES7210_SEL_MIC4;
|
||||
es7210_cfg.mic_selected = ES7120_SEL_MIC1 | ES7120_SEL_MIC2 | ES7120_SEL_MIC3 | ES7120_SEL_MIC4;
|
||||
in_codec_if_ = es7210_codec_new(&es7210_cfg);
|
||||
assert(in_codec_if_ != NULL);
|
||||
|
||||
@@ -184,7 +184,6 @@ void BoxAudioCodec::SetOutputVolume(int volume) {
|
||||
}
|
||||
|
||||
void BoxAudioCodec::EnableInput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == input_enabled_) {
|
||||
return;
|
||||
}
|
||||
@@ -208,7 +207,6 @@ void BoxAudioCodec::EnableInput(bool enable) {
|
||||
}
|
||||
|
||||
void BoxAudioCodec::EnableOutput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == output_enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
#include <esp_codec_dev.h>
|
||||
#include <esp_codec_dev_defaults.h>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
class BoxAudioCodec : public AudioCodec {
|
||||
private:
|
||||
@@ -19,7 +17,6 @@ private:
|
||||
|
||||
esp_codec_dev_handle_t output_dev_ = nullptr;
|
||||
esp_codec_dev_handle_t input_dev_ = nullptr;
|
||||
std::mutex data_if_mutex_;
|
||||
|
||||
void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din);
|
||||
|
||||
|
||||
@@ -155,7 +155,6 @@ void Es8311AudioCodec::SetOutputVolume(int volume) {
|
||||
}
|
||||
|
||||
void Es8311AudioCodec::EnableInput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == input_enabled_) {
|
||||
return;
|
||||
}
|
||||
@@ -164,7 +163,6 @@ void Es8311AudioCodec::EnableInput(bool enable) {
|
||||
}
|
||||
|
||||
void Es8311AudioCodec::EnableOutput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == output_enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_codec_dev.h>
|
||||
#include <esp_codec_dev_defaults.h>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
class Es8311AudioCodec : public AudioCodec {
|
||||
private:
|
||||
@@ -20,7 +18,6 @@ private:
|
||||
esp_codec_dev_handle_t dev_ = nullptr;
|
||||
gpio_num_t pa_pin_ = GPIO_NUM_NC;
|
||||
bool pa_inverted_ = false;
|
||||
std::mutex data_if_mutex_;
|
||||
|
||||
void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din);
|
||||
void UpdateDeviceState();
|
||||
|
||||
@@ -133,7 +133,6 @@ void Es8374AudioCodec::SetOutputVolume(int volume) {
|
||||
}
|
||||
|
||||
void Es8374AudioCodec::EnableInput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == input_enabled_) {
|
||||
return;
|
||||
}
|
||||
@@ -154,7 +153,6 @@ void Es8374AudioCodec::EnableInput(bool enable) {
|
||||
}
|
||||
|
||||
void Es8374AudioCodec::EnableOutput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == output_enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_codec_dev.h>
|
||||
#include <esp_codec_dev_defaults.h>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
class Es8374AudioCodec : public AudioCodec {
|
||||
private:
|
||||
@@ -20,7 +18,6 @@ private:
|
||||
esp_codec_dev_handle_t output_dev_ = nullptr;
|
||||
esp_codec_dev_handle_t input_dev_ = nullptr;
|
||||
gpio_num_t pa_pin_ = GPIO_NUM_NC;
|
||||
std::mutex data_if_mutex_;
|
||||
|
||||
void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din);
|
||||
|
||||
|
||||
@@ -137,7 +137,6 @@ void Es8388AudioCodec::SetOutputVolume(int volume) {
|
||||
}
|
||||
|
||||
void Es8388AudioCodec::EnableInput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == input_enabled_) {
|
||||
return;
|
||||
}
|
||||
@@ -158,7 +157,6 @@ void Es8388AudioCodec::EnableInput(bool enable) {
|
||||
}
|
||||
|
||||
void Es8388AudioCodec::EnableOutput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == output_enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
#include <driver/i2c_master.h>
|
||||
#include <esp_codec_dev.h>
|
||||
#include <esp_codec_dev_defaults.h>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
class Es8388AudioCodec : public AudioCodec {
|
||||
private:
|
||||
@@ -19,7 +17,6 @@ private:
|
||||
esp_codec_dev_handle_t output_dev_ = nullptr;
|
||||
esp_codec_dev_handle_t input_dev_ = nullptr;
|
||||
gpio_num_t pa_pin_ = GPIO_NUM_NC;
|
||||
std::mutex data_if_mutex_;
|
||||
|
||||
void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din);
|
||||
|
||||
|
||||
@@ -140,7 +140,6 @@ void Es8389AudioCodec::SetOutputVolume(int volume) {
|
||||
}
|
||||
|
||||
void Es8389AudioCodec::EnableInput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == input_enabled_) {
|
||||
return;
|
||||
}
|
||||
@@ -161,7 +160,6 @@ void Es8389AudioCodec::EnableInput(bool enable) {
|
||||
}
|
||||
|
||||
void Es8389AudioCodec::EnableOutput(bool enable) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
if (enable == output_enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_codec_dev.h>
|
||||
#include <esp_codec_dev_defaults.h>
|
||||
#include <mutex>
|
||||
|
||||
class Es8389AudioCodec : public AudioCodec {
|
||||
private:
|
||||
@@ -19,7 +18,6 @@ private:
|
||||
esp_codec_dev_handle_t output_dev_ = nullptr;
|
||||
esp_codec_dev_handle_t input_dev_ = nullptr;
|
||||
gpio_num_t pa_pin_ = GPIO_NUM_NC;
|
||||
std::mutex data_if_mutex_;
|
||||
|
||||
void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din);
|
||||
|
||||
|
||||
@@ -279,7 +279,6 @@ NoAudioCodecSimplexPdm::NoAudioCodecSimplexPdm(int input_sample_rate, int output
|
||||
}
|
||||
|
||||
int NoAudioCodec::Write(const int16_t* data, int samples) {
|
||||
std::lock_guard<std::mutex> lock(data_if_mutex_);
|
||||
std::vector<int32_t> buffer(samples);
|
||||
|
||||
// output_volume_: 0-100
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/i2s_pdm.h>
|
||||
#include <mutex>
|
||||
|
||||
class NoAudioCodec : public AudioCodec {
|
||||
protected:
|
||||
std::mutex data_if_mutex_;
|
||||
|
||||
private:
|
||||
virtual int Write(const int16_t* data, int samples) override;
|
||||
virtual int Read(int16_t* dest, int samples) override;
|
||||
|
||||
|
||||
@@ -13,6 +13,11 @@ void NoAudioProcessor::Feed(std::vector<int16_t>&& data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.size() != frame_samples_) {
|
||||
ESP_LOGE(TAG, "Feed data size is not equal to frame size, feed size: %u, frame size: %u", data.size(), frame_samples_);
|
||||
return;
|
||||
}
|
||||
|
||||
if (codec_->input_channels() == 2) {
|
||||
// If input channels is 2, we need to fetch the left channel data
|
||||
auto mono_data = std::vector<int16_t>(data.size() / 2);
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# AtomEchoS3R
|
||||
## 简介
|
||||
|
||||
AtomEchoS3R 是 M5Stack 推出的基于 ESP32-S3-PICO-1-N8R8 的物联网可编程控制器,采用了 ES8311 单声道音频解码器、MEMS 麦克风和 NS4150B 功率放大器的集成方案。
|
||||
|
||||
开发版**不带屏幕、不带额外按键**,需要使用语音唤醒。必要时,需要使用 `idf.py monitor` 查看 log 以确定运行状态。
|
||||
|
||||
## 配置、编译命令
|
||||
|
||||
**配置编译目标为 ESP32S3**
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32s3
|
||||
```
|
||||
|
||||
**打开 menuconfig 并配置**
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
分别配置如下选项:
|
||||
|
||||
- `Xiaozhi Assistant` → `Board Type` → 选择 `AtomEchoS3R`
|
||||
- `Partition Table` → `Custom partition CSV file` → 删除原有内容,输入 `partitions/v1/8m.csv`
|
||||
- `Serial flasher config` → `Flash size` → 选择 `8 MB`
|
||||
- `Component config` → `ESP PSRAM` → `Support for external, SPI-connected RAM` → `SPI RAM config` → 选择 `Octal Mode PSRAM`
|
||||
|
||||
按 `S` 保存,按 `Q` 退出。
|
||||
|
||||
**编译**
|
||||
|
||||
```bash
|
||||
idf.py build
|
||||
```
|
||||
|
||||
**烧录**
|
||||
|
||||
将 AtomEchoS3R 连接到电脑,按住侧面 RESET 按键,直到 RESET 按键下方绿灯闪烁。
|
||||
|
||||
```bash
|
||||
idf.py flash
|
||||
```
|
||||
|
||||
烧录完毕后,按一下 RESET 按钮重启设备。
|
||||
@@ -1,92 +0,0 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "i2c_device.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <wifi_station.h>
|
||||
|
||||
#define TAG "AtomEchoS3R"
|
||||
|
||||
|
||||
class AtomEchoS3rBaseBoard : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Button boot_button_;
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void I2cDetect() {
|
||||
uint8_t address;
|
||||
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
|
||||
for (int i = 0; i < 128; i += 16) {
|
||||
printf("%02x: ", i);
|
||||
for (int j = 0; j < 16; j++) {
|
||||
fflush(stdout);
|
||||
address = i + j;
|
||||
esp_err_t ret = i2c_master_probe(i2c_bus_, address, pdMS_TO_TICKS(200));
|
||||
if (ret == ESP_OK) {
|
||||
printf("%02x ", address);
|
||||
} else if (ret == ESP_ERR_TIMEOUT) {
|
||||
printf("UU ");
|
||||
} else {
|
||||
printf("-- ");
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
public:
|
||||
AtomEchoS3rBaseBoard() : boot_button_(USER_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
I2cDetect();
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static Es8311AudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
I2C_NUM_0,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
AUDIO_CODEC_GPIO_PA,
|
||||
AUDIO_CODEC_ES8311_ADDR,
|
||||
false);
|
||||
return &audio_codec;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(AtomEchoS3rBaseBoard);
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
// AtomEchoS3R Board configuration
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_11
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_3
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_17
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_48
|
||||
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_45
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_0
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_GPIO_PA GPIO_NUM_18
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_NC
|
||||
#define USER_BUTTON_GPIO GPIO_NUM_41
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "atom-echos3r",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v1/8m.csv\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -111,7 +111,7 @@ private:
|
||||
InitializeButtons();
|
||||
GetBacklight()->SetBrightness(100);
|
||||
display_->SetStatus(Lang::Strings::ERROR);
|
||||
display_->SetEmotion("triangle_exclamation");
|
||||
display_->SetEmotion("sad");
|
||||
display_->SetChatMessage("system", "Echo Base\nnot connected");
|
||||
|
||||
while (1) {
|
||||
|
||||
@@ -177,7 +177,7 @@ private:
|
||||
InitializeButtons();
|
||||
GetBacklight()->SetBrightness(100);
|
||||
display_->SetStatus(Lang::Strings::ERROR);
|
||||
display_->SetEmotion("triangle_exclamation");
|
||||
display_->SetEmotion("sad");
|
||||
display_->SetChatMessage("system", "Echo Base\nnot connected");
|
||||
|
||||
while (1) {
|
||||
|
||||
@@ -3,42 +3,32 @@
|
||||
AdcBatteryMonitor::AdcBatteryMonitor(adc_unit_t adc_unit, adc_channel_t adc_channel, float upper_resistor, float lower_resistor, gpio_num_t charging_pin)
|
||||
: charging_pin_(charging_pin) {
|
||||
|
||||
// Initialize charging pin (only if it's not NC)
|
||||
if (charging_pin_ != GPIO_NUM_NC) {
|
||||
gpio_config_t gpio_cfg = {
|
||||
.pin_bit_mask = 1ULL << charging_pin,
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
ESP_ERROR_CHECK(gpio_config(&gpio_cfg));
|
||||
}
|
||||
// Initialize charging pin
|
||||
gpio_config_t gpio_cfg = {
|
||||
.pin_bit_mask = 1ULL << charging_pin,
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
ESP_ERROR_CHECK(gpio_config(&gpio_cfg));
|
||||
|
||||
// Initialize ADC battery estimation
|
||||
adc_battery_estimation_t adc_cfg = {
|
||||
.internal = {
|
||||
.adc_unit = adc_unit,
|
||||
.adc_bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.adc_bitwidth = ADC_BITWIDTH_12,
|
||||
.adc_atten = ADC_ATTEN_DB_12,
|
||||
},
|
||||
.adc_channel = adc_channel,
|
||||
.upper_resistor = upper_resistor,
|
||||
.lower_resistor = lower_resistor
|
||||
};
|
||||
|
||||
// 在ADC配置部分进行条件设置
|
||||
if (charging_pin_ != GPIO_NUM_NC) {
|
||||
adc_cfg.charging_detect_cb = [](void *user_data) -> bool {
|
||||
AdcBatteryMonitor *self = (AdcBatteryMonitor *)user_data;
|
||||
return gpio_get_level(self->charging_pin_) == 1;
|
||||
};
|
||||
adc_cfg.charging_detect_user_data = this;
|
||||
} else {
|
||||
// 不设置回调,让adc_battery_estimation库使用软件估算
|
||||
adc_cfg.charging_detect_cb = nullptr;
|
||||
adc_cfg.charging_detect_user_data = nullptr;
|
||||
}
|
||||
adc_cfg.charging_detect_cb = [](void *user_data) -> bool {
|
||||
AdcBatteryMonitor *self = (AdcBatteryMonitor *)user_data;
|
||||
return gpio_get_level(self->charging_pin_) == 1;
|
||||
};
|
||||
adc_cfg.charging_detect_user_data = this;
|
||||
adc_battery_estimation_handle_ = adc_battery_estimation_create(&adc_cfg);
|
||||
|
||||
// Initialize timer
|
||||
@@ -58,29 +48,12 @@ AdcBatteryMonitor::~AdcBatteryMonitor() {
|
||||
if (adc_battery_estimation_handle_) {
|
||||
ESP_ERROR_CHECK(adc_battery_estimation_destroy(adc_battery_estimation_handle_));
|
||||
}
|
||||
|
||||
if (timer_handle_) {
|
||||
esp_timer_stop(timer_handle_);
|
||||
esp_timer_delete(timer_handle_);
|
||||
}
|
||||
}
|
||||
|
||||
bool AdcBatteryMonitor::IsCharging() {
|
||||
// 优先使用adc_battery_estimation库的功能
|
||||
if (adc_battery_estimation_handle_ != nullptr) {
|
||||
bool is_charging = false;
|
||||
esp_err_t err = adc_battery_estimation_get_charging_state(adc_battery_estimation_handle_, &is_charging);
|
||||
if (err == ESP_OK) {
|
||||
return is_charging;
|
||||
}
|
||||
}
|
||||
|
||||
// 回退到GPIO读取或返回默认值
|
||||
if (charging_pin_ != GPIO_NUM_NC) {
|
||||
return gpio_get_level(charging_pin_) == 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
bool is_charging = false;
|
||||
ESP_ERROR_CHECK(adc_battery_estimation_get_charging_state(adc_battery_estimation_handle_, &is_charging));
|
||||
return is_charging;
|
||||
}
|
||||
|
||||
bool AdcBatteryMonitor::IsDischarging() {
|
||||
@@ -88,17 +61,9 @@ bool AdcBatteryMonitor::IsDischarging() {
|
||||
}
|
||||
|
||||
uint8_t AdcBatteryMonitor::GetBatteryLevel() {
|
||||
// 如果句柄无效,返回默认值
|
||||
if (adc_battery_estimation_handle_ == nullptr) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
float capacity = 0;
|
||||
esp_err_t err = adc_battery_estimation_get_capacity(adc_battery_estimation_handle_, &capacity);
|
||||
if (err != ESP_OK) {
|
||||
return 100; // 出错时返回默认值
|
||||
}
|
||||
return (uint8_t)capacity;
|
||||
ESP_ERROR_CHECK(adc_battery_estimation_get_capacity(adc_battery_estimation_handle_, &capacity));
|
||||
return capacity;
|
||||
}
|
||||
|
||||
void AdcBatteryMonitor::OnChargingStatusChanged(std::function<void(bool)> callback) {
|
||||
|
||||
@@ -28,7 +28,7 @@ Esp32Camera::Esp32Camera(const camera_config_t& config) {
|
||||
memset(&preview_image_, 0, sizeof(preview_image_));
|
||||
preview_image_.header.magic = LV_IMAGE_HEADER_MAGIC;
|
||||
preview_image_.header.cf = LV_COLOR_FORMAT_RGB565;
|
||||
preview_image_.header.flags = 0;
|
||||
preview_image_.header.flags = LV_IMAGE_FLAGS_ALLOCATED | LV_IMAGE_FLAGS_MODIFIABLE;
|
||||
|
||||
switch (config.frame_size) {
|
||||
case FRAMESIZE_SVGA:
|
||||
@@ -89,7 +89,6 @@ bool Esp32Camera::Capture() {
|
||||
encoder_thread_.join();
|
||||
}
|
||||
|
||||
auto start_time = esp_timer_get_time();
|
||||
int frames_to_get = 2;
|
||||
// Try to get a stable frame
|
||||
for (int i = 0; i < frames_to_get; i++) {
|
||||
@@ -102,8 +101,6 @@ bool Esp32Camera::Capture() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
auto end_time = esp_timer_get_time();
|
||||
ESP_LOGI(TAG, "Camera captured %d frames in %d ms", frames_to_get, int((end_time - start_time) / 1000));
|
||||
|
||||
// 如果预览图片 buffer 为空,则跳过预览
|
||||
// 但仍返回 true,因为此时图像可以上传至服务器
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
#include "application.h"
|
||||
#include "display.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_timer.h>
|
||||
#include <font_awesome.h>
|
||||
#include <opus_encoder.h>
|
||||
|
||||
static const char *TAG = "Ml307Board";
|
||||
@@ -50,9 +50,9 @@ void Ml307Board::StartNetwork() {
|
||||
while (true) {
|
||||
auto result = modem_->WaitForNetworkReady();
|
||||
if (result == NetworkStatus::ErrorInsertPin) {
|
||||
application.Alert(Lang::Strings::ERROR, Lang::Strings::PIN_ERROR, "triangle_exclamation", Lang::Sounds::OGG_ERR_PIN);
|
||||
application.Alert(Lang::Strings::ERROR, Lang::Strings::PIN_ERROR, "sad", Lang::Sounds::OGG_ERR_PIN);
|
||||
} else if (result == NetworkStatus::ErrorRegistrationDenied) {
|
||||
application.Alert(Lang::Strings::ERROR, Lang::Strings::REG_ERROR, "triangle_exclamation", Lang::Sounds::OGG_ERR_REG);
|
||||
application.Alert(Lang::Strings::ERROR, Lang::Strings::REG_ERROR, "sad", Lang::Sounds::OGG_ERR_REG);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -80,13 +80,13 @@ const char* Ml307Board::GetNetworkStateIcon() {
|
||||
if (csq == -1) {
|
||||
return FONT_AWESOME_SIGNAL_OFF;
|
||||
} else if (csq >= 0 && csq <= 14) {
|
||||
return FONT_AWESOME_SIGNAL_WEAK;
|
||||
return FONT_AWESOME_SIGNAL_1;
|
||||
} else if (csq >= 15 && csq <= 19) {
|
||||
return FONT_AWESOME_SIGNAL_FAIR;
|
||||
return FONT_AWESOME_SIGNAL_2;
|
||||
} else if (csq >= 20 && csq <= 24) {
|
||||
return FONT_AWESOME_SIGNAL_GOOD;
|
||||
return FONT_AWESOME_SIGNAL_3;
|
||||
} else if (csq >= 25 && csq <= 31) {
|
||||
return FONT_AWESOME_SIGNAL_STRONG;
|
||||
return FONT_AWESOME_SIGNAL_4;
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "Invalid CSQ: %d", csq);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "display.h"
|
||||
#include "application.h"
|
||||
#include "system_info.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "settings.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
@@ -11,7 +12,6 @@
|
||||
#include <esp_network.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <font_awesome.h>
|
||||
#include <wifi_station.h>
|
||||
#include <wifi_configuration_ap.h>
|
||||
#include <ssid_manager.h>
|
||||
@@ -49,7 +49,7 @@ void WifiBoard::EnterWifiConfigMode() {
|
||||
hint += "\n\n";
|
||||
|
||||
// 播报配置 WiFi 的提示
|
||||
application.Alert(Lang::Strings::WIFI_CONFIG_MODE, hint.c_str(), "gear", Lang::Sounds::OGG_WIFICONFIG);
|
||||
application.Alert(Lang::Strings::WIFI_CONFIG_MODE, hint.c_str(), "", Lang::Sounds::OGG_WIFICONFIG);
|
||||
|
||||
#if CONFIG_USE_ACOUSTIC_WIFI_PROVISIONING
|
||||
auto display = Board::GetInstance().GetDisplay();
|
||||
@@ -124,7 +124,7 @@ const char* WifiBoard::GetNetworkStateIcon() {
|
||||
}
|
||||
auto& wifi_station = WifiStation::GetInstance();
|
||||
if (!wifi_station.IsConnected()) {
|
||||
return FONT_AWESOME_WIFI_SLASH;
|
||||
return FONT_AWESOME_WIFI_OFF;
|
||||
}
|
||||
int8_t rssi = wifi_station.GetRssi();
|
||||
if (rssi >= -60) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_ili9341.h"
|
||||
#include "led_control.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
@@ -519,13 +519,12 @@ private:
|
||||
|
||||
void InitializeSpi()
|
||||
{
|
||||
spi_bus_config_t bus_config = TAIJIPI_ST77916_PANEL_BUS_QSPI_CONFIG(QSPI_PIN_NUM_LCD_PCLK,
|
||||
QSPI_PIN_NUM_LCD_DATA0,
|
||||
QSPI_PIN_NUM_LCD_DATA1,
|
||||
QSPI_PIN_NUM_LCD_DATA2,
|
||||
QSPI_PIN_NUM_LCD_DATA3,
|
||||
QSPI_LCD_H_RES * 80 * sizeof(uint16_t));
|
||||
// bus_config.isr_cpu_id = ESP_INTR_CPU_AFFINITY_1;
|
||||
const spi_bus_config_t bus_config = TAIJIPI_ST77916_PANEL_BUS_QSPI_CONFIG(QSPI_PIN_NUM_LCD_PCLK,
|
||||
QSPI_PIN_NUM_LCD_DATA0,
|
||||
QSPI_PIN_NUM_LCD_DATA1,
|
||||
QSPI_PIN_NUM_LCD_DATA2,
|
||||
QSPI_PIN_NUM_LCD_DATA3,
|
||||
QSPI_LCD_H_RES * 80 * sizeof(uint16_t));
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(QSPI_LCD_HOST, &bus_config, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
@@ -563,7 +562,11 @@ private:
|
||||
|
||||
#if USE_LVGL_DEFAULT
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY, {
|
||||
.text_font = &font_puhui_20_4,
|
||||
.icon_font = &font_awesome_20_4,
|
||||
.emoji_font = font_emoji_64_init(),
|
||||
});
|
||||
#else
|
||||
display_ = new anim::EmoteDisplay(panel, panel_io);
|
||||
#endif
|
||||
|
||||
@@ -111,8 +111,8 @@ static void InitializeGraphics(esp_lcd_panel_handle_t panel, gfx_handle_t* engin
|
||||
};
|
||||
|
||||
gfx_cfg.task.task_stack_caps = MALLOC_CAP_DEFAULT;
|
||||
gfx_cfg.task.task_affinity = 1;
|
||||
gfx_cfg.task.task_priority = 1;
|
||||
gfx_cfg.task.task_affinity = 0;
|
||||
gfx_cfg.task.task_priority = 5;
|
||||
gfx_cfg.task.task_stack = 20 * 1024;
|
||||
|
||||
*engine_handle = gfx_emote_init(&gfx_cfg);
|
||||
@@ -303,7 +303,6 @@ bool EmoteEngine::OnFlushIoReady(esp_lcd_panel_io_handle_t panel_io,
|
||||
esp_lcd_panel_io_event_data_t* edata,
|
||||
void* user_ctx)
|
||||
{
|
||||
gfx_emote_flush_ready(user_ctx, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -314,6 +313,7 @@ void EmoteEngine::OnFlush(gfx_handle_t handle, int x_start, int y_start,
|
||||
if (panel) {
|
||||
esp_lcd_panel_draw_bitmap(panel, x_start, y_start, x_end, y_end, color_data);
|
||||
}
|
||||
gfx_emote_flush_ready(handle, true);
|
||||
}
|
||||
|
||||
// EmoteDisplay implementation
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "electron_emoji_display.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <font_awesome.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#define TAG "ElectronEmojiDisplay"
|
||||
|
||||
@@ -141,7 +141,7 @@ void ElectronEmojiDisplay::SetChatMessage(const char* role, const char* content)
|
||||
}
|
||||
|
||||
lv_label_set_text(chat_message_label_, content);
|
||||
lv_obj_remove_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
ESP_LOGI(TAG, "设置聊天消息 [%s]: %s", role, content);
|
||||
}
|
||||
@@ -163,7 +163,7 @@ void ElectronEmojiDisplay::SetIcon(const char* icon) {
|
||||
}
|
||||
|
||||
lv_label_set_text(chat_message_label_, icon_message.c_str());
|
||||
lv_obj_remove_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
ESP_LOGI(TAG, "设置图标: %s", icon);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_ili9341.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "box_audio_codec_lite.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_ili9341.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_ili9341.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "adc_pdm_audio_codec.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/i2c.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/i2s_tdm.h>
|
||||
@@ -12,7 +11,6 @@
|
||||
#include "hal/rtc_io_hal.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "settings.h"
|
||||
#include "config.h"
|
||||
|
||||
static const char TAG[] = "AdcPdmAudioCodec";
|
||||
|
||||
@@ -73,7 +71,7 @@ AdcPdmAudioCodec::AdcPdmAudioCodec(int input_sample_rate, int output_sample_rate
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle_, NULL));
|
||||
|
||||
i2s_pdm_tx_config_t pdm_cfg_default = BSP_I2S_DUPLEX_MONO_CFG((uint32_t)output_sample_rate, pdm_speak_p);
|
||||
pdm_cfg_default.clk_cfg.up_sample_fs = AUDIO_PDM_UPSAMPLE_FS;
|
||||
pdm_cfg_default.clk_cfg.up_sample_fs = output_sample_rate / 100;
|
||||
pdm_cfg_default.slot_cfg.sd_scale = I2S_PDM_SIG_SCALING_MUL_4;
|
||||
pdm_cfg_default.slot_cfg.hp_scale = I2S_PDM_SIG_SCALING_MUL_4;
|
||||
pdm_cfg_default.slot_cfg.lp_scale = I2S_PDM_SIG_SCALING_MUL_4;
|
||||
@@ -114,27 +112,10 @@ AdcPdmAudioCodec::AdcPdmAudioCodec(int input_sample_rate, int output_sample_rate
|
||||
esp_rom_gpio_connect_out_signal(pdm_speak_n, I2SO_SD_OUT_IDX, 1, 0); //反转输出 SD OUT 信号
|
||||
gpio_set_drive_capability(pdm_speak_n, GPIO_DRIVE_CAP_0);
|
||||
}
|
||||
|
||||
// 初始化输出定时器
|
||||
esp_timer_create_args_t output_timer_args = {
|
||||
.callback = &AdcPdmAudioCodec::OutputTimerCallback,
|
||||
.arg = this,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "output_timer"
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_timer_create(&output_timer_args, &output_timer_));
|
||||
|
||||
ESP_LOGI(TAG, "AdcPdmAudioCodec initialized");
|
||||
}
|
||||
|
||||
AdcPdmAudioCodec::~AdcPdmAudioCodec() {
|
||||
// 删除定时器
|
||||
if (output_timer_) {
|
||||
esp_timer_stop(output_timer_);
|
||||
esp_timer_delete(output_timer_);
|
||||
output_timer_ = nullptr;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_codec_dev_close(output_dev_));
|
||||
esp_codec_dev_delete(output_dev_);
|
||||
ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
|
||||
@@ -160,7 +141,8 @@ void AdcPdmAudioCodec::EnableInput(bool enable) {
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs));
|
||||
} else {
|
||||
ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
|
||||
// ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
|
||||
return;
|
||||
}
|
||||
AudioCodec::EnableInput(enable);
|
||||
}
|
||||
@@ -180,27 +162,11 @@ void AdcPdmAudioCodec::EnableOutput(bool enable) {
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_codec_dev_open(output_dev_, &fs));
|
||||
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(output_dev_, output_volume_));
|
||||
|
||||
// 强制按板卡配置重配PDM TX时钟,覆盖第三方库在set_fmt中的默认up_sample_fs
|
||||
// 若通道已启用,先禁用再重配,最后再启用
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(i2s_channel_disable(tx_handle_));
|
||||
i2s_pdm_tx_clk_config_t clk_cfg = I2S_PDM_TX_CLK_DEFAULT_CONFIG((uint32_t)output_sample_rate_);
|
||||
clk_cfg.up_sample_fs = AUDIO_PDM_UPSAMPLE_FS;
|
||||
ESP_ERROR_CHECK(i2s_channel_reconfig_pdm_tx_clock(tx_handle_, &clk_cfg));
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
|
||||
if(pa_ctrl_pin_ != GPIO_NUM_NC){
|
||||
gpio_set_level(pa_ctrl_pin_, 1);
|
||||
}
|
||||
// 启用输出时启动定时器
|
||||
if (output_timer_) {
|
||||
esp_timer_start_once(output_timer_, TIMER_TIMEOUT_US);
|
||||
}
|
||||
|
||||
} else {
|
||||
// 禁用输出时停止定时器
|
||||
if (output_timer_) {
|
||||
esp_timer_stop(output_timer_);
|
||||
}
|
||||
if(pa_ctrl_pin_ != GPIO_NUM_NC){
|
||||
gpio_set_level(pa_ctrl_pin_, 0);
|
||||
}
|
||||
@@ -218,11 +184,6 @@ int AdcPdmAudioCodec::Read(int16_t* dest, int samples) {
|
||||
int AdcPdmAudioCodec::Write(const int16_t* data, int samples) {
|
||||
if (output_enabled_) {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_write(output_dev_, (void*)data, samples * sizeof(int16_t)));
|
||||
// 重置输出定时器
|
||||
if (output_timer_) {
|
||||
esp_timer_stop(output_timer_);
|
||||
esp_timer_start_once(output_timer_, TIMER_TIMEOUT_US);
|
||||
}
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
@@ -235,15 +196,9 @@ void AdcPdmAudioCodec::Start() {
|
||||
output_volume_ = 10;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
|
||||
|
||||
EnableInput(true);
|
||||
EnableOutput(true);
|
||||
ESP_LOGI(TAG, "Audio codec started");
|
||||
}
|
||||
|
||||
// 定时器回调函数实现
|
||||
void AdcPdmAudioCodec::OutputTimerCallback(void* arg) {
|
||||
AdcPdmAudioCodec* codec = static_cast<AdcPdmAudioCodec*>(arg);
|
||||
if (codec && codec->output_enabled_) {
|
||||
codec->EnableOutput(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <esp_codec_dev.h>
|
||||
#include <esp_codec_dev_defaults.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
class AdcPdmAudioCodec : public AudioCodec {
|
||||
private:
|
||||
@@ -13,13 +12,6 @@ private:
|
||||
esp_codec_dev_handle_t input_dev_ = nullptr;
|
||||
gpio_num_t pa_ctrl_pin_ = GPIO_NUM_NC;
|
||||
|
||||
// 定时器相关成员变量
|
||||
esp_timer_handle_t output_timer_ = nullptr;
|
||||
static constexpr uint64_t TIMER_TIMEOUT_US = 120000; // 120ms = 120000us
|
||||
|
||||
// 定时器回调函数
|
||||
static void OutputTimerCallback(void* arg);
|
||||
|
||||
virtual int Read(int16_t* dest, int samples) override;
|
||||
virtual int Write(const int16_t* data, int samples) override;
|
||||
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
// 配置PDM上采样fs参数(取值范围<=480)。部分设备在441时表现更稳定
|
||||
#define AUDIO_PDM_UPSAMPLE_FS 441
|
||||
|
||||
#define AUDIO_ADC_MIC_CHANNEL 2
|
||||
#define AUDIO_PDM_SPEAK_P_GPIO GPIO_NUM_6
|
||||
#define AUDIO_PDM_SPEAK_N_GPIO GPIO_NUM_7
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=2048",
|
||||
"CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y",
|
||||
"CONFIG_NEWLIB_NANO_FORMAT=y",
|
||||
"CONFIG_MMAP_FILE_NAME_LENGTH=25",
|
||||
"CONFIG_ESP_CONSOLE_NONE=y",
|
||||
"CONFIG_USE_ESP_WAKE_WORD=y",
|
||||
"CONFIG_COMPILER_OPTIMIZATION_SIZE=y"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <esp_log.h>
|
||||
#include "mmap_generate_emoji.h"
|
||||
#include "emoji_display.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
@@ -48,8 +47,6 @@ EmojiPlayer::EmojiPlayer(esp_lcd_panel_handle_t panel, esp_lcd_panel_io_handle_t
|
||||
.task = ANIM_PLAYER_INIT_CONFIG()
|
||||
};
|
||||
|
||||
player_cfg.task.task_priority = 1;
|
||||
player_cfg.task.task_stack = 4096;
|
||||
player_handle_ = anim_player_init(&player_cfg);
|
||||
|
||||
const esp_lcd_panel_io_callbacks_t cbs = {
|
||||
@@ -149,9 +146,9 @@ void EmojiWidget::SetEmotion(const char* emotion)
|
||||
void EmojiWidget::SetStatus(const char* status)
|
||||
{
|
||||
if (player_) {
|
||||
if (strcmp(status, Lang::Strings::LISTENING) == 0) {
|
||||
if (strcmp(status, "聆听中...") == 0) {
|
||||
player_->StartPlayer(MMAP_EMOJI_ASKING_AAF, true, 15);
|
||||
} else if (strcmp(status, Lang::Strings::STANDBY) == 0) {
|
||||
} else if (strcmp(status, "待命") == 0) {
|
||||
player_->StartPlayer(MMAP_EMOJI_WAKE_AAF, true, 15);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,6 @@ public:
|
||||
|
||||
virtual void SetEmotion(const char* emotion) override;
|
||||
virtual void SetStatus(const char* status) override;
|
||||
virtual void SetChatMessage(const char* role, const char* content) override {}
|
||||
|
||||
anim::EmojiPlayer* GetPlayer()
|
||||
{
|
||||
return player_.get();
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "servo_dog_ctrl.h"
|
||||
#include "led_strip.h"
|
||||
#include "driver/rmt_tx.h"
|
||||
#include "device_state_event.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
@@ -285,14 +284,13 @@ private:
|
||||
ESP_LOGI(TAG, "Create emoji widget, panel: %p, panel_io: %p", panel, panel_io);
|
||||
display_ = new anim::EmojiWidget(panel, panel_io);
|
||||
|
||||
#if CONFIG_ESP_CONSOLE_NONE
|
||||
servo_dog_ctrl_config_t config = {
|
||||
.fl_gpio_num = FL_GPIO_NUM,
|
||||
.fr_gpio_num = FR_GPIO_NUM,
|
||||
.bl_gpio_num = BL_GPIO_NUM,
|
||||
.br_gpio_num = BR_GPIO_NUM,
|
||||
};
|
||||
|
||||
#if CONFIG_ESP_CONSOLE_NONE
|
||||
servo_dog_ctrl_init(&config);
|
||||
#endif
|
||||
}
|
||||
@@ -380,7 +378,7 @@ private:
|
||||
int r = properties["r"].value<int>();
|
||||
int g = properties["g"].value<int>();
|
||||
int b = properties["b"].value<int>();
|
||||
|
||||
|
||||
led_on_ = true;
|
||||
SetLedColor(r, g, b);
|
||||
return true;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
请确认自己的开发板硬件版本,如果硬件版本,在配置中进行ev_board type进行选择
|
||||
1.4与1.5只有io进行变更
|
||||
可以查看官方文档,确认具体细节https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html
|
||||
具体调整为:
|
||||
I2C_SCL IO18 -> IO48
|
||||
I2C_SDA IO8 -> IO47
|
||||
LCD_DATA6 IO47 -> IO8
|
||||
LCD_DATA7 IO48 -> IO18
|
||||
|
||||
本版本只支持了800x480的屏幕
|
||||
@@ -1,42 +0,0 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_7
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_16
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_6
|
||||
|
||||
#define BSP_POWER_AMP_IO (IO_EXPANDER_PIN_NUM_0)
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
|
||||
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_47
|
||||
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_48
|
||||
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR 0x82
|
||||
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_4
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
|
||||
#define DISPLAY_WIDTH 800
|
||||
#define DISPLAY_HEIGHT 480
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_SWAP_XY false
|
||||
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_19
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp-s3-lcd-ev-board-2",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "led/single_led.h"
|
||||
#include "pin_config.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <wifi_station.h>
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include "esp_lcd_gc9503.h"
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_panel_io_additions.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <lvgl.h>
|
||||
#include <esp_lcd_touch_gt1151.h>
|
||||
#include <esp_io_expander_tca9554.h>
|
||||
|
||||
#define TAG "ESP_S3_LCD_EV_Board_2"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_30_4);
|
||||
LV_FONT_DECLARE(font_awesome_30_4);
|
||||
|
||||
class ESP_S3_LCD_EV_Board_2 : public WifiBoard {
|
||||
private:
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
Button boot_button_;
|
||||
LcdDisplay* display_;
|
||||
//add support ev board lcd
|
||||
esp_io_expander_handle_t expander = NULL;
|
||||
|
||||
void InitializeRGB_GC9503V_Display() {
|
||||
ESP_LOGI(TAG, "Init GC9503V");
|
||||
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
|
||||
// add support ev board lcd
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = BIT64(GC9503V_PIN_NUM_VSYNC),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
};
|
||||
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_level(GC9503V_PIN_NUM_VSYNC, 1);
|
||||
|
||||
ESP_LOGI(TAG, "Install 3-wire SPI panel IO");
|
||||
spi_line_config_t line_config = {
|
||||
.cs_io_type = IO_TYPE_EXPANDER,
|
||||
.cs_expander_pin = GC9503V_LCD_IO_SPI_CS_1,
|
||||
.scl_io_type = IO_TYPE_EXPANDER,
|
||||
.scl_expander_pin = GC9503V_LCD_IO_SPI_SCL_1,
|
||||
.sda_io_type = IO_TYPE_EXPANDER,
|
||||
.sda_expander_pin = GC9503V_LCD_IO_SPI_SDO_1,
|
||||
.io_expander = expander,
|
||||
};
|
||||
|
||||
esp_lcd_panel_io_3wire_spi_config_t io_config = GC9503_PANEL_IO_3WIRE_SPI_CONFIG(line_config, 0);
|
||||
int espok = esp_lcd_new_panel_io_3wire_spi(&io_config, &panel_io);
|
||||
ESP_LOGI(TAG, "Install 3-wire SPI panel IO:%d",espok);
|
||||
|
||||
|
||||
ESP_LOGI(TAG, "Install RGB LCD panel driver");
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_rgb_panel_config_t rgb_config = {
|
||||
.clk_src = LCD_CLK_SRC_PLL160M,
|
||||
//add support ev board
|
||||
.timings = GC9503_800_480_PANEL_60HZ_RGB_TIMING(),
|
||||
.data_width = 16, // RGB565 in parallel mode, thus 16bit in width
|
||||
.bits_per_pixel = 16,
|
||||
.num_fbs = GC9503V_LCD_RGB_BUFFER_NUMS,
|
||||
.bounce_buffer_size_px = GC9503V_LCD_H_RES * GC9503V_LCD_RGB_BOUNCE_BUFFER_HEIGHT,
|
||||
.dma_burst_size = 64,
|
||||
.hsync_gpio_num = GC9503V_PIN_NUM_HSYNC,
|
||||
.vsync_gpio_num = GC9503V_PIN_NUM_VSYNC,
|
||||
.de_gpio_num = GC9503V_PIN_NUM_DE,
|
||||
.pclk_gpio_num = GC9503V_PIN_NUM_PCLK,
|
||||
.disp_gpio_num = GC9503V_PIN_NUM_DISP_EN,
|
||||
.data_gpio_nums = {
|
||||
GC9503V_PIN_NUM_DATA0,
|
||||
GC9503V_PIN_NUM_DATA1,
|
||||
GC9503V_PIN_NUM_DATA2,
|
||||
GC9503V_PIN_NUM_DATA3,
|
||||
GC9503V_PIN_NUM_DATA4,
|
||||
GC9503V_PIN_NUM_DATA5,
|
||||
GC9503V_PIN_NUM_DATA6,
|
||||
GC9503V_PIN_NUM_DATA7,
|
||||
GC9503V_PIN_NUM_DATA8,
|
||||
GC9503V_PIN_NUM_DATA9,
|
||||
GC9503V_PIN_NUM_DATA10,
|
||||
GC9503V_PIN_NUM_DATA11,
|
||||
GC9503V_PIN_NUM_DATA12,
|
||||
GC9503V_PIN_NUM_DATA13,
|
||||
GC9503V_PIN_NUM_DATA14,
|
||||
GC9503V_PIN_NUM_DATA15,
|
||||
},
|
||||
.flags= {
|
||||
.fb_in_psram = true, // allocate frame buffer in PSRAM
|
||||
}
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "Initialize RGB LCD panel");
|
||||
|
||||
gc9503_vendor_config_t vendor_config = {
|
||||
.rgb_config = &rgb_config,
|
||||
.flags = {
|
||||
.mirror_by_cmd = 0,
|
||||
.auto_del_panel_io = 1,
|
||||
},
|
||||
};
|
||||
const esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = -1,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
// .bits_per_pixel = 16,
|
||||
//add surpport ev board
|
||||
.bits_per_pixel = 18,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
(esp_lcd_new_panel_gc9503(panel_io, &panel_config, &panel_handle));
|
||||
(esp_lcd_panel_reset(panel_handle));
|
||||
(esp_lcd_panel_init(panel_handle));
|
||||
|
||||
display_ = new RgbLcdDisplay(panel_io, panel_handle,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X,
|
||||
DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_30_4,
|
||||
.icon_font = &font_awesome_30_4,
|
||||
.emoji_font = font_emoji_64_init(),
|
||||
});
|
||||
}
|
||||
void InitializeCodecI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = I2C_NUM_0,
|
||||
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
|
||||
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.intr_priority = 0,
|
||||
.trans_queue_depth = 0,
|
||||
.flags = {
|
||||
.enable_internal_pullup = 1,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
|
||||
//add support ev board lcd amp
|
||||
//初始化扩展io口
|
||||
esp_io_expander_new_i2c_tca9554(i2c_bus_, 0x20, &expander);
|
||||
/* Setup power amplifier pin, set default to enable */
|
||||
esp_io_expander_set_dir(expander, BSP_POWER_AMP_IO, IO_EXPANDER_OUTPUT);
|
||||
esp_io_expander_set_level(expander, BSP_POWER_AMP_IO, true);
|
||||
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
});
|
||||
boot_button_.OnPressDown([this]() {
|
||||
Application::GetInstance().StartListening();
|
||||
});
|
||||
boot_button_.OnPressUp([this]() {
|
||||
Application::GetInstance().StopListening();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeTouch() {
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_WIDTH,
|
||||
.y_max = DISPLAY_HEIGHT,
|
||||
.rst_gpio_num = GPIO_NUM_NC,
|
||||
.int_gpio_num = GPIO_NUM_NC,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 0,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 0,
|
||||
},
|
||||
};
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT1151_CONFIG();
|
||||
tp_io_config.scl_speed_hz = 400 * 1000;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus_, &tp_io_config, &tp_io_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt1151(tp_io_handle, &tp_cfg, &tp));
|
||||
|
||||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||
.disp = lv_display_get_default(),
|
||||
.handle = tp,
|
||||
};
|
||||
lvgl_port_add_touch(&touch_cfg);
|
||||
}
|
||||
|
||||
public:
|
||||
ESP_S3_LCD_EV_Board_2() : boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeCodecI2c();
|
||||
InitializeButtons();
|
||||
InitializeRGB_GC9503V_Display();
|
||||
InitializeTouch();
|
||||
}
|
||||
|
||||
|
||||
//es7210用作音频采集
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(
|
||||
i2c_bus_,
|
||||
AUDIO_INPUT_SAMPLE_RATE,
|
||||
AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK,
|
||||
AUDIO_I2S_GPIO_BCLK,
|
||||
AUDIO_I2S_GPIO_WS,
|
||||
AUDIO_I2S_GPIO_DOUT,
|
||||
AUDIO_I2S_GPIO_DIN,
|
||||
GPIO_NUM_NC,
|
||||
AUDIO_CODEC_ES8311_ADDR,
|
||||
AUDIO_CODEC_ES7210_ADDR,
|
||||
true);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
//添加彩灯显示状态,如果亮度太暗可以去更改默认亮度值 DEFAULT_BRIGHTNESS 在led的sigle_led.cc中
|
||||
virtual Led* GetLed() override {
|
||||
static SingleLed led(BUILTIN_LED_GPIO);
|
||||
return &led;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
DECLARE_BOARD(ESP_S3_LCD_EV_Board_2);
|
||||
@@ -1,504 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_lcd_panel_commands.h>
|
||||
#include <esp_lcd_panel_interface.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#include "esp_lcd_gc9503.h"
|
||||
|
||||
#define GC9503_CMD_MADCTL (0xB1) // Memory data access control
|
||||
#define GC9503_CMD_MADCTL_DEFAULT (0x10) // Default value of Memory data access control
|
||||
#define GC9503_CMD_SS_BIT (1 << 0) // Source driver scan direction, 0: top to bottom, 1: bottom to top
|
||||
#define GC9503_CMD_GS_BIT (1 << 1) // Gate driver scan direction, 0: left to right, 1: right to left
|
||||
#define GC9503_CMD_BGR_BIT (1 << 5) // RGB/BGR order, 0: RGB, 1: BGR
|
||||
|
||||
typedef struct
|
||||
{
|
||||
esp_lcd_panel_io_handle_t io;
|
||||
int reset_gpio_num;
|
||||
uint8_t madctl_val; // Save current value of GC9503_CMD_MADCTL register
|
||||
uint8_t colmod_val; // Save current value of LCD_CMD_COLMOD register
|
||||
const gc9503_lcd_init_cmd_t *init_cmds;
|
||||
uint16_t init_cmds_size;
|
||||
struct
|
||||
{
|
||||
unsigned int mirror_by_cmd : 1;
|
||||
unsigned int auto_del_panel_io : 1;
|
||||
unsigned int display_on_off_use_cmd : 1;
|
||||
unsigned int reset_level : 1;
|
||||
} flags;
|
||||
// To save the original functions of RGB panel
|
||||
esp_err_t (*init)(esp_lcd_panel_t *panel);
|
||||
esp_err_t (*del)(esp_lcd_panel_t *panel);
|
||||
esp_err_t (*reset)(esp_lcd_panel_t *panel);
|
||||
esp_err_t (*mirror)(esp_lcd_panel_t *panel, bool x_axis, bool y_axis);
|
||||
esp_err_t (*disp_on_off)(esp_lcd_panel_t *panel, bool on_off);
|
||||
} gc9503_panel_t;
|
||||
|
||||
static const char *TAG = "gc9503";
|
||||
|
||||
static esp_err_t panel_gc9503_send_init_cmds(gc9503_panel_t *gc9503);
|
||||
|
||||
static esp_err_t panel_gc9503_init(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_gc9503_del(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_gc9503_reset(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_gc9503_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
|
||||
static esp_err_t panel_gc9503_disp_on_off(esp_lcd_panel_t *panel, bool off);
|
||||
|
||||
esp_err_t esp_lcd_new_panel_gc9503(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config,
|
||||
esp_lcd_panel_handle_t *ret_panel)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid arguments");
|
||||
gc9503_vendor_config_t *vendor_config = (gc9503_vendor_config_t *)panel_dev_config->vendor_config;
|
||||
ESP_RETURN_ON_FALSE(vendor_config && vendor_config->rgb_config, ESP_ERR_INVALID_ARG, TAG, "`verndor_config` and `rgb_config` are necessary");
|
||||
ESP_RETURN_ON_FALSE(!vendor_config->flags.auto_del_panel_io || !vendor_config->flags.mirror_by_cmd,
|
||||
ESP_ERR_INVALID_ARG, TAG, "`mirror_by_cmd` and `auto_del_panel_io` cannot work together");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
gpio_config_t io_conf = {0};
|
||||
|
||||
gc9503_panel_t *gc9503 = (gc9503_panel_t *)calloc(1, sizeof(gc9503_panel_t));
|
||||
ESP_RETURN_ON_FALSE(gc9503, ESP_ERR_NO_MEM, TAG, "no mem for gc9503 panel");
|
||||
|
||||
if (panel_dev_config->reset_gpio_num >= 0)
|
||||
{
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num;
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
|
||||
}
|
||||
|
||||
gc9503->madctl_val = GC9503_CMD_MADCTL_DEFAULT;
|
||||
switch (panel_dev_config->rgb_ele_order)
|
||||
{
|
||||
case LCD_RGB_ELEMENT_ORDER_RGB:
|
||||
gc9503->madctl_val &= ~GC9503_CMD_BGR_BIT;
|
||||
break;
|
||||
case LCD_RGB_ELEMENT_ORDER_BGR:
|
||||
gc9503->madctl_val |= GC9503_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color element order");
|
||||
break;
|
||||
}
|
||||
|
||||
gc9503->colmod_val = 0;
|
||||
switch (panel_dev_config->bits_per_pixel)
|
||||
{
|
||||
case 16: // RGB565
|
||||
gc9503->colmod_val = 0x50;
|
||||
break;
|
||||
case 18: // RGB666
|
||||
gc9503->colmod_val = 0x60;
|
||||
break;
|
||||
case 24: // RGB888
|
||||
gc9503->colmod_val = 0x70;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width");
|
||||
break;
|
||||
}
|
||||
|
||||
gc9503->io = io;
|
||||
gc9503->init_cmds = vendor_config->init_cmds;
|
||||
gc9503->init_cmds_size = vendor_config->init_cmds_size;
|
||||
gc9503->reset_gpio_num = panel_dev_config->reset_gpio_num;
|
||||
gc9503->flags.reset_level = panel_dev_config->flags.reset_active_high;
|
||||
gc9503->flags.auto_del_panel_io = vendor_config->flags.auto_del_panel_io;
|
||||
gc9503->flags.mirror_by_cmd = vendor_config->flags.mirror_by_cmd;
|
||||
gc9503->flags.display_on_off_use_cmd = (vendor_config->rgb_config->disp_gpio_num >= 0) ? 0 : 1;
|
||||
|
||||
if (gc9503->flags.auto_del_panel_io)
|
||||
{
|
||||
if (gc9503->reset_gpio_num >= 0)
|
||||
{ // Perform hardware reset
|
||||
gpio_set_level(gc9503->reset_gpio_num, gc9503->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(gc9503->reset_gpio_num, !gc9503->flags.reset_level);
|
||||
}
|
||||
else
|
||||
{ // Perform software reset
|
||||
ESP_GOTO_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), err, TAG, "send command failed");
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
|
||||
/**
|
||||
* In order to enable the 3-wire SPI interface pins (such as SDA and SCK) to share other pins of the RGB interface
|
||||
* (such as HSYNC) and save GPIOs, we need to send LCD initialization commands via the 3-wire SPI interface before
|
||||
* `esp_lcd_new_rgb_panel()` is called.
|
||||
*/
|
||||
ESP_GOTO_ON_ERROR(panel_gc9503_send_init_cmds(gc9503), err, TAG, "send init commands failed");
|
||||
// After sending the initialization commands, the 3-wire SPI interface can be deleted
|
||||
ESP_GOTO_ON_ERROR(esp_lcd_panel_io_del(io), err, TAG, "delete panel IO failed");
|
||||
gc9503->io = NULL;
|
||||
ESP_LOGD(TAG, "delete panel IO");
|
||||
}
|
||||
|
||||
// Create RGB panel
|
||||
ESP_GOTO_ON_ERROR(esp_lcd_new_rgb_panel(vendor_config->rgb_config, ret_panel), err, TAG, "create RGB panel failed");
|
||||
ESP_LOGD(TAG, "new RGB panel @%p", ret_panel);
|
||||
|
||||
// Save the original functions of RGB panel
|
||||
gc9503->init = (*ret_panel)->init;
|
||||
gc9503->del = (*ret_panel)->del;
|
||||
gc9503->reset = (*ret_panel)->reset;
|
||||
gc9503->mirror = (*ret_panel)->mirror;
|
||||
gc9503->disp_on_off = (*ret_panel)->disp_on_off;
|
||||
// Overwrite the functions of RGB panel
|
||||
(*ret_panel)->init = panel_gc9503_init;
|
||||
(*ret_panel)->del = panel_gc9503_del;
|
||||
(*ret_panel)->reset = panel_gc9503_reset;
|
||||
(*ret_panel)->mirror = panel_gc9503_mirror;
|
||||
(*ret_panel)->disp_on_off = panel_gc9503_disp_on_off;
|
||||
(*ret_panel)->user_data = gc9503;
|
||||
ESP_LOGD(TAG, "new gc9503 panel @%p", gc9503);
|
||||
|
||||
// ESP_LOGI(TAG, "LCD panel create success, version: %d.%d.%d", ESP_LCD_GC9503_VER_MAJOR, ESP_LCD_GC9503_VER_MINOR,
|
||||
// ESP_LCD_GC9503_VER_PATCH);
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (gc9503)
|
||||
{
|
||||
if (panel_dev_config->reset_gpio_num >= 0)
|
||||
{
|
||||
gpio_reset_pin(panel_dev_config->reset_gpio_num);
|
||||
}
|
||||
free(gc9503);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// *INDENT-OFF*
|
||||
// static const gc9503_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
// // {cmd, { data }, data_size, delay_ms}
|
||||
// {0x11, (uint8_t []){0x00}, 0, 120},
|
||||
|
||||
// {0xf0, (uint8_t []){0x55, 0xaa, 0x52, 0x08, 0x00}, 5, 0},
|
||||
// {0xf6, (uint8_t []){0x5a, 0x87}, 2, 0},
|
||||
// {0xc1, (uint8_t []){0x3f}, 1, 0},
|
||||
// {0xc2, (uint8_t []){0x0e}, 1, 0},
|
||||
// {0xc6, (uint8_t []){0xf8}, 1, 0},
|
||||
// {0xc9, (uint8_t []){0x10}, 1, 0},
|
||||
// {0xcd, (uint8_t []){0x25}, 1, 0},
|
||||
// {0xf8, (uint8_t []){0x8a}, 1, 0},
|
||||
// {0xac, (uint8_t []){0x45}, 1, 0},
|
||||
// {0xa0, (uint8_t []){0xdd}, 1, 0},
|
||||
// {0xa7, (uint8_t []){0x47}, 1, 0},
|
||||
// {0xfa, (uint8_t []){0x00, 0x00, 0x00, 0x04}, 4, 0},
|
||||
// {0x86, (uint8_t []){0x99, 0xa3, 0xa3, 0x51}, 4, 0},
|
||||
// {0xa3, (uint8_t []){0xee}, 1, 0},
|
||||
// {0xfd, (uint8_t []){0x3c, 0x3c, 0x00}, 3, 0},
|
||||
// {0x71, (uint8_t []){0x48}, 1, 0},
|
||||
// {0x72, (uint8_t []){0x48}, 1, 0},
|
||||
// {0x73, (uint8_t []){0x00, 0x44}, 2, 0},
|
||||
// {0x97, (uint8_t []){0xee}, 1, 0},
|
||||
// {0x83, (uint8_t []){0x93}, 1, 0},
|
||||
// {0x9a, (uint8_t []){0x72}, 1, 0},
|
||||
// {0x9b, (uint8_t []){0x5a}, 1, 0},
|
||||
// {0x82, (uint8_t []){0x2c, 0x2c}, 2, 0},
|
||||
// {0x6d, (uint8_t []){0x00, 0x1f, 0x19, 0x1a, 0x10, 0x0e, 0x0c, 0x0a, 0x02, 0x07, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
|
||||
// 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x08, 0x01, 0x09, 0x0b, 0x0d, 0x0f, 0x1a, 0x19, 0x1f, 0x00}, 32, 0},
|
||||
// {0x64, (uint8_t []){0x38, 0x05, 0x01, 0xdb, 0x03, 0x03, 0x38, 0x04, 0x01, 0xdc, 0x03, 0x03, 0x7a, 0x7a, 0x7a, 0x7a}, 16, 0},
|
||||
// {0x65, (uint8_t []){0x38, 0x03, 0x01, 0xdd, 0x03, 0x03, 0x38, 0x02, 0x01, 0xde, 0x03, 0x03, 0x7a, 0x7a, 0x7a, 0x7a}, 16, 0},
|
||||
// {0x66, (uint8_t []){0x38, 0x01, 0x01, 0xdf, 0x03, 0x03, 0x38, 0x00, 0x01, 0xe0, 0x03, 0x03, 0x7a, 0x7a, 0x7a, 0x7a}, 16, 0},
|
||||
// {0x67, (uint8_t []){0x30, 0x01, 0x01, 0xe1, 0x03, 0x03, 0x30, 0x02, 0x01, 0xe2, 0x03, 0x03, 0x7a, 0x7a, 0x7a, 0x7a}, 16, 0},
|
||||
// {0x68, (uint8_t []){0x00, 0x08, 0x15, 0x08, 0x15, 0x7a, 0x7a, 0x08, 0x15, 0x08, 0x15, 0x7a, 0x7a}, 13, 0},
|
||||
// {0x60, (uint8_t []){0x38, 0x08, 0x7a, 0x7a, 0x38, 0x09, 0x7a, 0x7a}, 8, 0},
|
||||
// {0x63, (uint8_t []){0x31, 0xe4, 0x7a, 0x7a, 0x31, 0xe5, 0x7a, 0x7a}, 8, 0},
|
||||
// {0x69, (uint8_t []){0x04, 0x22, 0x14, 0x22, 0x14, 0x22, 0x08}, 7, 0},
|
||||
// {0x6b, (uint8_t []){0x07}, 1, 0},
|
||||
// {0x7a, (uint8_t []){0x08, 0x13}, 2, 0},
|
||||
// {0x7b, (uint8_t []){0x08, 0x13}, 2, 0},
|
||||
// {0xd1, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
// 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
// 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
// 0xff}, 52, 0},
|
||||
// {0xd2, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
// 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
// 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
// 0xff}, 52, 0},
|
||||
// {0xd3, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
// 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
// 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
// 0xff}, 52, 0},
|
||||
// {0xd4, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
// 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
// 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
// 0xff}, 52, 0},
|
||||
// {0xd5, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
// 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
// 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
// 0xff}, 52, 0},
|
||||
// {0xd6, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
// 0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
// 0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
// 0xff}, 52, 0},
|
||||
// {0x11, (uint8_t []){0x00}, 0, 120},
|
||||
// {0x29, (uint8_t []){0x00}, 0, 20},
|
||||
// };
|
||||
static const gc9503_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
// {0x11, (uint8_t[]){}, 0, 20},
|
||||
|
||||
{0xf0, (uint8_t []){0x55, 0xaa, 0x52, 0x08, 0x00}, 5, 0},
|
||||
{0xf6, (uint8_t []){0x5a, 0x87}, 2, 0},
|
||||
{0xc1, (uint8_t []){0x3f}, 1, 0},
|
||||
{0xc2, (uint8_t []){0x0e}, 1, 0},
|
||||
{0xc6, (uint8_t []){0xf8}, 1, 0},
|
||||
{0xc9, (uint8_t []){0x10}, 1, 0},
|
||||
{0xcd, (uint8_t []){0x25}, 1, 0},
|
||||
{0xf8, (uint8_t []){0x8a}, 1, 0},
|
||||
{0xac, (uint8_t []){0x45}, 1, 0},
|
||||
{0xa0, (uint8_t []){0xdd}, 1, 0},
|
||||
{0xa7, (uint8_t []){0x47}, 1, 0},
|
||||
{0xfa, (uint8_t []){0x00, 0x00, 0x00, 0x04}, 4, 0},
|
||||
{0x86, (uint8_t []){0x99, 0xa3, 0xa3, 0x51}, 4, 0},
|
||||
{0xa3, (uint8_t []){0xee}, 1, 0},
|
||||
{0xfd, (uint8_t []){0x3c, 0x3c, 0x00}, 3, 0},
|
||||
{0x71, (uint8_t []){0x48}, 1, 0},
|
||||
{0x72, (uint8_t []){0x48}, 1, 0},
|
||||
{0x73, (uint8_t []){0x00, 0x44}, 2, 0},
|
||||
{0x97, (uint8_t []){0xee}, 1, 0},
|
||||
{0x83, (uint8_t []){0x93}, 1, 0},
|
||||
{0x9a, (uint8_t []){0x72}, 1, 0},
|
||||
{0x9b, (uint8_t []){0x5a}, 1, 0},
|
||||
{0x82, (uint8_t []){0x2c, 0x2c}, 2, 0},
|
||||
{0x6d, (uint8_t []){0x00, 0x1f, 0x19, 0x1a, 0x10, 0x0e, 0x0c, 0x0a, 0x02, 0x07, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
|
||||
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x08, 0x01, 0x09, 0x0b, 0x0d, 0x0f, 0x1a, 0x19, 0x1f, 0x00}, 32, 0},
|
||||
{0x64, (uint8_t []){0x38, 0x05, 0x01, 0xdb, 0x03, 0x03, 0x38, 0x04, 0x01, 0xdc, 0x03, 0x03, 0x7a, 0x7a, 0x7a, 0x7a}, 16, 0},
|
||||
{0x65, (uint8_t []){0x38, 0x03, 0x01, 0xdd, 0x03, 0x03, 0x38, 0x02, 0x01, 0xde, 0x03, 0x03, 0x7a, 0x7a, 0x7a, 0x7a}, 16, 0},
|
||||
{0x66, (uint8_t []){0x38, 0x01, 0x01, 0xdf, 0x03, 0x03, 0x38, 0x00, 0x01, 0xe0, 0x03, 0x03, 0x7a, 0x7a, 0x7a, 0x7a}, 16, 0},
|
||||
{0x67, (uint8_t []){0x30, 0x01, 0x01, 0xe1, 0x03, 0x03, 0x30, 0x02, 0x01, 0xe2, 0x03, 0x03, 0x7a, 0x7a, 0x7a, 0x7a}, 16, 0},
|
||||
{0x68, (uint8_t []){0x00, 0x08, 0x15, 0x08, 0x15, 0x7a, 0x7a, 0x08, 0x15, 0x08, 0x15, 0x7a, 0x7a}, 13, 0},
|
||||
{0x60, (uint8_t []){0x38, 0x08, 0x7a, 0x7a, 0x38, 0x09, 0x7a, 0x7a}, 8, 0},
|
||||
{0x63, (uint8_t []){0x31, 0xe4, 0x7a, 0x7a, 0x31, 0xe5, 0x7a, 0x7a}, 8, 0},
|
||||
{0x69, (uint8_t []){0x04, 0x22, 0x14, 0x22, 0x14, 0x22, 0x08}, 7, 0},
|
||||
{0x6b, (uint8_t []){0x07}, 1, 0},
|
||||
{0x7a, (uint8_t []){0x08, 0x13}, 2, 0},
|
||||
{0x7b, (uint8_t []){0x08, 0x13}, 2, 0},
|
||||
{0xd1, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
0xff}, 52, 0},
|
||||
{0xd2, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
0xff}, 52, 0},
|
||||
{0xd3, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
0xff}, 52, 0},
|
||||
{0xd4, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
0xff}, 52, 0},
|
||||
{0xd5, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
0xff}, 52, 0},
|
||||
{0xd6, (uint8_t []){0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x18, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x47, 0x00,
|
||||
0x56, 0x00, 0x90, 0x00, 0xe5, 0x01, 0x68, 0x01, 0xd5, 0x01, 0xd7, 0x02, 0x36, 0x02, 0xa6, 0x02, 0xee,
|
||||
0x03, 0x48, 0x03, 0xa0, 0x03, 0xba, 0x03, 0xc5, 0x03, 0xd0, 0x03, 0xe0, 0x03, 0xea, 0x03, 0xfa, 0x03,
|
||||
0xff}, 52, 0},
|
||||
{0x11, (uint8_t []){0x00}, 0, 120},
|
||||
{0x29, (uint8_t []){0x00}, 0, 20},
|
||||
|
||||
};
|
||||
|
||||
// *INDENT-OFF*
|
||||
|
||||
static esp_err_t panel_gc9503_send_init_cmds(gc9503_panel_t *gc9503)
|
||||
{
|
||||
esp_lcd_panel_io_handle_t io = gc9503->io;
|
||||
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, GC9503_CMD_MADCTL, (uint8_t[]){
|
||||
gc9503->madctl_val,
|
||||
},
|
||||
1),
|
||||
TAG, "send command failed");
|
||||
;
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_COLMOD, (uint8_t[]){
|
||||
gc9503->colmod_val,
|
||||
},
|
||||
1),
|
||||
TAG, "send command failed");
|
||||
;
|
||||
|
||||
// Vendor specific initialization, it can be different between manufacturers
|
||||
// should consult the LCD supplier for initialization sequence code
|
||||
const gc9503_lcd_init_cmd_t *init_cmds = NULL;
|
||||
uint16_t init_cmds_size = 0;
|
||||
if (gc9503->init_cmds)
|
||||
{
|
||||
init_cmds = gc9503->init_cmds;
|
||||
init_cmds_size = gc9503->init_cmds_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
init_cmds = vendor_specific_init_default;
|
||||
init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(gc9503_lcd_init_cmd_t);
|
||||
}
|
||||
|
||||
bool is_cmd_overwritten = false;
|
||||
for (int i = 0; i < init_cmds_size; i++)
|
||||
{
|
||||
// Check if the command has been used or conflicts with the internal
|
||||
switch (init_cmds[i].cmd)
|
||||
{
|
||||
case LCD_CMD_MADCTL:
|
||||
is_cmd_overwritten = true;
|
||||
gc9503->madctl_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
case LCD_CMD_COLMOD:
|
||||
is_cmd_overwritten = true;
|
||||
gc9503->colmod_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
default:
|
||||
is_cmd_overwritten = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_cmd_overwritten)
|
||||
{
|
||||
ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence",
|
||||
init_cmds[i].cmd);
|
||||
}
|
||||
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes),
|
||||
TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms));
|
||||
}
|
||||
ESP_LOGD(TAG, "send init commands success");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_gc9503_init(esp_lcd_panel_t *panel)
|
||||
{
|
||||
gc9503_panel_t *gc9503 = (gc9503_panel_t *)panel->user_data;
|
||||
|
||||
if (!gc9503->flags.auto_del_panel_io)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(panel_gc9503_send_init_cmds(gc9503), TAG, "send init commands failed");
|
||||
}
|
||||
// Init RGB panel
|
||||
ESP_RETURN_ON_ERROR(gc9503->init(panel), TAG, "init RGB panel failed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_gc9503_del(esp_lcd_panel_t *panel)
|
||||
{
|
||||
gc9503_panel_t *gc9503 = (gc9503_panel_t *)panel->user_data;
|
||||
|
||||
if (gc9503->reset_gpio_num >= 0)
|
||||
{
|
||||
gpio_reset_pin(gc9503->reset_gpio_num);
|
||||
}
|
||||
// Delete RGB panel
|
||||
gc9503->del(panel);
|
||||
free(gc9503);
|
||||
ESP_LOGD(TAG, "del gc9503 panel @%p", gc9503);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_gc9503_reset(esp_lcd_panel_t *panel)
|
||||
{
|
||||
gc9503_panel_t *gc9503 = (gc9503_panel_t *)panel->user_data;
|
||||
esp_lcd_panel_io_handle_t io = gc9503->io;
|
||||
|
||||
// Perform hardware reset
|
||||
if (gc9503->reset_gpio_num >= 0)
|
||||
{
|
||||
gpio_set_level(gc9503->reset_gpio_num, gc9503->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(gc9503->reset_gpio_num, !gc9503->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
}
|
||||
else if (io)
|
||||
{ // Perform software reset
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
}
|
||||
// Reset RGB panel
|
||||
ESP_RETURN_ON_ERROR(gc9503->reset(panel), TAG, "reset RGB panel failed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_gc9503_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
|
||||
{
|
||||
gc9503_panel_t *gc9503 = (gc9503_panel_t *)panel->user_data;
|
||||
esp_lcd_panel_io_handle_t io = gc9503->io;
|
||||
|
||||
if (gc9503->flags.mirror_by_cmd)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(io, ESP_FAIL, TAG, "Panel IO is deleted, cannot send command");
|
||||
// Control mirror through LCD command
|
||||
if (mirror_x)
|
||||
{
|
||||
gc9503->madctl_val |= GC9503_CMD_GS_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
gc9503->madctl_val &= ~GC9503_CMD_GS_BIT;
|
||||
}
|
||||
if (mirror_y)
|
||||
{
|
||||
gc9503->madctl_val |= GC9503_CMD_SS_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
gc9503->madctl_val &= ~GC9503_CMD_SS_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, GC9503_CMD_MADCTL, (uint8_t[]){
|
||||
gc9503->madctl_val,
|
||||
},
|
||||
1),
|
||||
TAG, "send command failed");
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Control mirror through RGB panel
|
||||
ESP_RETURN_ON_ERROR(gc9503->mirror(panel, mirror_x, mirror_y), TAG, "RGB panel mirror failed");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_gc9503_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
||||
{
|
||||
gc9503_panel_t *gc9503 = (gc9503_panel_t *)panel->user_data;
|
||||
esp_lcd_panel_io_handle_t io = gc9503->io;
|
||||
int command = 0;
|
||||
|
||||
if (gc9503->flags.display_on_off_use_cmd)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(io, ESP_FAIL, TAG, "Panel IO is deleted, cannot send command");
|
||||
// Control display on/off through LCD command
|
||||
if (on_off)
|
||||
{
|
||||
command = LCD_CMD_DISPON;
|
||||
}
|
||||
else
|
||||
{
|
||||
command = LCD_CMD_DISPOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Control display on/off through display control signal
|
||||
ESP_RETURN_ON_ERROR(gc9503->disp_on_off(panel, on_off), TAG, "RGB panel disp_on_off failed");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief ESP LCD: GC9503
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_lcd_panel_rgb.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LCD panel initialization commands.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
int cmd; /*<! The specific LCD command */
|
||||
const void *data; /*<! Buffer that holds the command specific data */
|
||||
size_t data_bytes; /*<! Size of `data` in memory, in bytes */
|
||||
unsigned int delay_ms; /*<! Delay in milliseconds after this command */
|
||||
} gc9503_lcd_init_cmd_t;
|
||||
|
||||
/**
|
||||
* @brief LCD panel vendor configuration.
|
||||
*
|
||||
* @note This structure needs to be passed to the `vendor_config` field in `esp_lcd_panel_dev_config_t`.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
const esp_lcd_rgb_panel_config_t *rgb_config; /*!< RGB panel configuration */
|
||||
const gc9503_lcd_init_cmd_t *init_cmds; /*!< Pointer to initialization commands array. Set to NULL if using default commands.
|
||||
* The array should be declared as `static const` and positioned outside the function.
|
||||
* Please refer to `vendor_specific_init_default` in source file.
|
||||
*/
|
||||
uint16_t init_cmds_size; /*<! Number of commands in above array */
|
||||
struct {
|
||||
unsigned int mirror_by_cmd: 1; /*<! The `mirror()` function will be implemented by LCD command if set to 1.
|
||||
* Otherwise, the function will be implemented by software.
|
||||
*/
|
||||
unsigned int auto_del_panel_io: 1; /*<! Delete the panel IO instance automatically if set to 1. All `*_by_cmd` flags will be invalid.
|
||||
* If the panel IO pins are sharing other pins of the RGB interface to save GPIOs,
|
||||
* Please set it to 1 to release the panel IO and its pins (except CS signal).
|
||||
*/
|
||||
} flags;
|
||||
} gc9503_vendor_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create LCD panel for model GC9503
|
||||
*
|
||||
* @note When `auto_del_panel_io` is set to 1, this function will first initialize the GC9503 with vendor specific initialization and then calls `esp_lcd_new_rgb_panel()` to create an RGB LCD panel. And the `esp_lcd_panel_init()` function will only initialize RGB.
|
||||
* @note When `auto_del_panel_io` is set to 0, this function will only call `esp_lcd_new_rgb_panel()` to create an RGB LCD panel. And the `esp_lcd_panel_init()` function will initialize both the GC9503 and RGB.
|
||||
* @note Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for initialization sequence code.
|
||||
*
|
||||
* @param[in] io LCD panel IO handle
|
||||
* @param[in] panel_dev_config General panel device configuration (`vendor_config` and `rgb_config` are necessary)
|
||||
* @param[out] ret_panel Returned LCD panel handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
* - Otherwise on fail
|
||||
*/
|
||||
esp_err_t esp_lcd_new_panel_gc9503(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config,
|
||||
esp_lcd_panel_handle_t *ret_panel);
|
||||
|
||||
/**
|
||||
* @brief 3-wire SPI panel IO configuration structure
|
||||
*
|
||||
* @param[in] line_cfg SPI line configuration
|
||||
* @param[in] scl_active_edge SCL signal active edge, 0: rising edge, 1: falling edge
|
||||
*
|
||||
*/
|
||||
#define GC9503_PANEL_IO_3WIRE_SPI_CONFIG(line_cfg, scl_active_edge) \
|
||||
{ \
|
||||
.line_config = line_cfg, \
|
||||
.expect_clk_speed = PANEL_IO_3WIRE_SPI_CLK_MAX, \
|
||||
.spi_mode = scl_active_edge ? 1 : 0, \
|
||||
.lcd_cmd_bytes = 1, \
|
||||
.lcd_param_bytes = 1, \
|
||||
.flags = { \
|
||||
.use_dc_bit = 1, \
|
||||
.dc_zero_on_data = 0, \
|
||||
.lsb_first = 0, \
|
||||
.cs_high_active = 0, \
|
||||
.del_keep_cs_inactive = 1, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RGB timing structure
|
||||
*
|
||||
* @note refresh_rate = (pclk_hz * data_width) / (h_res + hsync_pulse_width + hsync_back_porch + hsync_front_porch)
|
||||
* / (v_res + vsync_pulse_width + vsync_back_porch + vsync_front_porch)
|
||||
* / bits_per_pixel
|
||||
* .pclk_hz = 16 * 1000 * 1000, \
|
||||
.h_res = 384, \
|
||||
.v_res = 960, \
|
||||
.hsync_pulse_width = 24, \
|
||||
.hsync_back_porch = 20, \
|
||||
.hsync_front_porch = 40, \
|
||||
.vsync_pulse_width = 30, \
|
||||
.vsync_back_porch = 18, \
|
||||
.vsync_front_porch = 20, \
|
||||
.flags.pclk_active_neg = 0, \
|
||||
|
||||
.hsync_pulse_width = 24, \
|
||||
.hsync_back_porch = 20, \
|
||||
.hsync_front_porch = 40, \
|
||||
.vsync_pulse_width = 30, \
|
||||
.vsync_back_porch = 18, \
|
||||
.vsync_front_porch = 20, \
|
||||
|
||||
*/
|
||||
|
||||
#define GC9503_800_480_PANEL_60HZ_RGB_TIMING() \
|
||||
{ \
|
||||
.pclk_hz = 16 * 1000 * 1000, \
|
||||
.h_res = 800, \
|
||||
.v_res = 480, \
|
||||
.hsync_pulse_width = 10, \
|
||||
.hsync_back_porch = 10, \
|
||||
.hsync_front_porch = 20, \
|
||||
.vsync_pulse_width = 10, \
|
||||
.vsync_back_porch = 10, \
|
||||
.vsync_front_porch = 10, \
|
||||
.flags = { \
|
||||
.hsync_idle_low = 0, \
|
||||
.vsync_idle_low = 0, \
|
||||
.de_idle_high = 0, \
|
||||
.pclk_active_neg = 0, \
|
||||
.pclk_idle_high = 0, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,52 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
//关于开发板和屏幕的资料参考
|
||||
//https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-lcd-ev-board/user_guide.html
|
||||
|
||||
#define GC9503V_LCD_H_RES 800
|
||||
#define GC9503V_LCD_V_RES 480
|
||||
|
||||
|
||||
#define GC9503V_LCD_LVGL_DIRECT_MODE (1)
|
||||
#define GC9503V_LCD_LVGL_AVOID_TEAR (1)
|
||||
#define GC9503V_LCD_RGB_BOUNCE_BUFFER_MODE (1)
|
||||
#define GC9503V_LCD_DRAW_BUFF_DOUBLE (0)
|
||||
#define GC9503V_LCD_DRAW_BUFF_HEIGHT (100)
|
||||
#define GC9503V_LCD_RGB_BUFFER_NUMS (2)
|
||||
#define GC9503V_LCD_RGB_BOUNCE_BUFFER_HEIGHT (10)
|
||||
|
||||
#define GC9503V_LCD_PIXEL_CLOCK_HZ (16 * 1000 * 1000)
|
||||
#define GC9503V_LCD_BK_LIGHT_ON_LEVEL 1
|
||||
#define GC9503V_LCD_BK_LIGHT_OFF_LEVEL !GC9503V_LCD_BK_LIGHT_ON_LEVEL
|
||||
|
||||
#define GC9503V_PIN_NUM_BK_LIGHT GPIO_NUM_NC //GPIO_NUM_4
|
||||
#define GC9503V_PIN_NUM_HSYNC GPIO_NUM_46
|
||||
#define GC9503V_PIN_NUM_VSYNC GPIO_NUM_3
|
||||
#define GC9503V_PIN_NUM_DE GPIO_NUM_17
|
||||
#define GC9503V_PIN_NUM_PCLK GPIO_NUM_9
|
||||
|
||||
#define GC9503V_PIN_NUM_DATA0 GPIO_NUM_10 // B0
|
||||
#define GC9503V_PIN_NUM_DATA1 GPIO_NUM_11 // B1
|
||||
#define GC9503V_PIN_NUM_DATA2 GPIO_NUM_12 // B2
|
||||
#define GC9503V_PIN_NUM_DATA3 GPIO_NUM_13 // B3
|
||||
#define GC9503V_PIN_NUM_DATA4 GPIO_NUM_14 // B4
|
||||
|
||||
#define GC9503V_PIN_NUM_DATA5 GPIO_NUM_21 // G0
|
||||
#define GC9503V_PIN_NUM_DATA6 GPIO_NUM_8 // G1
|
||||
#define GC9503V_PIN_NUM_DATA7 GPIO_NUM_18 // G2
|
||||
#define GC9503V_PIN_NUM_DATA8 GPIO_NUM_45 // G3
|
||||
#define GC9503V_PIN_NUM_DATA9 GPIO_NUM_38 // G4
|
||||
#define GC9503V_PIN_NUM_DATA10 GPIO_NUM_39 // G5
|
||||
|
||||
#define GC9503V_PIN_NUM_DATA11 GPIO_NUM_40 // R0
|
||||
#define GC9503V_PIN_NUM_DATA12 GPIO_NUM_41 // R1
|
||||
#define GC9503V_PIN_NUM_DATA13 GPIO_NUM_42 // R2
|
||||
#define GC9503V_PIN_NUM_DATA14 GPIO_NUM_2 // R3
|
||||
#define GC9503V_PIN_NUM_DATA15 GPIO_NUM_1 // R4
|
||||
|
||||
#define GC9503V_PIN_NUM_DISP_EN -1
|
||||
|
||||
#define GC9503V_LCD_IO_SPI_CS_1 (IO_EXPANDER_PIN_NUM_1)
|
||||
#define GC9503V_LCD_IO_SPI_SCL_1 (IO_EXPANDER_PIN_NUM_2)
|
||||
#define GC9503V_LCD_IO_SPI_SDO_1 (IO_EXPANDER_PIN_NUM_3)
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "wifi_board.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include "codecs/es8311_audio_codec.h"
|
||||
#include "application.h"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
#ifdef CONFIG_ESP32S3_KORVO2_V3_LCD_ST7789
|
||||
#ifdef CONFIG_LCD_ST7789
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_WIDTH 280
|
||||
@@ -40,7 +40,7 @@
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP32S3_KORVO2_V3_LCD_ILI9341
|
||||
#ifdef CONFIG_LCD_ILI9341
|
||||
#define LCD_TYPE_ILI9341_SERIAL
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_NC
|
||||
@@ -78,4 +78,4 @@
|
||||
#define CAMERA_PIN_PCLK 11
|
||||
|
||||
#define XCLK_FREQ_HZ 20000000
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "i2c_device.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
@@ -17,16 +16,6 @@
|
||||
#include "esp32_camera.h"
|
||||
|
||||
#define TAG "esp32s3_korvo2_v3"
|
||||
/* ADC Buttons */
|
||||
typedef enum {
|
||||
BSP_ADC_BUTTON_REC,
|
||||
BSP_ADC_BUTTON_VOL_MUTE,
|
||||
BSP_ADC_BUTTON_PLAY,
|
||||
BSP_ADC_BUTTON_SET,
|
||||
BSP_ADC_BUTTON_VOL_DOWN,
|
||||
BSP_ADC_BUTTON_VOL_UP,
|
||||
BSP_ADC_BUTTON_NUM
|
||||
} bsp_adc_button_t;
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_20_4);
|
||||
LV_FONT_DECLARE(font_awesome_20_4);
|
||||
@@ -56,10 +45,6 @@ static const ili9341_lcd_init_cmd_t vendor_specific_init[] = {
|
||||
class Esp32S3Korvo2V3Board : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
Button* adc_button_[BSP_ADC_BUTTON_NUM];
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
adc_oneshot_unit_handle_t bsp_adc_handle = NULL;
|
||||
#endif
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
LcdDisplay* display_;
|
||||
esp_io_expander_handle_t io_expander_ = NULL;
|
||||
@@ -146,103 +131,7 @@ private:
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void ChangeVol(int val) {
|
||||
auto codec = GetAudioCodec();
|
||||
auto volume = codec->output_volume() + val;
|
||||
if (volume > 100) {
|
||||
volume = 100;
|
||||
}
|
||||
if (volume < 0) {
|
||||
volume = 0;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
|
||||
}
|
||||
|
||||
void MuteVol() {
|
||||
auto codec = GetAudioCodec();
|
||||
auto volume = codec->output_volume();
|
||||
if (volume > 1) {
|
||||
volume = 0;
|
||||
} else {
|
||||
volume = 50;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
button_adc_config_t adc_cfg = {};
|
||||
adc_cfg.adc_channel = ADC_CHANNEL_4; // ADC1 channel 0 is GPIO5
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
const adc_oneshot_unit_init_cfg_t init_config1 = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
};
|
||||
adc_oneshot_new_unit(&init_config1, &bsp_adc_handle);
|
||||
adc_cfg.adc_handle = &bsp_adc_handle;
|
||||
#endif
|
||||
adc_cfg.button_index = BSP_ADC_BUTTON_REC;
|
||||
adc_cfg.min = 2310; // middle is 2410mV
|
||||
adc_cfg.max = 2510;
|
||||
adc_button_[0] = new AdcButton(adc_cfg);
|
||||
|
||||
adc_cfg.button_index = BSP_ADC_BUTTON_VOL_MUTE;
|
||||
adc_cfg.min = 1880; // middle is 1980mV
|
||||
adc_cfg.max = 2080;
|
||||
adc_button_[1] = new AdcButton(adc_cfg);
|
||||
|
||||
adc_cfg.button_index = BSP_ADC_BUTTON_PLAY;
|
||||
adc_cfg.min = 1550; // middle is 1650mV
|
||||
adc_cfg.max = 1750;
|
||||
adc_button_[2] = new AdcButton(adc_cfg);
|
||||
|
||||
adc_cfg.button_index = BSP_ADC_BUTTON_SET;
|
||||
adc_cfg.min = 1015; // middle is 1115mV
|
||||
adc_cfg.max = 1215;
|
||||
adc_button_[3] = new AdcButton(adc_cfg);
|
||||
|
||||
adc_cfg.button_index = BSP_ADC_BUTTON_VOL_DOWN;
|
||||
adc_cfg.min = 720; // middle is 820mV
|
||||
adc_cfg.max = 920;
|
||||
adc_button_[4] = new AdcButton(adc_cfg);
|
||||
|
||||
adc_cfg.button_index = BSP_ADC_BUTTON_VOL_UP;
|
||||
adc_cfg.min = 280; // middle is 380mV
|
||||
adc_cfg.max = 480;
|
||||
adc_button_[5] = new AdcButton(adc_cfg);
|
||||
|
||||
auto volume_up_button = adc_button_[BSP_ADC_BUTTON_VOL_UP];
|
||||
volume_up_button->OnClick([this]() {ChangeVol(10);});
|
||||
volume_up_button->OnLongPress([this]() {
|
||||
GetAudioCodec()->SetOutputVolume(100);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
|
||||
});
|
||||
|
||||
auto volume_down_button = adc_button_[BSP_ADC_BUTTON_VOL_DOWN];
|
||||
volume_down_button->OnClick([this]() {ChangeVol(-10);});
|
||||
volume_down_button->OnLongPress([this]() {
|
||||
GetAudioCodec()->SetOutputVolume(0);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MUTED);
|
||||
});
|
||||
|
||||
auto volume_mute_button = adc_button_[BSP_ADC_BUTTON_VOL_MUTE];
|
||||
volume_mute_button->OnClick([this]() {MuteVol();});
|
||||
|
||||
auto play_button = adc_button_[BSP_ADC_BUTTON_PLAY];
|
||||
play_button->OnClick([this]() {
|
||||
ESP_LOGI(TAG, " TODO %s:%d\n", __func__, __LINE__);
|
||||
});
|
||||
|
||||
auto set_button = adc_button_[BSP_ADC_BUTTON_SET];
|
||||
set_button->OnClick([this]() {
|
||||
ESP_LOGI(TAG, "TODO %s:%d\n", __func__, __LINE__);
|
||||
});
|
||||
|
||||
auto rec_button = adc_button_[BSP_ADC_BUTTON_REC];
|
||||
rec_button->OnClick([this]() {
|
||||
ESP_LOGI(TAG, "TODO %s:%d\n", __func__, __LINE__);
|
||||
});
|
||||
boot_button_.OnClick([this]() {});
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
|
||||
@@ -173,8 +173,8 @@ private:
|
||||
{
|
||||
esp_lcd_touch_handle_t tp;
|
||||
esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = DISPLAY_HEIGHT,
|
||||
.y_max = DISPLAY_WIDTH,
|
||||
.x_max = DISPLAY_WIDTH,
|
||||
.y_max = DISPLAY_HEIGHT,
|
||||
.rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset
|
||||
.int_gpio_num = GPIO_NUM_NC,
|
||||
.levels = {
|
||||
|
||||
@@ -64,7 +64,7 @@ CoreS3AudioCodec::CoreS3AudioCodec(void* i2c_master_handle, int input_sample_rat
|
||||
|
||||
es7210_codec_cfg_t es7210_cfg = {};
|
||||
es7210_cfg.ctrl_if = in_ctrl_if_;
|
||||
es7210_cfg.mic_selected = ES7210_SEL_MIC1 | ES7210_SEL_MIC2 | ES7210_SEL_MIC3;
|
||||
es7210_cfg.mic_selected = ES7120_SEL_MIC1 | ES7120_SEL_MIC2 | ES7120_SEL_MIC3;
|
||||
in_codec_if_ = es7210_codec_new(&es7210_cfg);
|
||||
assert(in_codec_if_ != NULL);
|
||||
|
||||
|
||||
@@ -627,7 +627,6 @@ CONFIG_BOARD_TYPE_M5STACK_CORE_S3=y
|
||||
# CONFIG_BOARD_TYPE_MIXGO_NOVA is not set
|
||||
# CONFIG_BOARD_TYPE_GENJUTECH_S3_1_54TFT is not set
|
||||
# CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board is not set
|
||||
# CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board_2 is not set
|
||||
# CONFIG_BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI is not set
|
||||
# CONFIG_BOARD_TYPE_MINSI_K08_DUAL is not set
|
||||
# CONFIG_BOARD_TYPE_ZHENGCHEN_1_54TFT_ML307 is not set
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "tab5_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_ili9881c.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "font_emoji.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
|
||||
@@ -66,7 +66,7 @@ Tab5AudioCodec::Tab5AudioCodec(void* i2c_master_handle, int input_sample_rate, i
|
||||
|
||||
es7210_codec_cfg_t es7210_cfg = {};
|
||||
es7210_cfg.ctrl_if = in_ctrl_if_;
|
||||
es7210_cfg.mic_selected = ES7210_SEL_MIC1 | ES7210_SEL_MIC2 | ES7210_SEL_MIC3 | ES7210_SEL_MIC4;
|
||||
es7210_cfg.mic_selected = ES7120_SEL_MIC1 | ES7120_SEL_MIC2 | ES7120_SEL_MIC3 | ES7120_SEL_MIC4;
|
||||
in_codec_if_ = es7210_codec_new(&es7210_cfg);
|
||||
assert(in_codec_if_ != NULL);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "button.h"
|
||||
#include "led/circular_strip.h"
|
||||
#include "config.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "led/circular_strip.h"
|
||||
#include "config.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <wifi_station.h>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "led/single_led.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include <wifi_station.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "led/single_led.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include <wifi_station.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "otto_emoji_display.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <font_awesome.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "display/lcd_display.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#define TAG "OttoEmojiDisplay"
|
||||
|
||||
@@ -142,7 +142,7 @@ void OttoEmojiDisplay::SetChatMessage(const char* role, const char* content) {
|
||||
}
|
||||
|
||||
lv_label_set_text(chat_message_label_, content);
|
||||
lv_obj_remove_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
ESP_LOGI(TAG, "设置聊天消息 [%s]: %s", role, content);
|
||||
}
|
||||
@@ -164,7 +164,7 @@ void OttoEmojiDisplay::SetIcon(const char* icon) {
|
||||
}
|
||||
|
||||
lv_label_set_text(chat_message_label_, icon_message.c_str());
|
||||
lv_obj_remove_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
ESP_LOGI(TAG, "设置图标: %s", icon);
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ void Otto::ShakeLeg(int steps, int period, int dir) {
|
||||
int homes[SERVO_COUNT] = {90, 90, 90, 90, HAND_HOME_POSITION, 180 - HAND_HOME_POSITION};
|
||||
|
||||
// Changes in the parameters if left leg is chosen
|
||||
if (dir == 1) {
|
||||
if (dir == -1) {
|
||||
shake_leg1[2] = 180 - 35;
|
||||
shake_leg1[3] = 180 - 58;
|
||||
shake_leg2[2] = 180 - 120;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "wifi_board.h"
|
||||
#include "sensecap_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "application.h"
|
||||
#include "knob.h"
|
||||
#include "config.h"
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
|
||||
#define TAG "SURFERC3114TFT"
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_20_4);
|
||||
LV_FONT_DECLARE(font_awesome_20_4);
|
||||
LV_FONT_DECLARE(font_puhui_16_4);
|
||||
LV_FONT_DECLARE(font_awesome_16_4);
|
||||
|
||||
class SurferC3114TFT : public WifiBoard {
|
||||
private:
|
||||
@@ -148,8 +148,8 @@ private:
|
||||
display_ = new SpiLcdDisplay(panel_io_, panel_,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_20_4,
|
||||
.icon_font = &font_awesome_20_4,
|
||||
.text_font = &font_puhui_16_4,
|
||||
.icon_font = &font_awesome_16_4,
|
||||
.emoji_font = font_emoji_32_init(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "power_save_timer.h"
|
||||
#include "axp2101.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <driver/gpio.h>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
新增 微雪 开发板: ESP32-S3-AUDIO-Board
|
||||
产品链接:
|
||||
https://www.waveshare.net/shop/ESP32-S3-AUDIO-Board.htm
|
||||
@@ -1,95 +0,0 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 24000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_38
|
||||
|
||||
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_12
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_13
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_14
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_15
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_16
|
||||
#define AUDIO_CODEC_PA_PIN GPIO_NUM_NC
|
||||
#define AUDIO_INPUT_REFERENCE true
|
||||
#define AUDIO_CODEC_ES8311_ADDR ES8311_CODEC_DEFAULT_ADDR
|
||||
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
|
||||
|
||||
#define I2C_SCL_IO GPIO_NUM_10
|
||||
#define I2C_SDA_IO GPIO_NUM_11
|
||||
|
||||
#define I2C_ADDRESS ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_000
|
||||
|
||||
#define DISPLAY_SDA_PIN I2C_SDA_IO
|
||||
#define DISPLAY_SCL_PIN I2C_SCL_IO
|
||||
|
||||
#define DISPLAY_MISO_PIN GPIO_NUM_8
|
||||
#define DISPLAY_MOSI_PIN GPIO_NUM_9
|
||||
#define DISPLAY_SCLK_PIN GPIO_NUM_4
|
||||
#define DISPLAY_CS_PIN GPIO_NUM_3
|
||||
#define DISPLAY_DC_PIN GPIO_NUM_7
|
||||
#define DISPLAY_RESET_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_5
|
||||
|
||||
#define DISPLAY_SPI_SCLK_HZ (20 * 1000 * 1000)
|
||||
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN -1
|
||||
#define CAMERA_PIN_RESET -1
|
||||
#define CAMERA_PIN_XCLK 43
|
||||
#define CAMERA_PIN_SIOD -1
|
||||
#define CAMERA_PIN_SIOC -1
|
||||
|
||||
#define CAMERA_PIN_D7 48
|
||||
#define CAMERA_PIN_D6 47
|
||||
#define CAMERA_PIN_D5 46
|
||||
#define CAMERA_PIN_D4 45
|
||||
#define CAMERA_PIN_D3 39
|
||||
#define CAMERA_PIN_D2 18
|
||||
#define CAMERA_PIN_D1 17
|
||||
#define CAMERA_PIN_D0 2
|
||||
#define CAMERA_PIN_VSYNC 21
|
||||
#define CAMERA_PIN_HREF 1
|
||||
#define CAMERA_PIN_PCLK 44
|
||||
|
||||
#define XCLK_FREQ_HZ 20000000
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_AUDIO_BOARD_LCD_JD9853
|
||||
#define LCD_TYPE_JD9853_SERIAL
|
||||
#define DISPLAY_WIDTH 320
|
||||
#define DISPLAY_HEIGHT 172
|
||||
|
||||
#define DISPLAY_SWAP_XY true
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AUDIO_BOARD_LCD_ST7789
|
||||
#define LCD_TYPE_ST7789_SERIAL
|
||||
#define DISPLAY_WIDTH 240
|
||||
#define DISPLAY_HEIGHT 320
|
||||
|
||||
#define DISPLAY_SWAP_XY false
|
||||
#define DISPLAY_MIRROR_X false
|
||||
#define DISPLAY_MIRROR_Y false
|
||||
#define DISPLAY_INVERT_COLOR true
|
||||
#define BACKLIGHT_INVERT false
|
||||
#define DISPLAY_OFFSET_X 0
|
||||
#define DISPLAY_OFFSET_Y 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "waveshare-s3-audio-board",
|
||||
"sdkconfig_append": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
#include "wifi_board.h"
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "system_reset.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include "i2c_device.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <driver/ledc.h>
|
||||
#include <wifi_station.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_st77916.h>
|
||||
#include <esp_timer.h>
|
||||
#include "esp_io_expander_tca95xx_16bit.h"
|
||||
#include "esp32_camera.h"
|
||||
#include "led/circular_strip.h"
|
||||
#include "esp_lcd_jd9853.h"
|
||||
|
||||
#define TAG "waveshare_lcd_1_85c"
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_READ_CMD (0x0BULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
LV_FONT_DECLARE(font_puhui_14_1);
|
||||
LV_FONT_DECLARE(font_awesome_14_1);
|
||||
|
||||
|
||||
|
||||
|
||||
class CustomBoard : public WifiBoard {
|
||||
private:
|
||||
Button boot_button_;
|
||||
i2c_master_bus_handle_t i2c_bus_;
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
LcdDisplay* display_;
|
||||
Esp32Camera* camera_;
|
||||
|
||||
void InitializeI2c() {
|
||||
// Initialize I2C peripheral
|
||||
i2c_master_bus_config_t i2c_bus_cfg = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = I2C_SDA_IO,
|
||||
.scl_io_num = I2C_SCL_IO,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeTca9555(void)
|
||||
{
|
||||
esp_err_t ret = esp_io_expander_new_i2c_tca95xx_16bit(i2c_bus_, I2C_ADDRESS, &io_expander);
|
||||
if(ret != ESP_OK)
|
||||
ESP_LOGE(TAG, "TCA9554 create returned error"); // 打印引脚状态
|
||||
|
||||
ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 | IO_EXPANDER_PIN_NUM_8|IO_EXPANDER_PIN_NUM_5|IO_EXPANDER_PIN_NUM_6, IO_EXPANDER_OUTPUT); // 设置引脚 EXIO0 和 EXIO1 模式为输出
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 0); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 1); // 复位 LCD 与 TouchPad
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_8, 1); // 启用喇叭功放
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_5, false); // 复位摄像头
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
ret = esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_6, true);
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void InitializeSpi() {
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
|
||||
buscfg.miso_io_num = GPIO_NUM_NC;
|
||||
buscfg.sclk_io_num = DISPLAY_SCLK_PIN;
|
||||
buscfg.quadwp_io_num = GPIO_NUM_NC;
|
||||
buscfg.quadhd_io_num = GPIO_NUM_NC;
|
||||
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
|
||||
void InitializeSt7789Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片ST7789
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR));
|
||||
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_14_1,
|
||||
.icon_font = &font_awesome_14_1,
|
||||
.emoji_font = font_emoji_32_init(),
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeJd9853Display() {
|
||||
esp_lcd_panel_io_handle_t panel_io = nullptr;
|
||||
esp_lcd_panel_handle_t panel = nullptr;
|
||||
// 液晶屏控制IO初始化
|
||||
ESP_LOGD(TAG, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.cs_gpio_num = DISPLAY_CS_PIN;
|
||||
io_config.dc_gpio_num = DISPLAY_DC_PIN;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
||||
io_config.trans_queue_depth = 10;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
|
||||
|
||||
// 初始化液晶屏驱动芯片JD9853
|
||||
ESP_LOGD(TAG, "Install LCD driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = GPIO_NUM_NC;
|
||||
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
|
||||
panel_config.bits_per_pixel = 16;
|
||||
//ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_jd9853(panel_io, &panel_config, &panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, true));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel, 0, 34));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, true, false));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, true));
|
||||
display_ = new SpiLcdDisplay(panel_io, panel,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
|
||||
{
|
||||
.text_font = &font_puhui_14_1,
|
||||
.icon_font = &font_awesome_14_1,
|
||||
.emoji_font = font_emoji_32_init(),
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([this]() {
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
|
||||
ResetWifiConfiguration();
|
||||
}
|
||||
app.ToggleChatState();
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t config = {};
|
||||
config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用
|
||||
config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = CAMERA_PIN_SIOD; // 这里如果写-1 表示使用已经初始化的I2C接口
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 0; // 这里如果写1 默认使用I2C1
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_QVGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
|
||||
camera_ = new Esp32Camera(config);
|
||||
camera_->SetVFlip(1);
|
||||
}
|
||||
public:
|
||||
CustomBoard() :
|
||||
boot_button_(BOOT_BUTTON_GPIO) {
|
||||
InitializeI2c();
|
||||
InitializeTca9555();
|
||||
InitializeSpi();
|
||||
InitializeButtons();
|
||||
#ifdef LCD_TYPE_JD9853_SERIAL
|
||||
InitializeJd9853Display();
|
||||
#else
|
||||
InitializeSt7789Display();
|
||||
#endif
|
||||
InitializeCamera();
|
||||
GetBacklight()->RestoreBrightness();
|
||||
}
|
||||
|
||||
virtual Led* GetLed() override {
|
||||
static CircularStrip led(BUILTIN_LED_GPIO, 6);
|
||||
return &led;
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
static BoxAudioCodec audio_codec(i2c_bus_, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN, AUDIO_CODEC_PA_PIN, AUDIO_CODEC_ES8311_ADDR, AUDIO_CODEC_ES7210_ADDR, AUDIO_INPUT_REFERENCE);
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
|
||||
virtual Backlight* GetBacklight() override {
|
||||
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, BACKLIGHT_INVERT);
|
||||
return &backlight;
|
||||
}
|
||||
|
||||
virtual Camera* GetCamera() override {
|
||||
return camera_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CustomBoard);
|
||||
@@ -1,460 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "esp_lcd_jd9853.h"
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_panel_commands.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
|
||||
static const char *TAG = "JD9853";
|
||||
|
||||
static esp_err_t panel_jd9853_del(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_jd9853_reset(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_jd9853_init(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_jd9853_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data);
|
||||
static esp_err_t panel_jd9853_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);
|
||||
static esp_err_t panel_jd9853_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
|
||||
static esp_err_t panel_jd9853_swap_xy(esp_lcd_panel_t *panel, bool swap_axes);
|
||||
static esp_err_t panel_jd9853_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap);
|
||||
static esp_err_t panel_jd9853_disp_on_off(esp_lcd_panel_t *panel, bool off);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
esp_lcd_panel_t base;
|
||||
esp_lcd_panel_io_handle_t io;
|
||||
int reset_gpio_num;
|
||||
bool reset_level;
|
||||
int x_gap;
|
||||
int y_gap;
|
||||
uint8_t fb_bits_per_pixel;
|
||||
uint8_t madctl_val; // save current value of LCD_CMD_MADCTL register
|
||||
uint8_t colmod_val; // save current value of LCD_CMD_COLMOD register
|
||||
const jd9853_lcd_init_cmd_t *init_cmds;
|
||||
uint16_t init_cmds_size;
|
||||
} jd9853_panel_t;
|
||||
|
||||
esp_err_t esp_lcd_new_panel_jd9853(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
jd9853_panel_t *jd9853 = NULL;
|
||||
gpio_config_t io_conf = {0};
|
||||
|
||||
ESP_GOTO_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
jd9853 = (jd9853_panel_t *)calloc(1, sizeof(jd9853_panel_t));
|
||||
ESP_GOTO_ON_FALSE(jd9853, ESP_ERR_NO_MEM, err, TAG, "no mem for jd9853 panel");
|
||||
|
||||
if (panel_dev_config->reset_gpio_num >= 0)
|
||||
{
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num;
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
switch (panel_dev_config->color_space)
|
||||
{
|
||||
case ESP_LCD_COLOR_SPACE_RGB:
|
||||
jd9853->madctl_val = 0;
|
||||
break;
|
||||
case ESP_LCD_COLOR_SPACE_BGR:
|
||||
jd9853->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color space");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
switch (panel_dev_config->rgb_endian)
|
||||
{
|
||||
case LCD_RGB_ENDIAN_RGB:
|
||||
jd9853->madctl_val = 0;
|
||||
break;
|
||||
case LCD_RGB_ENDIAN_BGR:
|
||||
jd9853->madctl_val |= LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported rgb endian");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (panel_dev_config->bits_per_pixel)
|
||||
{
|
||||
case 16: // RGB565
|
||||
jd9853->colmod_val = 0x55;
|
||||
jd9853->fb_bits_per_pixel = 16;
|
||||
break;
|
||||
case 18: // RGB666
|
||||
jd9853->colmod_val = 0x66;
|
||||
// each color component (R/G/B) should occupy the 6 high bits of a byte, which means 3 full bytes are required for a pixel
|
||||
jd9853->fb_bits_per_pixel = 24;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width");
|
||||
break;
|
||||
}
|
||||
|
||||
jd9853->io = io;
|
||||
jd9853->reset_gpio_num = panel_dev_config->reset_gpio_num;
|
||||
jd9853->reset_level = panel_dev_config->flags.reset_active_high;
|
||||
if (panel_dev_config->vendor_config)
|
||||
{
|
||||
jd9853->init_cmds = ((jd9853_vendor_config_t *)panel_dev_config->vendor_config)->init_cmds;
|
||||
jd9853->init_cmds_size = ((jd9853_vendor_config_t *)panel_dev_config->vendor_config)->init_cmds_size;
|
||||
}
|
||||
jd9853->base.del = panel_jd9853_del;
|
||||
jd9853->base.reset = panel_jd9853_reset;
|
||||
jd9853->base.init = panel_jd9853_init;
|
||||
jd9853->base.draw_bitmap = panel_jd9853_draw_bitmap;
|
||||
jd9853->base.invert_color = panel_jd9853_invert_color;
|
||||
jd9853->base.set_gap = panel_jd9853_set_gap;
|
||||
jd9853->base.mirror = panel_jd9853_mirror;
|
||||
jd9853->base.swap_xy = panel_jd9853_swap_xy;
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
jd9853->base.disp_off = panel_jd9853_disp_on_off;
|
||||
#else
|
||||
jd9853->base.disp_on_off = panel_jd9853_disp_on_off;
|
||||
#endif
|
||||
*ret_panel = &(jd9853->base);
|
||||
ESP_LOGD(TAG, "new jd9853 panel @%p", jd9853);
|
||||
|
||||
// ESP_LOGI(TAG, "LCD panel create success, version: %d.%d.%d", ESP_LCD_jd9853_VER_MAJOR, ESP_LCD_jd9853_VER_MINOR,
|
||||
// ESP_LCD_jd9853_VER_PATCH);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (jd9853)
|
||||
{
|
||||
if (panel_dev_config->reset_gpio_num >= 0)
|
||||
{
|
||||
gpio_reset_pin(panel_dev_config->reset_gpio_num);
|
||||
}
|
||||
free(jd9853);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_del(esp_lcd_panel_t *panel)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
|
||||
if (jd9853->reset_gpio_num >= 0)
|
||||
{
|
||||
gpio_reset_pin(jd9853->reset_gpio_num);
|
||||
}
|
||||
ESP_LOGD(TAG, "del jd9853 panel @%p", jd9853);
|
||||
free(jd9853);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_reset(esp_lcd_panel_t *panel)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
|
||||
// perform hardware reset
|
||||
if (jd9853->reset_gpio_num >= 0)
|
||||
{
|
||||
gpio_set_level(jd9853->reset_gpio_num, jd9853->reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(jd9853->reset_gpio_num, !jd9853->reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
else
|
||||
{ // perform software reset
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); // spec, wait at least 5ms before sending new command
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cmd;
|
||||
uint8_t data[16];
|
||||
uint8_t data_bytes; // Length of data in above data array; 0xFF = end of cmds.
|
||||
} lcd_init_cmd_t;
|
||||
|
||||
// static const jd9853_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
// // {cmd, { data }, data_size, delay_ms}
|
||||
// /* Power contorl B, power control = 0, DC_ENA = 1 */
|
||||
// {0xCF, (uint8_t []){0x00, 0xAA, 0XE0}, 3, 0},
|
||||
// /* Power on sequence control,
|
||||
// * cp1 keeps 1 frame, 1st frame enable
|
||||
// * vcl = 0, ddvdh=3, vgh=1, vgl=2
|
||||
// * DDVDH_ENH=1
|
||||
// */
|
||||
// {0xED, (uint8_t []){0x67, 0x03, 0X12, 0X81}, 4, 0},
|
||||
// /* Driver timing control A,
|
||||
// * non-overlap=default +1
|
||||
// * EQ=default - 1, CR=default
|
||||
// * pre-charge=default - 1
|
||||
// */
|
||||
// {0xE8, (uint8_t []){0x8A, 0x01, 0x78}, 3, 0},
|
||||
// /* Power control A, Vcore=1.6V, DDVDH=5.6V */
|
||||
// {0xCB, (uint8_t []){0x39, 0x2C, 0x00, 0x34, 0x02}, 5, 0},
|
||||
// /* Pump ratio control, DDVDH=2xVCl */
|
||||
// {0xF7, (uint8_t []){0x20}, 1, 0},
|
||||
|
||||
// {0xF7, (uint8_t []){0x20}, 1, 0},
|
||||
// /* Driver timing control, all=0 unit */
|
||||
// {0xEA, (uint8_t []){0x00, 0x00}, 2, 0},
|
||||
// /* Power control 1, GVDD=4.75V */
|
||||
// {0xC0, (uint8_t []){0x23}, 1, 0},
|
||||
// /* Power control 2, DDVDH=VCl*2, VGH=VCl*7, VGL=-VCl*3 */
|
||||
// {0xC1, (uint8_t []){0x11}, 1, 0},
|
||||
// /* VCOM control 1, VCOMH=4.025V, VCOML=-0.950V */
|
||||
// {0xC5, (uint8_t []){0x43, 0x4C}, 2, 0},
|
||||
// /* VCOM control 2, VCOMH=VMH-2, VCOML=VML-2 */
|
||||
// {0xC7, (uint8_t []){0xA0}, 1, 0},
|
||||
// /* Frame rate control, f=fosc, 70Hz fps */
|
||||
// {0xB1, (uint8_t []){0x00, 0x1B}, 2, 0},
|
||||
// /* Enable 3G, disabled */
|
||||
// {0xF2, (uint8_t []){0x00}, 1, 0},
|
||||
// /* Gamma set, curve 1 */
|
||||
// {0x26, (uint8_t []){0x01}, 1, 0},
|
||||
// /* Positive gamma correction */
|
||||
// {0xE0, (uint8_t []){0x1F, 0x36, 0x36, 0x3A, 0x0C, 0x05, 0x4F, 0X87, 0x3C, 0x08, 0x11, 0x35, 0x19, 0x13, 0x00}, 15, 0},
|
||||
// /* Negative gamma correction */
|
||||
// {0xE1, (uint8_t []){0x00, 0x09, 0x09, 0x05, 0x13, 0x0A, 0x30, 0x78, 0x43, 0x07, 0x0E, 0x0A, 0x26, 0x2C, 0x1F}, 15, 0},
|
||||
// /* Entry mode set, Low vol detect disabled, normal display */
|
||||
// {0xB7, (uint8_t []){0x07}, 1, 0},
|
||||
// /* Display function control */
|
||||
// {0xB6, (uint8_t []){0x08, 0x82, 0x27}, 3, 0},
|
||||
// };
|
||||
|
||||
static const jd9853_lcd_init_cmd_t vendor_specific_init_default[] = {
|
||||
{0x11, (uint8_t []){ 0x00 }, 0, 120},
|
||||
{0xDF, (uint8_t[]){0x98, 0x53}, 2, 0},
|
||||
{0xDF, (uint8_t[]){0x98, 0x53}, 2, 0},
|
||||
{0xB2, (uint8_t[]){0x23}, 1, 0},
|
||||
{0xB7, (uint8_t[]){0x00, 0x47, 0x00, 0x6F}, 4, 0},
|
||||
{0xBB, (uint8_t[]){0x1C, 0x1A, 0x55, 0x73, 0x63, 0xF0}, 6, 0},
|
||||
{0xC0, (uint8_t[]){0x44, 0xA4}, 2, 0},
|
||||
{0xC1, (uint8_t[]){0x16}, 1, 0},
|
||||
{0xC3, (uint8_t[]){0x7D, 0x07, 0x14, 0x06, 0xCF, 0x71, 0x72, 0x77}, 8, 0},
|
||||
{0xC4, (uint8_t[]){0x00, 0x00, 0xA0, 0x79, 0x0B, 0x0A, 0x16, 0x79, 0x0B, 0x0A, 0x16, 0x82}, 12, 0}, // 00=60Hz 06=57Hz 08=51Hz, LN=320 Line
|
||||
{0xC8, (uint8_t[]){0x3F, 0x32, 0x29, 0x29, 0x27, 0x2B, 0x27, 0x28, 0x28, 0x26, 0x25, 0x17, 0x12, 0x0D, 0x04, 0x00, 0x3F, 0x32, 0x29, 0x29, 0x27, 0x2B, 0x27, 0x28, 0x28, 0x26, 0x25, 0x17, 0x12, 0x0D, 0x04, 0x00}, 32, 0}, // SET_R_GAMMA
|
||||
{0xD0, (uint8_t[]){0x04, 0x06, 0x6B, 0x0F, 0x00}, 5, 0},
|
||||
{0xD7, (uint8_t[]){0x00, 0x30}, 2, 0},
|
||||
{0xE6, (uint8_t[]){0x14}, 1, 0},
|
||||
{0xDE, (uint8_t[]){0x01}, 1, 0},
|
||||
{0xB7, (uint8_t[]){0x03, 0x13, 0xEF, 0x35, 0x35}, 5, 0},
|
||||
{0xC1, (uint8_t[]){0x14, 0x15, 0xC0}, 3, 0},
|
||||
{0xC2, (uint8_t[]){0x06, 0x3A}, 2, 0},
|
||||
{0xC4, (uint8_t[]){0x72, 0x12}, 2, 0},
|
||||
{0xBE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xDE, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xE5, (uint8_t[]){0x00, 0x02, 0x00}, 3, 0},
|
||||
{0xE5, (uint8_t[]){0x01, 0x02, 0x00}, 3, 0},
|
||||
{0xDE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x35, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x3A, (uint8_t[]){0x05}, 1, 0}, // 06=RGB666;05=RGB565
|
||||
{0x2A, (uint8_t[]){0x00, 0x22, 0x00, 0xCD}, 4, 0}, // Start_X=34, End_X=205
|
||||
{0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0x3F}, 4, 0}, // Start_Y=0, End_Y=319
|
||||
{0xDE, (uint8_t[]){0x02}, 1, 0},
|
||||
{0xE5, (uint8_t[]){0x00, 0x02, 0x00}, 3, 0},
|
||||
{0xDE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x29, (uint8_t []){ 0x00 }, 0, 0},
|
||||
};
|
||||
|
||||
static esp_err_t panel_jd9853_init(esp_lcd_panel_t *panel)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
|
||||
// LCD goes into sleep mode and display will be turned off after power on reset, exit sleep mode first
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_SLPOUT, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]){
|
||||
jd9853->madctl_val,
|
||||
},
|
||||
1),
|
||||
TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_COLMOD, (uint8_t[]){
|
||||
jd9853->colmod_val,
|
||||
},
|
||||
1),
|
||||
TAG, "send command failed");
|
||||
|
||||
const jd9853_lcd_init_cmd_t *init_cmds = NULL;
|
||||
uint16_t init_cmds_size = 0;
|
||||
if (jd9853->init_cmds)
|
||||
{
|
||||
init_cmds = jd9853->init_cmds;
|
||||
init_cmds_size = jd9853->init_cmds_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
init_cmds = vendor_specific_init_default;
|
||||
init_cmds_size = sizeof(vendor_specific_init_default) / sizeof(jd9853_lcd_init_cmd_t);
|
||||
}
|
||||
|
||||
bool is_cmd_overwritten = false;
|
||||
for (int i = 0; i < init_cmds_size; i++)
|
||||
{
|
||||
// Check if the command has been used or conflicts with the internal
|
||||
switch (init_cmds[i].cmd)
|
||||
{
|
||||
case LCD_CMD_MADCTL:
|
||||
is_cmd_overwritten = true;
|
||||
jd9853->madctl_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
case LCD_CMD_COLMOD:
|
||||
is_cmd_overwritten = true;
|
||||
jd9853->colmod_val = ((uint8_t *)init_cmds[i].data)[0];
|
||||
break;
|
||||
default:
|
||||
is_cmd_overwritten = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_cmd_overwritten)
|
||||
{
|
||||
ESP_LOGW(TAG, "The %02Xh command has been used and will be overwritten by external initialization sequence", init_cmds[i].cmd);
|
||||
}
|
||||
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, init_cmds[i].cmd, init_cmds[i].data, init_cmds[i].data_bytes), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(init_cmds[i].delay_ms));
|
||||
}
|
||||
ESP_LOGD(TAG, "send init commands success");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
|
||||
x_start += jd9853->x_gap;
|
||||
x_end += jd9853->x_gap;
|
||||
y_start += jd9853->y_gap;
|
||||
y_end += jd9853->y_gap;
|
||||
|
||||
// define an area of frame memory where MCU can access
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_CASET, (uint8_t[]){
|
||||
(x_start >> 8) & 0xFF,
|
||||
x_start & 0xFF,
|
||||
((x_end - 1) >> 8) & 0xFF,
|
||||
(x_end - 1) & 0xFF,
|
||||
},
|
||||
4),
|
||||
TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_RASET, (uint8_t[]){
|
||||
(y_start >> 8) & 0xFF,
|
||||
y_start & 0xFF,
|
||||
((y_end - 1) >> 8) & 0xFF,
|
||||
(y_end - 1) & 0xFF,
|
||||
},
|
||||
4),
|
||||
TAG, "send command failed");
|
||||
// transfer frame buffer
|
||||
size_t len = (x_end - x_start) * (y_end - y_start) * jd9853->fb_bits_per_pixel / 8;
|
||||
esp_lcd_panel_io_tx_color(io, LCD_CMD_RAMWR, color_data, len);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
int command = 0;
|
||||
if (invert_color_data)
|
||||
{
|
||||
command = LCD_CMD_INVON;
|
||||
}
|
||||
else
|
||||
{
|
||||
command = LCD_CMD_INVOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
if (mirror_x)
|
||||
{
|
||||
jd9853->madctl_val |= LCD_CMD_MX_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
jd9853->madctl_val &= ~LCD_CMD_MX_BIT;
|
||||
}
|
||||
if (mirror_y)
|
||||
{
|
||||
jd9853->madctl_val |= LCD_CMD_MY_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
jd9853->madctl_val &= ~LCD_CMD_MY_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]){jd9853->madctl_val}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_swap_xy(esp_lcd_panel_t *panel, bool swap_axes)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
if (swap_axes)
|
||||
{
|
||||
jd9853->madctl_val |= LCD_CMD_MV_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
jd9853->madctl_val &= ~LCD_CMD_MV_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, LCD_CMD_MADCTL, (uint8_t[]){jd9853->madctl_val}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
jd9853->x_gap = x_gap;
|
||||
jd9853->y_gap = y_gap;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_jd9853_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
||||
{
|
||||
jd9853_panel_t *jd9853 = __containerof(panel, jd9853_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = jd9853->io;
|
||||
int command = 0;
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
on_off = !on_off;
|
||||
#endif
|
||||
|
||||
if (on_off)
|
||||
{
|
||||
command = LCD_CMD_DISPON;
|
||||
}
|
||||
else
|
||||
{
|
||||
command = LCD_CMD_DISPOFF;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_tx_param(io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief ESP LCD: jd9853
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/spi_ll.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LCD panel initialization commands.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
int cmd; /*<! The specific LCD command */
|
||||
const void *data; /*<! Buffer that holds the command specific data */
|
||||
size_t data_bytes; /*<! Size of `data` in memory, in bytes */
|
||||
unsigned int delay_ms; /*<! Delay in milliseconds after this command */
|
||||
} jd9853_lcd_init_cmd_t;
|
||||
|
||||
/**
|
||||
* @brief LCD panel vendor configuration.
|
||||
*
|
||||
* @note This structure needs to be passed to the `vendor_config` field in `esp_lcd_panel_dev_config_t`.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
const jd9853_lcd_init_cmd_t *init_cmds; /*!< Pointer to initialization commands array. Set to NULL if using default commands.
|
||||
* The array should be declared as `static const` and positioned outside the function.
|
||||
* Please refer to `vendor_specific_init_default` in source file.
|
||||
*/
|
||||
uint16_t init_cmds_size; /*<! Number of commands in above array */
|
||||
} jd9853_vendor_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create LCD panel for model jd9853
|
||||
*
|
||||
* @note Vendor specific initialization can be different between manufacturers, should consult the LCD supplier for initialization sequence code.
|
||||
*
|
||||
* @param[in] io LCD panel IO handle
|
||||
* @param[in] panel_dev_config general panel device configuration
|
||||
* @param[out] ret_panel Returned LCD panel handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_NO_MEM if out of memory
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_new_panel_jd9853(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel);
|
||||
|
||||
/**
|
||||
* @brief LCD panel bus configuration structure
|
||||
*
|
||||
* @param[in] sclk SPI clock pin number
|
||||
* @param[in] mosi SPI MOSI pin number
|
||||
* @param[in] max_trans_sz Maximum transfer size in bytes
|
||||
*
|
||||
*/
|
||||
#define JD9853_PANEL_BUS_SPI_CONFIG(sclk, mosi, max_trans_sz) \
|
||||
{ \
|
||||
.sclk_io_num = sclk, \
|
||||
.mosi_io_num = mosi, \
|
||||
.miso_io_num = -1, \
|
||||
.quadhd_io_num = -1, \
|
||||
.quadwp_io_num = -1, \
|
||||
.max_transfer_sz = max_trans_sz, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LCD panel IO configuration structure
|
||||
*
|
||||
* @param[in] cs SPI chip select pin number
|
||||
* @param[in] dc SPI data/command pin number
|
||||
* @param[in] cb Callback function when SPI transfer is done
|
||||
* @param[in] cb_ctx Callback function context
|
||||
*
|
||||
*/
|
||||
#define JD9853_PANEL_IO_SPI_CONFIG(cs, dc, callback, callback_ctx) \
|
||||
{ \
|
||||
.cs_gpio_num = cs, \
|
||||
.dc_gpio_num = dc, \
|
||||
.spi_mode = 0, \
|
||||
.pclk_hz = 40 * 1000 * 1000, \
|
||||
.trans_queue_depth = 10, \
|
||||
.on_color_trans_done = callback, \
|
||||
.user_ctx = callback_ctx, \
|
||||
.lcd_cmd_bits = 8, \
|
||||
.lcd_param_bits = 8, \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "wifi_board.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "application.h"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "wifi_board.h"
|
||||
#include "display/lcd_display.h"
|
||||
#include "esp_lcd_sh8601.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
|
||||
#include "codecs/box_audio_codec.h"
|
||||
#include "application.h"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "lcd_display.h"
|
||||
|
||||
#include <vector>
|
||||
#include <font_awesome_symbols.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
@@ -349,4 +350,4 @@ CustomLcdDisplay::CustomLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_p
|
||||
}
|
||||
|
||||
SetupUI();
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "settings.h"
|
||||
#include "config.h"
|
||||
#include "sleep_timer.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "adc_battery_monitor.h"
|
||||
#include "press_to_talk_mcp_tool.h"
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "settings.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "adc_battery_monitor.h"
|
||||
#include "press_to_talk_mcp_tool.h"
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "settings.h"
|
||||
#include "config.h"
|
||||
#include "power_save_timer.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "press_to_talk_mcp_tool.h"
|
||||
|
||||
#include <wifi_station.h>
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
|
||||
void SetupHighTempWarningPopup() {
|
||||
// 创建高温警告弹窗
|
||||
high_temp_popup_ = lv_obj_create(lv_screen_active()); // 使用当前屏幕
|
||||
high_temp_popup_ = lv_obj_create(lv_scr_act()); // 使用当前屏幕
|
||||
lv_obj_set_scrollbar_mode(high_temp_popup_, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_obj_set_size(high_temp_popup_, LV_HOR_RES * 0.9, fonts_.text_font->line_height * 2);
|
||||
lv_obj_align(high_temp_popup_, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
void ShowHighTempWarning() {
|
||||
if (high_temp_popup_ && lv_obj_has_flag(high_temp_popup_, LV_OBJ_FLAG_HIDDEN)) {
|
||||
lv_obj_remove_flag(high_temp_popup_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(high_temp_popup_, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <font_awesome.h>
|
||||
|
||||
#include "display.h"
|
||||
#include "board.h"
|
||||
#include "application.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "audio_codec.h"
|
||||
#include "settings.h"
|
||||
#include "assets/lang_config.h"
|
||||
@@ -21,7 +21,7 @@ Display::Display() {
|
||||
Display *display = static_cast<Display*>(arg);
|
||||
DisplayLockGuard lock(display);
|
||||
lv_obj_add_flag(display->notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_remove_flag(display->status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(display->status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
},
|
||||
.arg = this,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
@@ -67,7 +67,7 @@ void Display::SetStatus(const char* status) {
|
||||
return;
|
||||
}
|
||||
lv_label_set_text(status_label_, status);
|
||||
lv_obj_remove_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
last_status_update_time_ = std::chrono::system_clock::now();
|
||||
@@ -83,7 +83,7 @@ void Display::ShowNotification(const char* notification, int duration_ms) {
|
||||
return;
|
||||
}
|
||||
lv_label_set_text(notification_label_, notification);
|
||||
lv_obj_remove_flag(notification_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
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_);
|
||||
@@ -105,7 +105,7 @@ void Display::UpdateStatusBar(bool update_all) {
|
||||
// 如果静音状态改变,则更新图标
|
||||
if (codec->output_volume() == 0 && !muted_) {
|
||||
muted_ = true;
|
||||
lv_label_set_text(mute_label_, FONT_AWESOME_VOLUME_XMARK);
|
||||
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_, "");
|
||||
@@ -136,13 +136,13 @@ void Display::UpdateStatusBar(bool update_all) {
|
||||
const char* icon = nullptr;
|
||||
if (board.GetBatteryLevel(battery_level, charging, discharging)) {
|
||||
if (charging) {
|
||||
icon = FONT_AWESOME_BATTERY_BOLT;
|
||||
icon = FONT_AWESOME_BATTERY_CHARGING;
|
||||
} else {
|
||||
const char* levels[] = {
|
||||
FONT_AWESOME_BATTERY_EMPTY, // 0-19%
|
||||
FONT_AWESOME_BATTERY_QUARTER, // 20-39%
|
||||
FONT_AWESOME_BATTERY_HALF, // 40-59%
|
||||
FONT_AWESOME_BATTERY_THREE_QUARTERS, // 60-79%
|
||||
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%
|
||||
};
|
||||
@@ -157,7 +157,7 @@ void Display::UpdateStatusBar(bool update_all) {
|
||||
if (low_battery_popup_ != nullptr) {
|
||||
if (strcmp(icon, FONT_AWESOME_BATTERY_EMPTY) == 0 && discharging) {
|
||||
if (lv_obj_has_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN)) { // 如果低电量提示框隐藏,则显示
|
||||
lv_obj_remove_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN);
|
||||
app.PlaySound(Lang::Sounds::OGG_LOW_BATTERY);
|
||||
}
|
||||
} else {
|
||||
@@ -196,11 +196,50 @@ void Display::UpdateStatusBar(bool update_all) {
|
||||
|
||||
|
||||
void Display::SetEmotion(const char* emotion) {
|
||||
const char* utf8 = font_awesome_get_utf8(emotion);
|
||||
if (utf8 != nullptr) {
|
||||
SetIcon(utf8);
|
||||
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"}
|
||||
};
|
||||
|
||||
// 查找匹配的表情
|
||||
std::string_view emotion_view(emotion);
|
||||
auto it = std::find_if(emotions.begin(), emotions.end(),
|
||||
[&emotion_view](const Emotion& e) { return e.text == emotion_view; });
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
if (emotion_label_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果找到匹配的表情就显示对应图标,否则显示默认的neutral表情
|
||||
if (it != emotions.end()) {
|
||||
lv_label_set_text(emotion_label_, it->icon);
|
||||
} else {
|
||||
SetIcon(FONT_AWESOME_NEUTRAL);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_EMOJI_NEUTRAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#include "lcd_display.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <font_awesome.h>
|
||||
#include <font_awesome_symbols.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <esp_psram.h>
|
||||
#include <esp_heap_caps.h>
|
||||
#include "assets/lang_config.h"
|
||||
#include <cstring>
|
||||
#include "settings.h"
|
||||
|
||||
#include "board.h"
|
||||
|
||||
@@ -102,24 +102,10 @@ SpiLcdDisplay::SpiLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_h
|
||||
ESP_LOGI(TAG, "Initialize LVGL library");
|
||||
lv_init();
|
||||
|
||||
#if CONFIG_SPIRAM
|
||||
// lv image cache, currently only PNG is supported
|
||||
size_t psram_size_mb = esp_psram_get_size() / 1024 / 1024;
|
||||
if (psram_size_mb >= 8) {
|
||||
lv_image_cache_resize(2 * 1024 * 1024, true);
|
||||
ESP_LOGI(TAG, "Use 2MB of PSRAM for image cache");
|
||||
} else if (psram_size_mb >= 2) {
|
||||
lv_image_cache_resize(512 * 1024, true);
|
||||
ESP_LOGI(TAG, "Use 512KB of PSRAM for image cache");
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Initialize LVGL port");
|
||||
lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
port_cfg.task_priority = 1;
|
||||
#if CONFIG_SOC_CPU_CORES_NUM > 1
|
||||
port_cfg.task_affinity = 1;
|
||||
#endif
|
||||
port_cfg.timer_period_ms = 50;
|
||||
lvgl_port_init(&port_cfg);
|
||||
|
||||
ESP_LOGI(TAG, "Adding LCD display");
|
||||
@@ -181,9 +167,7 @@ RgbLcdDisplay::RgbLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_h
|
||||
ESP_LOGI(TAG, "Initialize LVGL port");
|
||||
lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
port_cfg.task_priority = 1;
|
||||
#if CONFIG_SOC_CPU_CORES_NUM > 1
|
||||
port_cfg.task_affinity = 1;
|
||||
#endif
|
||||
port_cfg.timer_period_ms = 50;
|
||||
lvgl_port_init(&port_cfg);
|
||||
|
||||
ESP_LOGI(TAG, "Adding LCD display");
|
||||
@@ -242,10 +226,6 @@ MipiLcdDisplay::MipiLcdDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel
|
||||
|
||||
ESP_LOGI(TAG, "Initialize LVGL port");
|
||||
lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
port_cfg.task_priority = 1;
|
||||
#if CONFIG_SOC_CPU_CORES_NUM > 1
|
||||
port_cfg.task_affinity = 1;
|
||||
#endif
|
||||
lvgl_port_init(&port_cfg);
|
||||
|
||||
ESP_LOGI(TAG, "Adding LCD display");
|
||||
@@ -387,7 +367,7 @@ void LcdDisplay::SetupUI() {
|
||||
emotion_label_ = lv_label_create(status_bar_);
|
||||
lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_4, 0);
|
||||
lv_obj_set_style_text_color(emotion_label_, current_theme_.text, 0);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_MICROCHIP_AI);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP);
|
||||
lv_obj_set_style_margin_right(emotion_label_, 5, 0); // 添加右边距,与后面的元素分隔
|
||||
|
||||
notification_label_ = lv_label_create(status_bar_);
|
||||
@@ -641,7 +621,7 @@ void LcdDisplay::SetPreviewImage(const lv_img_dsc_t* img_dsc) {
|
||||
|
||||
// 设置自定义属性标记气泡类型
|
||||
lv_obj_set_user_data(img_bubble, (void*)"image");
|
||||
|
||||
|
||||
// Create the image object inside the bubble
|
||||
lv_obj_t* preview_image = lv_image_create(img_bubble);
|
||||
|
||||
@@ -764,7 +744,7 @@ void LcdDisplay::SetupUI() {
|
||||
emotion_label_ = lv_label_create(content_);
|
||||
lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_4, 0);
|
||||
lv_obj_set_style_text_color(emotion_label_, current_theme_.text, 0);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_MICROCHIP_AI);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP);
|
||||
|
||||
preview_image_ = lv_image_create(content_);
|
||||
lv_obj_set_size(preview_image_, width_ * 0.5, height_ * 0.5);
|
||||
@@ -834,13 +814,11 @@ void LcdDisplay::SetPreviewImage(const lv_img_dsc_t* img_dsc) {
|
||||
}
|
||||
|
||||
if (img_dsc != nullptr) {
|
||||
// zoom factor 0.5
|
||||
lv_image_set_scale(preview_image_, 128 * width_ / img_dsc->header.w);
|
||||
// 设置图片源并显示预览图片
|
||||
lv_image_set_src(preview_image_, img_dsc);
|
||||
if (img_dsc->header.w > 0) {
|
||||
// zoom factor 0.5
|
||||
lv_image_set_scale(preview_image_, 128 * width_ / img_dsc->header.w);
|
||||
}
|
||||
lv_obj_remove_flag(preview_image_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(preview_image_, LV_OBJ_FLAG_HIDDEN);
|
||||
// 隐藏emotion_label_
|
||||
if (emotion_label_ != nullptr) {
|
||||
lv_obj_add_flag(emotion_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
@@ -849,7 +827,7 @@ void LcdDisplay::SetPreviewImage(const lv_img_dsc_t* img_dsc) {
|
||||
// 隐藏预览图片并显示emotion_label_
|
||||
lv_obj_add_flag(preview_image_, LV_OBJ_FLAG_HIDDEN);
|
||||
if (emotion_label_ != nullptr) {
|
||||
lv_obj_remove_flag(emotion_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(emotion_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -889,13 +867,6 @@ void LcdDisplay::SetEmotion(const char* emotion) {
|
||||
std::string_view emotion_view(emotion);
|
||||
auto it = std::find_if(emotions.begin(), emotions.end(),
|
||||
[&emotion_view](const Emotion& e) { return e.text == emotion_view; });
|
||||
if (fonts_.emoji_font == nullptr || it == emotions.end()) {
|
||||
const char* utf8 = font_awesome_get_utf8(emotion);
|
||||
if (utf8 != nullptr) {
|
||||
SetIcon(utf8);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayLockGuard lock(this);
|
||||
if (emotion_label_ == nullptr) {
|
||||
@@ -912,7 +883,7 @@ void LcdDisplay::SetEmotion(const char* emotion) {
|
||||
|
||||
#if !CONFIG_USE_WECHAT_MESSAGE_STYLE
|
||||
// 显示emotion_label_,隐藏preview_image_
|
||||
lv_obj_remove_flag(emotion_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(emotion_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
if (preview_image_ != nullptr) {
|
||||
lv_obj_add_flag(preview_image_, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
@@ -929,7 +900,7 @@ void LcdDisplay::SetIcon(const char* icon) {
|
||||
|
||||
#if !CONFIG_USE_WECHAT_MESSAGE_STYLE
|
||||
// 显示emotion_label_,隐藏preview_image_
|
||||
lv_obj_remove_flag(emotion_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(emotion_label_, LV_OBJ_FLAG_HIDDEN);
|
||||
if (preview_image_ != nullptr) {
|
||||
lv_obj_add_flag(preview_image_, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "oled_display.h"
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <string>
|
||||
@@ -7,7 +8,6 @@
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <font_awesome.h>
|
||||
|
||||
#define TAG "OledDisplay"
|
||||
|
||||
@@ -23,9 +23,7 @@ OledDisplay::OledDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handl
|
||||
lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||||
port_cfg.task_priority = 1;
|
||||
port_cfg.task_stack = 6144;
|
||||
#if CONFIG_SOC_CPU_CORES_NUM > 1
|
||||
port_cfg.task_affinity = 1;
|
||||
#endif
|
||||
port_cfg.timer_period_ms = 50;
|
||||
lvgl_port_init(&port_cfg);
|
||||
|
||||
ESP_LOGI(TAG, "Adding OLED display");
|
||||
@@ -114,7 +112,7 @@ void OledDisplay::SetChatMessage(const char* role, const char* content) {
|
||||
lv_obj_add_flag(content_right_, LV_OBJ_FLAG_HIDDEN);
|
||||
} else {
|
||||
lv_label_set_text(chat_message_label_, content_str.c_str());
|
||||
lv_obj_remove_flag(content_right_, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(content_right_, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,7 +157,7 @@ void OledDisplay::SetupUI_128x64() {
|
||||
|
||||
emotion_label_ = lv_label_create(content_left_);
|
||||
lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_1, 0);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_MICROCHIP_AI);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP);
|
||||
lv_obj_center(emotion_label_);
|
||||
lv_obj_set_style_pad_top(emotion_label_, 8, 0);
|
||||
|
||||
@@ -251,7 +249,7 @@ void OledDisplay::SetupUI_128x32() {
|
||||
|
||||
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_MICROCHIP_AI);
|
||||
lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP);
|
||||
lv_obj_center(emotion_label_);
|
||||
|
||||
/* Right side */
|
||||
|
||||
@@ -13,27 +13,26 @@ dependencies:
|
||||
espressif/esp_io_expander_tca9554: ==2.0.0
|
||||
espressif/esp_lcd_panel_io_additions: ^1.0.1
|
||||
78/esp_lcd_nv3023: ~1.0.0
|
||||
78/esp-wifi-connect: ~2.6.1
|
||||
78/esp-wifi-connect: ~2.5.0
|
||||
78/esp-opus-encoder: ~2.4.1
|
||||
78/esp-ml307: ~3.3.7
|
||||
78/xiaozhi-fonts: ~1.5.2
|
||||
espressif/led_strip: ~3.0.1
|
||||
espressif/esp_codec_dev: ~1.4.0
|
||||
espressif/esp-sr: ~2.1.5
|
||||
78/esp-ml307: ~3.2.6
|
||||
78/xiaozhi-fonts: ~1.4.0
|
||||
espressif/led_strip: ^2.5.5
|
||||
espressif/esp_codec_dev: ~1.3.6
|
||||
espressif/esp-sr: ~2.1.4
|
||||
espressif/button: ~4.1.3
|
||||
espressif/knob: ^1.0.0
|
||||
espressif/esp32-camera: ~2.1.2
|
||||
espressif/esp32-camera: ^2.0.15
|
||||
espressif/esp_lcd_touch_ft5x06: ~1.0.7
|
||||
espressif/esp_lcd_touch_gt911: ^1
|
||||
espressif/esp_lcd_touch_gt1151: ^1
|
||||
waveshare/esp_lcd_touch_cst9217: ^1.0.3
|
||||
espressif/esp_lcd_touch_cst816s: ^1.0.6
|
||||
lvgl/lvgl: ~9.3.0
|
||||
lvgl/lvgl: ~9.2.2
|
||||
esp_lvgl_port: ~2.6.0
|
||||
espressif/esp_io_expander_tca95xx_16bit: ^2.0.0
|
||||
espressif2022/image_player: ^1.1.1
|
||||
espressif2022/esp_emote_gfx: ^1.0.2
|
||||
espressif/adc_mic: ^0.2.1
|
||||
espressif2022/image_player: ==1.1.0~1
|
||||
espressif2022/esp_emote_gfx: ^1.0.0
|
||||
espressif/adc_mic: ^0.2.0
|
||||
espressif/esp_mmap_assets: '>=1.2'
|
||||
txp666/otto-emoji-gif-component: ~1.0.2
|
||||
espressif/adc_battery_estimation: ^0.2.0
|
||||
@@ -62,7 +61,7 @@ dependencies:
|
||||
rules:
|
||||
- if: target in [esp32p4]
|
||||
espressif/esp_hosted:
|
||||
version: 2.0.17
|
||||
version: '2.0.17'
|
||||
rules:
|
||||
- if: target in [esp32h2, esp32p4]
|
||||
espressif/esp_wifi_remote:
|
||||
|
||||
@@ -15,7 +15,7 @@ CircularStrip::CircularStrip(gpio_num_t gpio, uint8_t max_leds) : max_leds_(max_
|
||||
led_strip_config_t strip_config = {};
|
||||
strip_config.strip_gpio_num = gpio;
|
||||
strip_config.max_leds = max_leds_;
|
||||
strip_config.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB;
|
||||
strip_config.led_pixel_format = LED_PIXEL_FORMAT_GRB;
|
||||
strip_config.led_model = LED_MODEL_WS2812;
|
||||
|
||||
led_strip_rmt_config_t rmt_config = {};
|
||||
|
||||
@@ -18,7 +18,7 @@ SingleLed::SingleLed(gpio_num_t gpio) {
|
||||
led_strip_config_t strip_config = {};
|
||||
strip_config.strip_gpio_num = gpio;
|
||||
strip_config.max_leds = 1;
|
||||
strip_config.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB;
|
||||
strip_config.led_pixel_format = LED_PIXEL_FORMAT_GRB;
|
||||
strip_config.led_model = LED_MODEL_WS2812;
|
||||
|
||||
led_strip_rmt_config_t rmt_config = {};
|
||||
|
||||
@@ -27,4 +27,5 @@ extern "C" void app_main(void)
|
||||
// Launch the application
|
||||
auto& app = Application::GetInstance();
|
||||
app.Start();
|
||||
app.MainEventLoop();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#define TAG "MCP"
|
||||
|
||||
#define DEFAULT_TOOLCALL_STACK_SIZE 6144
|
||||
|
||||
McpServer::McpServer() {
|
||||
}
|
||||
|
||||
@@ -27,17 +29,12 @@ McpServer::~McpServer() {
|
||||
}
|
||||
|
||||
void McpServer::AddCommonTools() {
|
||||
// *Important* To speed up the response time, we add the common tools to the beginning of
|
||||
// To speed up the response time, we add the common tools to the beginning of
|
||||
// the tools list to utilize the prompt cache.
|
||||
// **重要** 为了提升响应速度,我们把常用的工具放在前面,利用 prompt cache 的特性。
|
||||
|
||||
// Backup the original tools list and restore it after adding the common tools.
|
||||
auto original_tools = std::move(tools_);
|
||||
auto& board = Board::GetInstance();
|
||||
|
||||
// Do not add custom tools here.
|
||||
// Custom tools must be added in the board's InitializeTools function.
|
||||
|
||||
AddTool("self.get_device_status",
|
||||
"Provides the real-time information of the device, including the current status of the audio speaker, screen, battery, network, etc.\n"
|
||||
"Use this tool for: \n"
|
||||
@@ -98,9 +95,6 @@ void McpServer::AddCommonTools() {
|
||||
Property("question", kPropertyTypeString)
|
||||
}),
|
||||
[camera](const PropertyList& properties) -> ReturnValue {
|
||||
// Lower the priority to do the camera capture
|
||||
TaskPriorityReset priority_reset(1);
|
||||
|
||||
if (!camera->Capture()) {
|
||||
return "{\"success\": false, \"message\": \"Failed to capture photo\"}";
|
||||
}
|
||||
@@ -128,12 +122,6 @@ void McpServer::AddTool(const std::string& name, const std::string& description,
|
||||
AddTool(new McpTool(name, description, properties, callback));
|
||||
}
|
||||
|
||||
void McpServer::AddUserOnlyTool(const std::string& name, const std::string& description, const PropertyList& properties, std::function<ReturnValue(const PropertyList&)> callback) {
|
||||
auto tool = new McpTool(name, description, properties, callback);
|
||||
tool->set_user_only(true);
|
||||
AddTool(tool);
|
||||
}
|
||||
|
||||
void McpServer::ParseMessage(const std::string& message) {
|
||||
cJSON* json = cJSON_Parse(message.c_str());
|
||||
if (json == nullptr) {
|
||||
@@ -236,7 +224,13 @@ void McpServer::ParseMessage(const cJSON* json) {
|
||||
ReplyError(id_int, "Invalid arguments");
|
||||
return;
|
||||
}
|
||||
DoToolCall(id_int, std::string(tool_name->valuestring), tool_arguments);
|
||||
auto stack_size = cJSON_GetObjectItem(params, "stackSize");
|
||||
if (stack_size != nullptr && !cJSON_IsNumber(stack_size)) {
|
||||
ESP_LOGE(TAG, "tools/call: Invalid stackSize");
|
||||
ReplyError(id_int, "Invalid stackSize");
|
||||
return;
|
||||
}
|
||||
DoToolCall(id_int, std::string(tool_name->valuestring), tool_arguments, stack_size ? stack_size->valueint : DEFAULT_TOOLCALL_STACK_SIZE);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Method not implemented: %s", method_str.c_str());
|
||||
ReplyError(id_int, "Method not implemented: " + method_str);
|
||||
@@ -311,7 +305,7 @@ void McpServer::GetToolsList(int id, const std::string& cursor) {
|
||||
ReplyResult(id, json);
|
||||
}
|
||||
|
||||
void McpServer::DoToolCall(int id, const std::string& tool_name, const cJSON* tool_arguments) {
|
||||
void McpServer::DoToolCall(int id, const std::string& tool_name, const cJSON* tool_arguments, int stack_size) {
|
||||
auto tool_iter = std::find_if(tools_.begin(), tools_.end(),
|
||||
[&tool_name](const McpTool* tool) {
|
||||
return tool->name() == tool_name;
|
||||
@@ -353,9 +347,15 @@ void McpServer::DoToolCall(int id, const std::string& tool_name, const cJSON* to
|
||||
return;
|
||||
}
|
||||
|
||||
// Use main thread to call the tool
|
||||
auto& app = Application::GetInstance();
|
||||
app.Schedule([this, id, tool_iter, arguments = std::move(arguments)]() {
|
||||
// Start a task to receive data with stack size
|
||||
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name = "tool_call";
|
||||
cfg.stack_size = stack_size;
|
||||
cfg.prio = 1;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
|
||||
// Use a thread to call the tool to avoid blocking the main thread
|
||||
tool_call_thread_ = std::thread([this, id, tool_iter, arguments = std::move(arguments)]() {
|
||||
try {
|
||||
ReplyResult(id, (*tool_iter)->Call(arguments));
|
||||
} catch (const std::exception& e) {
|
||||
@@ -363,4 +363,5 @@ void McpServer::DoToolCall(int id, const std::string& tool_name, const cJSON* to
|
||||
ReplyError(id, e.what());
|
||||
}
|
||||
});
|
||||
tool_call_thread_.detach();
|
||||
}
|
||||
@@ -177,7 +177,6 @@ private:
|
||||
std::string description_;
|
||||
PropertyList properties_;
|
||||
std::function<ReturnValue(const PropertyList&)> callback_;
|
||||
bool user_only_ = false;
|
||||
|
||||
public:
|
||||
McpTool(const std::string& name,
|
||||
@@ -189,11 +188,9 @@ public:
|
||||
properties_(properties),
|
||||
callback_(callback) {}
|
||||
|
||||
void set_user_only(bool user_only) { user_only_ = user_only; }
|
||||
inline const std::string& name() const { return name_; }
|
||||
inline const std::string& description() const { return description_; }
|
||||
inline const PropertyList& properties() const { return properties_; }
|
||||
inline bool user_only() const { return user_only_; }
|
||||
|
||||
std::string to_json() const {
|
||||
std::vector<std::string> required = properties_.GetRequired();
|
||||
@@ -217,15 +214,6 @@ public:
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(json, "inputSchema", input_schema);
|
||||
|
||||
// Add audience annotation if the tool is user only (invisible to AI)
|
||||
if (user_only_) {
|
||||
cJSON *annotations = cJSON_CreateObject();
|
||||
cJSON *audience = cJSON_CreateArray();
|
||||
cJSON_AddItemToArray(audience, cJSON_CreateString("user"));
|
||||
cJSON_AddItemToObject(annotations, "audience", audience);
|
||||
cJSON_AddItemToObject(json, "annotations", annotations);
|
||||
}
|
||||
|
||||
char *json_str = cJSON_PrintUnformatted(json);
|
||||
std::string result(json_str);
|
||||
@@ -271,7 +259,6 @@ public:
|
||||
void AddCommonTools();
|
||||
void AddTool(McpTool* tool);
|
||||
void AddTool(const std::string& name, const std::string& description, const PropertyList& properties, std::function<ReturnValue(const PropertyList&)> callback);
|
||||
void AddUserOnlyTool(const std::string& name, const std::string& description, const PropertyList& properties, std::function<ReturnValue(const PropertyList&)> callback);
|
||||
void ParseMessage(const cJSON* json);
|
||||
void ParseMessage(const std::string& message);
|
||||
|
||||
@@ -285,9 +272,10 @@ private:
|
||||
void ReplyError(int id, const std::string& message);
|
||||
|
||||
void GetToolsList(int id, const std::string& cursor);
|
||||
void DoToolCall(int id, const std::string& tool_name, const cJSON* tool_arguments);
|
||||
void DoToolCall(int id, const std::string& tool_name, const cJSON* tool_arguments, int stack_size);
|
||||
|
||||
std::vector<McpTool*> tools_;
|
||||
std::thread tool_call_thread_;
|
||||
};
|
||||
|
||||
#endif // MCP_SERVER_H
|
||||
|
||||
@@ -51,17 +51,17 @@ std::string Ota::GetCheckVersionUrl() {
|
||||
|
||||
std::unique_ptr<Http> Ota::SetupHttp() {
|
||||
auto& board = Board::GetInstance();
|
||||
auto app_desc = esp_app_get_description();
|
||||
|
||||
auto network = board.GetNetwork();
|
||||
auto http = network->CreateHttp(0);
|
||||
auto user_agent = SystemInfo::GetUserAgent();
|
||||
http->SetHeader("Activation-Version", has_serial_number_ ? "2" : "1");
|
||||
http->SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
|
||||
http->SetHeader("Client-Id", board.GetUuid());
|
||||
if (has_serial_number_) {
|
||||
http->SetHeader("Serial-Number", serial_number_.c_str());
|
||||
ESP_LOGI(TAG, "Setup HTTP, User-Agent: %s, Serial-Number: %s", user_agent.c_str(), serial_number_.c_str());
|
||||
}
|
||||
http->SetHeader("User-Agent", user_agent);
|
||||
http->SetHeader("User-Agent", std::string(BOARD_NAME "/") + app_desc->version);
|
||||
http->SetHeader("Accept-Language", Lang::CODE);
|
||||
http->SetHeader("Content-Type", "application/json");
|
||||
|
||||
|
||||
@@ -12,33 +12,11 @@
|
||||
|
||||
MqttProtocol::MqttProtocol() {
|
||||
event_group_handle_ = xEventGroupCreate();
|
||||
|
||||
// Initialize reconnect timer
|
||||
esp_timer_create_args_t reconnect_timer_args = {
|
||||
.callback = [](void* arg) {
|
||||
MqttProtocol* protocol = (MqttProtocol*)arg;
|
||||
auto& app = Application::GetInstance();
|
||||
if (app.GetDeviceState() == kDeviceStateIdle) {
|
||||
ESP_LOGI(TAG, "Reconnecting to MQTT server");
|
||||
app.Schedule([protocol]() {
|
||||
protocol->StartMqttClient(false);
|
||||
});
|
||||
}
|
||||
},
|
||||
.arg = this,
|
||||
};
|
||||
esp_timer_create(&reconnect_timer_args, &reconnect_timer_);
|
||||
}
|
||||
|
||||
MqttProtocol::~MqttProtocol() {
|
||||
ESP_LOGI(TAG, "MqttProtocol deinit");
|
||||
if (reconnect_timer_ != nullptr) {
|
||||
esp_timer_stop(reconnect_timer_);
|
||||
esp_timer_delete(reconnect_timer_);
|
||||
}
|
||||
if (event_group_handle_ != nullptr) {
|
||||
vEventGroupDelete(event_group_handle_);
|
||||
}
|
||||
vEventGroupDelete(event_group_handle_);
|
||||
}
|
||||
|
||||
bool MqttProtocol::Start() {
|
||||
@@ -72,18 +50,7 @@ bool MqttProtocol::StartMqttClient(bool report_error) {
|
||||
mqtt_->SetKeepAlive(keepalive_interval);
|
||||
|
||||
mqtt_->OnDisconnected([this]() {
|
||||
if (on_disconnected_ != nullptr) {
|
||||
on_disconnected_();
|
||||
}
|
||||
ESP_LOGI(TAG, "MQTT disconnected, schedule reconnect in %d seconds", MQTT_RECONNECT_INTERVAL_MS / 1000);
|
||||
esp_timer_start_once(reconnect_timer_, MQTT_RECONNECT_INTERVAL_MS * 1000);
|
||||
});
|
||||
|
||||
mqtt_->OnConnected([this]() {
|
||||
if (on_connected_ != nullptr) {
|
||||
on_connected_();
|
||||
}
|
||||
esp_timer_stop(reconnect_timer_);
|
||||
ESP_LOGI(TAG, "Disconnected from endpoint");
|
||||
});
|
||||
|
||||
mqtt_->OnMessage([this](const std::string& topic, const std::string& payload) {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <mbedtls/aes.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/event_groups.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
@@ -17,7 +16,7 @@
|
||||
#include <mutex>
|
||||
|
||||
#define MQTT_PING_INTERVAL_SECONDS 90
|
||||
#define MQTT_RECONNECT_INTERVAL_MS 60000
|
||||
#define MQTT_RECONNECT_INTERVAL_MS 10000
|
||||
|
||||
#define MQTT_PROTOCOL_SERVER_HELLO_EVENT (1 << 0)
|
||||
|
||||
@@ -46,7 +45,6 @@ private:
|
||||
int udp_port_;
|
||||
uint32_t local_sequence_;
|
||||
uint32_t remote_sequence_;
|
||||
esp_timer_handle_t reconnect_timer_;
|
||||
|
||||
bool StartMqttClient(bool report_error=false);
|
||||
void ParseServerHello(const cJSON* root);
|
||||
|
||||
@@ -24,14 +24,6 @@ void Protocol::OnNetworkError(std::function<void(const std::string& message)> ca
|
||||
on_network_error_ = callback;
|
||||
}
|
||||
|
||||
void Protocol::OnConnected(std::function<void()> callback) {
|
||||
on_connected_ = callback;
|
||||
}
|
||||
|
||||
void Protocol::OnDisconnected(std::function<void()> callback) {
|
||||
on_disconnected_ = callback;
|
||||
}
|
||||
|
||||
void Protocol::SetError(const std::string& message) {
|
||||
error_occurred_ = true;
|
||||
if (on_network_error_ != nullptr) {
|
||||
|
||||
@@ -60,8 +60,6 @@ public:
|
||||
void OnAudioChannelOpened(std::function<void()> callback);
|
||||
void OnAudioChannelClosed(std::function<void()> callback);
|
||||
void OnNetworkError(std::function<void(const std::string& message)> callback);
|
||||
void OnConnected(std::function<void()> callback);
|
||||
void OnDisconnected(std::function<void()> callback);
|
||||
|
||||
virtual bool Start() = 0;
|
||||
virtual bool OpenAudioChannel() = 0;
|
||||
@@ -80,8 +78,6 @@ protected:
|
||||
std::function<void()> on_audio_channel_opened_;
|
||||
std::function<void()> on_audio_channel_closed_;
|
||||
std::function<void(const std::string& message)> on_network_error_;
|
||||
std::function<void()> on_connected_;
|
||||
std::function<void()> on_disconnected_;
|
||||
|
||||
int server_sample_rate_ = 24000;
|
||||
int server_frame_duration_ = 60;
|
||||
|
||||
@@ -47,12 +47,6 @@ std::string SystemInfo::GetChipModelName() {
|
||||
return std::string(CONFIG_IDF_TARGET);
|
||||
}
|
||||
|
||||
std::string SystemInfo::GetUserAgent() {
|
||||
auto app_desc = esp_app_get_description();
|
||||
auto user_agent = std::string(BOARD_NAME "/") + app_desc->version;
|
||||
return user_agent;
|
||||
}
|
||||
|
||||
esp_err_t SystemInfo::PrintTaskCpuUsage(TickType_t xTicksToWait) {
|
||||
#define ARRAY_SIZE_OFFSET 5
|
||||
TaskStatus_t *start_array = NULL, *end_array = NULL;
|
||||
|
||||
@@ -13,7 +13,6 @@ public:
|
||||
static size_t GetFreeHeapSize();
|
||||
static std::string GetMacAddress();
|
||||
static std::string GetChipModelName();
|
||||
static std::string GetUserAgent();
|
||||
static esp_err_t PrintTaskCpuUsage(TickType_t xTicksToWait);
|
||||
static void PrintTaskList();
|
||||
static void PrintHeapStats();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user