v2.2.0: Add bread-compact-nt26 board (#1663)
* Refactor application error handling and improve network task logic - Updated error handling for modem initialization failure in Application::Initialize(). - Added new error message for modem initialization in English and Chinese language files. - Simplified lambda captures in NetworkTask to avoid unnecessary references. - Set main task priority in Application::Run() for better performance. * Add support for Bread Compact NT26 board - Introduced new board configuration for Bread Compact NT26 in CMakeLists.txt and Kconfig. - Added board-specific implementation in compact_nt26_board.cc and nt26_board.cc. - Created configuration files for NT26, including config.h and config.json. - Updated dependencies in idf_component.yml to include uart-eth-modem. - Translated error messages in config.h for OLED display type selection to English. - Enhanced display and button initialization logic for NT26 board. * Update project version and improve build configuration - Updated project version from 2.1.0 to 2.2.0 in CMakeLists.txt. - Enabled minimal build configuration to include only essential components. - Updated README files to replace QQ group links with Discord links for community engagement. * Update Bread Compact NT26 board configuration name in config.json * fix compile errors * Update uart-eth-modem dependency format in idf_component.yml * fix esp32 compiling errors * Update CMakeLists.txt to change component dependency from REQUIRES to PRIV_REQUIRES for esp_pm, esp_psram, and esp_driver_gpio * Refactor CMakeLists.txt to explicitly list board common source files and update include directories for better clarity and organization. * Add esp_driver_ppa as a dependency in CMakeLists.txt
This commit is contained in:
@ -45,7 +45,7 @@
|
||||
#elif CONFIG_OLED_SSD1306_128X64
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#else
|
||||
#error "未选择 OLED 屏幕类型"
|
||||
#error "OLED display type is not selected"
|
||||
#endif
|
||||
|
||||
#define DISPLAY_MIRROR_X true
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
#elif CONFIG_OLED_SSD1306_128X64
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#else
|
||||
#error "未选择 OLED 屏幕类型"
|
||||
#error "OLED display type is not selected"
|
||||
#endif
|
||||
|
||||
#define DISPLAY_MIRROR_X true
|
||||
|
||||
181
main/boards/bread-compact-nt26/compact_nt26_board.cc
Normal file
181
main/boards/bread-compact-nt26/compact_nt26_board.cc
Normal file
@ -0,0 +1,181 @@
|
||||
#include "board.h"
|
||||
#include "nt26_board.h"
|
||||
#include "codecs/no_audio_codec.h"
|
||||
#include "display/oled_display.h"
|
||||
#include "application.h"
|
||||
#include "button.h"
|
||||
#include "config.h"
|
||||
#include "lamp_controller.h"
|
||||
#include "led/single_led.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <driver/i2c_master.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
|
||||
#define TAG "CompactNt26Board"
|
||||
|
||||
class CompactNt26Board : public Nt26Board {
|
||||
private:
|
||||
i2c_master_bus_handle_t display_i2c_bus_;
|
||||
esp_lcd_panel_io_handle_t panel_io_ = nullptr;
|
||||
esp_lcd_panel_handle_t panel_ = nullptr;
|
||||
Display* display_ = nullptr;
|
||||
Button boot_button_;
|
||||
Button touch_button_;
|
||||
Button volume_up_button_;
|
||||
Button volume_down_button_;
|
||||
|
||||
void InitializeDisplayI2c() {
|
||||
i2c_master_bus_config_t bus_config = {
|
||||
.i2c_port = (i2c_port_t)0,
|
||||
.sda_io_num = DISPLAY_SDA_PIN,
|
||||
.scl_io_num = DISPLAY_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(&bus_config, &display_i2c_bus_));
|
||||
}
|
||||
|
||||
void InitializeSsd1306Display() {
|
||||
// SSD1306 config
|
||||
esp_lcd_panel_io_i2c_config_t io_config = {
|
||||
.dev_addr = 0x3C,
|
||||
.on_color_trans_done = nullptr,
|
||||
.user_ctx = nullptr,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 6,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
.flags = {
|
||||
.dc_low_on_data = 0,
|
||||
.disable_control_phase = 0,
|
||||
},
|
||||
.scl_speed_hz = 400 * 1000,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c_v2(display_i2c_bus_, &io_config, &panel_io_));
|
||||
|
||||
ESP_LOGI(TAG, "Install SSD1306 driver");
|
||||
esp_lcd_panel_dev_config_t panel_config = {};
|
||||
panel_config.reset_gpio_num = -1;
|
||||
panel_config.bits_per_pixel = 1;
|
||||
|
||||
esp_lcd_panel_ssd1306_config_t ssd1306_config = {
|
||||
.height = static_cast<uint8_t>(DISPLAY_HEIGHT),
|
||||
};
|
||||
panel_config.vendor_config = &ssd1306_config;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(panel_io_, &panel_config, &panel_));
|
||||
ESP_LOGI(TAG, "SSD1306 driver installed");
|
||||
|
||||
// Reset the display
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_));
|
||||
if (esp_lcd_panel_init(panel_) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize display");
|
||||
display_ = new NoDisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the display to on
|
||||
ESP_LOGI(TAG, "Turning display on");
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_, true));
|
||||
|
||||
display_ = new OledDisplay(panel_io_, panel_, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
|
||||
}
|
||||
|
||||
void InitializeButtons() {
|
||||
boot_button_.OnClick([]() {
|
||||
Application::GetInstance().ToggleChatState();
|
||||
});
|
||||
|
||||
touch_button_.OnPressDown([]() {
|
||||
Application::GetInstance().StartListening();
|
||||
});
|
||||
touch_button_.OnPressUp([]() {
|
||||
Application::GetInstance().StopListening();
|
||||
});
|
||||
|
||||
volume_up_button_.OnClick([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
auto volume = codec->output_volume() + 10;
|
||||
if (volume > 100) {
|
||||
volume = 100;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_up_button_.OnLongPress([this]() {
|
||||
GetAudioCodec()->SetOutputVolume(100);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
|
||||
});
|
||||
|
||||
volume_down_button_.OnClick([this]() {
|
||||
auto codec = GetAudioCodec();
|
||||
auto volume = codec->output_volume() - 10;
|
||||
if (volume < 0) {
|
||||
volume = 0;
|
||||
}
|
||||
codec->SetOutputVolume(volume);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
|
||||
});
|
||||
|
||||
volume_down_button_.OnLongPress([this]() {
|
||||
GetAudioCodec()->SetOutputVolume(0);
|
||||
GetDisplay()->ShowNotification(Lang::Strings::MUTED);
|
||||
});
|
||||
}
|
||||
|
||||
// 物联网初始化,添加对 AI 可见设备
|
||||
void InitializeTools() {
|
||||
static LampController lamp(LAMP_GPIO);
|
||||
}
|
||||
|
||||
public:
|
||||
CompactNt26Board() :
|
||||
Nt26Board(NT26_TX_PIN, NT26_RX_PIN, NT26_DTR_PIN, NT26_RI_PIN),
|
||||
boot_button_(BOOT_BUTTON_GPIO),
|
||||
touch_button_(TOUCH_BUTTON_GPIO),
|
||||
volume_up_button_(VOLUME_UP_BUTTON_GPIO),
|
||||
volume_down_button_(VOLUME_DOWN_BUTTON_GPIO) {
|
||||
|
||||
InitializeDisplayI2c();
|
||||
InitializeSsd1306Display();
|
||||
InitializeButtons();
|
||||
InitializeTools();
|
||||
}
|
||||
|
||||
virtual void StartNetwork() override {
|
||||
GetDisplay()->SetStatus(Lang::Strings::DETECTING_MODULE);
|
||||
Nt26Board::StartNetwork();
|
||||
}
|
||||
|
||||
virtual Led* GetLed() override {
|
||||
static SingleLed led(BUILTIN_LED_GPIO);
|
||||
return &led;
|
||||
}
|
||||
|
||||
virtual AudioCodec* GetAudioCodec() override {
|
||||
#ifdef AUDIO_I2S_METHOD_SIMPLEX
|
||||
static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN);
|
||||
#else
|
||||
static NoAudioCodecDuplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
||||
AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN);
|
||||
#endif
|
||||
return &audio_codec;
|
||||
}
|
||||
|
||||
virtual Display* GetDisplay() override {
|
||||
return display_;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_BOARD(CompactNt26Board);
|
||||
61
main/boards/bread-compact-nt26/config.h
Normal file
61
main/boards/bread-compact-nt26/config.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef _BOARD_CONFIG_H_
|
||||
#define _BOARD_CONFIG_H_
|
||||
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define AUDIO_INPUT_SAMPLE_RATE 16000
|
||||
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
|
||||
|
||||
// 如果使用 Duplex I2S 模式,请注释下面一行
|
||||
#define AUDIO_I2S_METHOD_SIMPLEX
|
||||
|
||||
#ifdef AUDIO_I2S_METHOD_SIMPLEX
|
||||
|
||||
#define AUDIO_I2S_MIC_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_MIC_GPIO_SCK GPIO_NUM_5
|
||||
#define AUDIO_I2S_MIC_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_7
|
||||
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_15
|
||||
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_16
|
||||
|
||||
#else
|
||||
|
||||
#define AUDIO_I2S_GPIO_WS GPIO_NUM_4
|
||||
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5
|
||||
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_6
|
||||
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7
|
||||
|
||||
#endif
|
||||
|
||||
#define BUILTIN_LED_GPIO GPIO_NUM_48
|
||||
#define BOOT_BUTTON_GPIO GPIO_NUM_0
|
||||
#define TOUCH_BUTTON_GPIO GPIO_NUM_47
|
||||
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_40
|
||||
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_39
|
||||
|
||||
#define DISPLAY_SDA_PIN GPIO_NUM_41
|
||||
#define DISPLAY_SCL_PIN GPIO_NUM_42
|
||||
#define DISPLAY_WIDTH 128
|
||||
|
||||
#if CONFIG_OLED_SSD1306_128X32
|
||||
#define DISPLAY_HEIGHT 32
|
||||
#elif CONFIG_OLED_SSD1306_128X64
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#else
|
||||
#error "OLED display type is not selected"
|
||||
#endif
|
||||
|
||||
#define DISPLAY_MIRROR_X true
|
||||
#define DISPLAY_MIRROR_Y true
|
||||
|
||||
|
||||
#define NT26_DTR_PIN GPIO_NUM_9
|
||||
#define NT26_RI_PIN GPIO_NUM_10
|
||||
#define NT26_RX_PIN GPIO_NUM_11
|
||||
#define NT26_TX_PIN GPIO_NUM_12
|
||||
|
||||
|
||||
// A MCP Test: Control a lamp
|
||||
#define LAMP_GPIO GPIO_NUM_18
|
||||
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
11
main/boards/bread-compact-nt26/config.json
Normal file
11
main/boards/bread-compact-nt26/config.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"target": "esp32s3",
|
||||
"builds": [
|
||||
{
|
||||
"name": "bread-compact-nt26",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_OLED_SSD1306_128X32=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -46,7 +46,7 @@
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#define SH1106
|
||||
#else
|
||||
#error "未选择 OLED 屏幕类型"
|
||||
#error "OLED display type is not selected"
|
||||
#endif
|
||||
|
||||
#define DISPLAY_MIRROR_X true
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
#include "ml307_board.h"
|
||||
|
||||
#include "application.h"
|
||||
#include "audio_codec.h"
|
||||
#include "display.h"
|
||||
#include "assets/lang_config.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_timer.h>
|
||||
@ -66,8 +65,6 @@ void Ml307Board::OnNetworkEvent(NetworkEvent event, const std::string& data) {
|
||||
}
|
||||
|
||||
void Ml307Board::NetworkTask() {
|
||||
auto& application = Application::GetInstance();
|
||||
|
||||
// Notify modem detection started
|
||||
OnNetworkEvent(NetworkEvent::ModemDetecting);
|
||||
|
||||
@ -92,7 +89,7 @@ void Ml307Board::NetworkTask() {
|
||||
|
||||
// Set up network state change callback
|
||||
// Note: Don't call GetCarrierName() here as it sends AT command and will block ReceiveTask
|
||||
modem_->OnNetworkStateChanged([this, &application](bool network_ready) {
|
||||
modem_->OnNetworkStateChanged([this](bool network_ready) {
|
||||
if (network_ready) {
|
||||
OnNetworkEvent(NetworkEvent::Connected);
|
||||
} else {
|
||||
|
||||
266
main/boards/common/nt26_board.cc
Normal file
266
main/boards/common/nt26_board.cc
Normal file
@ -0,0 +1,266 @@
|
||||
#include "nt26_board.h"
|
||||
#include "display.h"
|
||||
#include "application.h"
|
||||
#include "audio_codec.h"
|
||||
#include <esp_log.h>
|
||||
#include <font_awesome.h>
|
||||
#include <cJSON.h>
|
||||
|
||||
#define TAG "Nt26Board"
|
||||
|
||||
Nt26Board::Nt26Board(gpio_num_t tx_pin, gpio_num_t rx_pin, gpio_num_t dtr_pin, gpio_num_t ri_pin, gpio_num_t reset_pin)
|
||||
: tx_pin_(tx_pin), rx_pin_(rx_pin), dtr_pin_(dtr_pin), ri_pin_(ri_pin), reset_pin_(reset_pin) {
|
||||
|
||||
gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
|
||||
esp_event_loop_create_default();
|
||||
esp_netif_init();
|
||||
|
||||
// Create PM lock handle
|
||||
esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "nt26_cpu", &pm_lock_cpu_max_);
|
||||
|
||||
// Create network ready timeout timer
|
||||
esp_timer_create_args_t timer_args = {
|
||||
.callback = OnNetworkReadyTimeout,
|
||||
.arg = this,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "nt26_net_timer",
|
||||
.skip_unhandled_events = true
|
||||
};
|
||||
esp_timer_create(&timer_args, &network_ready_timer_);
|
||||
}
|
||||
|
||||
Nt26Board::~Nt26Board() {
|
||||
if (current_power_level_ != PowerSaveLevel::LOW_POWER) {
|
||||
SetPowerSaveLevel(PowerSaveLevel::LOW_POWER);
|
||||
}
|
||||
|
||||
if (network_ready_timer_) {
|
||||
esp_timer_stop(network_ready_timer_);
|
||||
esp_timer_delete(network_ready_timer_);
|
||||
}
|
||||
|
||||
if (modem_) {
|
||||
modem_->Stop();
|
||||
}
|
||||
|
||||
if (pm_lock_cpu_max_) {
|
||||
esp_pm_lock_delete(pm_lock_cpu_max_);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Nt26Board::GetBoardType() {
|
||||
return "nt26";
|
||||
}
|
||||
|
||||
void Nt26Board::OnNetworkEvent(NetworkEvent event, const std::string& data) {
|
||||
if (network_event_callback_) {
|
||||
network_event_callback_(event, data);
|
||||
}
|
||||
}
|
||||
|
||||
void Nt26Board::OnNetworkReadyTimeout(void* arg) {
|
||||
auto* self = static_cast<Nt26Board*>(arg);
|
||||
ESP_LOGW(TAG, "Network ready timeout");
|
||||
self->OnNetworkEvent(NetworkEvent::ModemErrorTimeout, "网络连接超时");
|
||||
}
|
||||
|
||||
void Nt26Board::StartNetwork() {
|
||||
OnNetworkEvent(NetworkEvent::ModemDetecting);
|
||||
|
||||
UartEthModem::Config config = {
|
||||
.uart_num = UART_NUM_1,
|
||||
.baud_rate = 3000000,
|
||||
.tx_pin = tx_pin_,
|
||||
.rx_pin = rx_pin_,
|
||||
.mrdy_pin = dtr_pin_,
|
||||
.srdy_pin = ri_pin_
|
||||
};
|
||||
|
||||
modem_ = std::make_unique<UartEthModem>(config);
|
||||
modem_->SetDebug(false);
|
||||
|
||||
modem_->SetNetworkEventCallback([this](UartEthModem::UartEthModemEvent event) {
|
||||
switch (event) {
|
||||
case UartEthModem::UartEthModemEvent::Connected:
|
||||
esp_timer_stop(network_ready_timer_);
|
||||
OnNetworkEvent(NetworkEvent::Connected);
|
||||
break;
|
||||
case UartEthModem::UartEthModemEvent::Disconnected:
|
||||
OnNetworkEvent(NetworkEvent::Disconnected);
|
||||
break;
|
||||
case UartEthModem::UartEthModemEvent::ErrorNoSim:
|
||||
esp_timer_stop(network_ready_timer_);
|
||||
ScheduleAsyncStop();
|
||||
OnNetworkEvent(NetworkEvent::ModemErrorNoSim);
|
||||
break;
|
||||
case UartEthModem::UartEthModemEvent::ErrorRegistrationDenied:
|
||||
esp_timer_stop(network_ready_timer_);
|
||||
ScheduleAsyncStop();
|
||||
OnNetworkEvent(NetworkEvent::ModemErrorRegDenied);
|
||||
break;
|
||||
case UartEthModem::UartEthModemEvent::Connecting:
|
||||
OnNetworkEvent(NetworkEvent::Connecting);
|
||||
break;
|
||||
case UartEthModem::UartEthModemEvent::ErrorInitFailed:
|
||||
case UartEthModem::UartEthModemEvent::ErrorNoCarrier:
|
||||
esp_timer_stop(network_ready_timer_);
|
||||
ScheduleAsyncStop();
|
||||
OnNetworkEvent(NetworkEvent::ModemErrorInitFailed);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (modem_->Start() != ESP_OK) {
|
||||
OnNetworkEvent(NetworkEvent::ModemErrorInitFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_timer_start_once(network_ready_timer_, 30000 * 1000ULL);
|
||||
OnNetworkEvent(NetworkEvent::Connecting);
|
||||
}
|
||||
|
||||
void Nt26Board::ScheduleAsyncStop() {
|
||||
Application::GetInstance().Schedule([this]() {
|
||||
if (modem_) {
|
||||
modem_->Stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Nt26Board::SetNetworkEventCallback(NetworkEventCallback callback) {
|
||||
network_event_callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
NetworkInterface* Nt26Board::GetNetwork() {
|
||||
static EspNetwork network;
|
||||
return &network;
|
||||
}
|
||||
|
||||
const char* Nt26Board::GetNetworkStateIcon() {
|
||||
if (modem_ == nullptr || !modem_->IsInitialized()) {
|
||||
return FONT_AWESOME_SIGNAL_OFF;
|
||||
}
|
||||
int csq = modem_->GetSignalStrength();
|
||||
if (csq == 99 || csq == -1) {
|
||||
return FONT_AWESOME_SIGNAL_OFF;
|
||||
} else if (csq >= 0 && csq <= 9) {
|
||||
return FONT_AWESOME_SIGNAL_WEAK;
|
||||
} else if (csq >= 10 && csq <= 14) {
|
||||
return FONT_AWESOME_SIGNAL_FAIR;
|
||||
} else if (csq >= 15 && csq <= 19) {
|
||||
return FONT_AWESOME_SIGNAL_GOOD;
|
||||
} else if (csq >= 20 && csq <= 31) {
|
||||
return FONT_AWESOME_SIGNAL_STRONG;
|
||||
}
|
||||
return FONT_AWESOME_SIGNAL_OFF;
|
||||
}
|
||||
|
||||
void Nt26Board::SetPowerSaveLevel(PowerSaveLevel level) {
|
||||
if (level == current_power_level_) return;
|
||||
|
||||
if (current_power_level_ == PowerSaveLevel::BALANCED ||
|
||||
current_power_level_ == PowerSaveLevel::PERFORMANCE) {
|
||||
if (pm_lock_cpu_max_) {
|
||||
esp_pm_lock_release(pm_lock_cpu_max_);
|
||||
}
|
||||
}
|
||||
|
||||
if (level == PowerSaveLevel::BALANCED || level == PowerSaveLevel::PERFORMANCE) {
|
||||
if (pm_lock_cpu_max_) {
|
||||
esp_pm_lock_acquire(pm_lock_cpu_max_);
|
||||
}
|
||||
}
|
||||
|
||||
current_power_level_ = level;
|
||||
}
|
||||
|
||||
std::string Nt26Board::GetBoardJson() {
|
||||
// Set the board type for OTA
|
||||
std::string board_json = std::string("{\"type\":\"" BOARD_TYPE "\",");
|
||||
board_json += "\"name\":\"" BOARD_NAME "\",";
|
||||
if (modem_) {
|
||||
board_json += "\"revision\":\"" + modem_->GetModuleRevision() + "\",";
|
||||
board_json += "\"carrier\":\"" + modem_->GetCarrierName() + "\",";
|
||||
board_json += "\"csq\":\"" + std::to_string(modem_->GetSignalStrength()) + "\",";
|
||||
board_json += "\"imei\":\"" + modem_->GetImei() + "\",";
|
||||
board_json += "\"iccid\":\"" + modem_->GetIccid() + "\",";
|
||||
board_json += "\"cereg\":" + GetRegistrationState().ToString() + "}";
|
||||
} else {
|
||||
board_json += "\"status\":\"offline\"}";
|
||||
}
|
||||
return board_json;
|
||||
}
|
||||
|
||||
Nt26CeregState Nt26Board::GetRegistrationState() {
|
||||
Nt26CeregState state;
|
||||
if (modem_) {
|
||||
auto cell_info = modem_->GetCellInfo();
|
||||
state.stat = cell_info.stat;
|
||||
state.tac = cell_info.tac;
|
||||
state.ci = cell_info.ci;
|
||||
state.AcT = cell_info.act;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
std::string Nt26Board::GetDeviceStatusJson() {
|
||||
auto& board = Board::GetInstance();
|
||||
auto root = cJSON_CreateObject();
|
||||
|
||||
// Audio speaker
|
||||
auto audio_speaker = cJSON_CreateObject();
|
||||
auto audio_codec = board.GetAudioCodec();
|
||||
if (audio_codec) {
|
||||
cJSON_AddNumberToObject(audio_speaker, "volume", audio_codec->output_volume());
|
||||
}
|
||||
cJSON_AddItemToObject(root, "audio_speaker", audio_speaker);
|
||||
|
||||
// Screen
|
||||
auto backlight = board.GetBacklight();
|
||||
auto screen = cJSON_CreateObject();
|
||||
if (backlight) {
|
||||
cJSON_AddNumberToObject(screen, "brightness", backlight->brightness());
|
||||
}
|
||||
auto display = board.GetDisplay();
|
||||
if (display && display->height() > 64) {
|
||||
auto theme = display->GetTheme();
|
||||
if (theme != nullptr) {
|
||||
cJSON_AddStringToObject(screen, "theme", theme->name().c_str());
|
||||
}
|
||||
}
|
||||
cJSON_AddItemToObject(root, "screen", screen);
|
||||
|
||||
// Battery
|
||||
int battery_level = 0;
|
||||
bool charging = false, discharging = false;
|
||||
if (board.GetBatteryLevel(battery_level, charging, discharging)) {
|
||||
auto battery = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(battery, "level", battery_level);
|
||||
cJSON_AddBoolToObject(battery, "charging", charging);
|
||||
cJSON_AddItemToObject(root, "battery", battery);
|
||||
}
|
||||
|
||||
// Network
|
||||
auto network = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(network, "type", "cellular");
|
||||
if (modem_) {
|
||||
cJSON_AddStringToObject(network, "carrier", modem_->GetCarrierName().c_str());
|
||||
int csq = modem_->GetSignalStrength();
|
||||
if (csq == 99 || csq == -1) {
|
||||
cJSON_AddStringToObject(network, "signal", "unknown");
|
||||
} else if (csq >= 0 && csq <= 14) {
|
||||
cJSON_AddStringToObject(network, "signal", "weak");
|
||||
} else if (csq >= 15 && csq <= 24) {
|
||||
cJSON_AddStringToObject(network, "signal", "medium");
|
||||
} else if (csq >= 25 && csq <= 31) {
|
||||
cJSON_AddStringToObject(network, "signal", "strong");
|
||||
}
|
||||
}
|
||||
cJSON_AddItemToObject(root, "network", network);
|
||||
|
||||
auto json_str = cJSON_PrintUnformatted(root);
|
||||
std::string json(json_str);
|
||||
cJSON_free(json_str);
|
||||
cJSON_Delete(root);
|
||||
return json;
|
||||
}
|
||||
62
main/boards/common/nt26_board.h
Normal file
62
main/boards/common/nt26_board.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef NT26_BOARD_H
|
||||
#define NT26_BOARD_H
|
||||
|
||||
#include <memory>
|
||||
#include <uart_eth_modem.h>
|
||||
#include <esp_network.h>
|
||||
#include <esp_pm.h>
|
||||
#include <esp_timer.h>
|
||||
#include "board.h"
|
||||
|
||||
struct Nt26CeregState {
|
||||
int stat = 0;
|
||||
std::string tac;
|
||||
std::string ci;
|
||||
int AcT = -1;
|
||||
|
||||
std::string ToString() const {
|
||||
std::string json = "{";
|
||||
json += "\"stat\":" + std::to_string(stat);
|
||||
if (!tac.empty()) json += ",\"tac\":\"" + tac + "\"";
|
||||
if (!ci.empty()) json += ",\"ci\":\"" + ci + "\"";
|
||||
if (AcT >= 0) json += ",\"AcT\":" + std::to_string(AcT);
|
||||
json += "}";
|
||||
return json;
|
||||
}
|
||||
};
|
||||
|
||||
class Nt26Board : public Board {
|
||||
protected:
|
||||
std::unique_ptr<UartEthModem> modem_;
|
||||
gpio_num_t tx_pin_;
|
||||
gpio_num_t rx_pin_;
|
||||
gpio_num_t dtr_pin_; // mrdy_pin
|
||||
gpio_num_t ri_pin_; // srdy_pin
|
||||
gpio_num_t reset_pin_;
|
||||
|
||||
NetworkEventCallback network_event_callback_;
|
||||
esp_pm_lock_handle_t pm_lock_cpu_max_ = nullptr;
|
||||
PowerSaveLevel current_power_level_ = PowerSaveLevel::LOW_POWER;
|
||||
esp_timer_handle_t network_ready_timer_ = nullptr;
|
||||
|
||||
virtual std::string GetBoardJson() override;
|
||||
|
||||
void OnNetworkEvent(NetworkEvent event, const std::string& data = "");
|
||||
static void OnNetworkReadyTimeout(void* arg);
|
||||
void ScheduleAsyncStop();
|
||||
|
||||
public:
|
||||
Nt26Board(gpio_num_t tx_pin, gpio_num_t rx_pin, gpio_num_t dtr_pin, gpio_num_t ri_pin, gpio_num_t reset_pin = GPIO_NUM_NC);
|
||||
virtual ~Nt26Board();
|
||||
virtual std::string GetBoardType() override;
|
||||
virtual void StartNetwork() override;
|
||||
virtual void SetNetworkEventCallback(NetworkEventCallback callback) override;
|
||||
virtual NetworkInterface* GetNetwork() override;
|
||||
virtual const char* GetNetworkStateIcon() override;
|
||||
virtual void SetPowerSaveLevel(PowerSaveLevel level) override;
|
||||
virtual AudioCodec* GetAudioCodec() override { return nullptr; }
|
||||
virtual std::string GetDeviceStatusJson() override;
|
||||
Nt26CeregState GetRegistrationState();
|
||||
};
|
||||
|
||||
#endif // NT26_BOARD_H
|
||||
Reference in New Issue
Block a user