atk_dnesp32s3_box2.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. #include "dual_network_board.h"
  2. #include "codecs/es8389_audio_codec.h"
  3. #include "display/lcd_display.h"
  4. #include "system_reset.h"
  5. #include "application.h"
  6. #include "button.h"
  7. #include "config.h"
  8. #include "power_save_timer.h"
  9. #include "led/single_led.h"
  10. #include "assets/lang_config.h"
  11. #include "power_manager.h"
  12. #include "i2c_device.h"
  13. #include <esp_log.h>
  14. #include <esp_lcd_panel_vendor.h>
  15. #include <wifi_station.h>
  16. #include <driver/rtc_io.h>
  17. #include <esp_sleep.h>
  18. #include "esp_io_expander_tca95xx_16bit.h"
  19. #define TAG "atk_dnesp32s3_box2_4g"
  20. LV_FONT_DECLARE(font_puhui_20_4);
  21. LV_FONT_DECLARE(font_awesome_20_4);
  22. class atk_dnesp32s3_box2_4g : public DualNetworkBoard {
  23. private:
  24. i2c_master_bus_handle_t i2c_bus_;
  25. LcdDisplay* display_;
  26. esp_io_expander_handle_t io_exp_handle;
  27. button_handle_t btns;
  28. button_driver_t* btn_driver_ = nullptr;
  29. static atk_dnesp32s3_box2_4g* instance_;
  30. PowerSaveTimer* power_save_timer_;
  31. PowerManager* power_manager_;
  32. PowerSupply power_status_;
  33. esp_timer_handle_t wake_timer_handle_;
  34. esp_lcd_panel_io_handle_t panel_io = nullptr;
  35. esp_lcd_panel_handle_t panel = nullptr;
  36. int ticks_ = 0;
  37. const int kChgCtrlInterval = 5;
  38. void InitializeBoardPowerManager() {
  39. instance_ = this;
  40. if (IoExpanderGetLevel(XIO_CHRG) == 0) {
  41. power_status_ = kDeviceTypecSupply;
  42. } else {
  43. power_status_ = kDeviceBatterySupply;
  44. }
  45. esp_timer_create_args_t wake_display_timer_args = {
  46. .callback = [](void *arg) {
  47. atk_dnesp32s3_box2_4g* self = static_cast<atk_dnesp32s3_box2_4g*>(arg);
  48. self->ticks_ ++;
  49. if (self->ticks_ % self->kChgCtrlInterval == 0) {
  50. if (self->IoExpanderGetLevel(XIO_CHRG) == 0) {
  51. self->power_status_ = kDeviceTypecSupply;
  52. } else {
  53. self->power_status_ = kDeviceBatterySupply;
  54. }
  55. /* 低于某个电量,会自动关机 */
  56. if (self->power_manager_->low_voltage_ < 2630 && self->power_status_ == kDeviceBatterySupply) {
  57. esp_timer_stop(self->power_manager_->timer_handle_);
  58. esp_io_expander_set_dir(self->io_exp_handle, XIO_CHG_CTRL, IO_EXPANDER_OUTPUT);
  59. esp_io_expander_set_level(self->io_exp_handle, XIO_CHG_CTRL, 0);
  60. vTaskDelay(pdMS_TO_TICKS(100));
  61. esp_io_expander_set_dir(self->io_exp_handle, XIO_CHG_CTRL, IO_EXPANDER_INPUT);
  62. esp_io_expander_set_level(self->io_exp_handle, XIO_CHG_CTRL, 0);
  63. vTaskDelay(pdMS_TO_TICKS(100));
  64. }
  65. }
  66. },
  67. .arg = this,
  68. .dispatch_method = ESP_TIMER_TASK,
  69. .name = "wake_update_timer",
  70. .skip_unhandled_events = true,
  71. };
  72. ESP_ERROR_CHECK(esp_timer_create(&wake_display_timer_args, &wake_timer_handle_));
  73. ESP_ERROR_CHECK(esp_timer_start_periodic(wake_timer_handle_, 100000));
  74. }
  75. void InitializePowerManager() {
  76. power_manager_ = new PowerManager(io_exp_handle);
  77. power_manager_->OnChargingStatusChanged([this](bool is_charging) {
  78. if (is_charging) {
  79. power_save_timer_->SetEnabled(false);
  80. } else {
  81. power_save_timer_->SetEnabled(true);
  82. }
  83. });
  84. }
  85. void InitializePowerSaveTimer() {
  86. power_save_timer_ = new PowerSaveTimer(-1, 60, 300);
  87. power_save_timer_->OnEnterSleepMode([this]() {
  88. display_->SetChatMessage("system", "");
  89. display_->SetEmotion("sleepy");
  90. GetBacklight()->SetBrightness(1);
  91. });
  92. power_save_timer_->OnExitSleepMode([this]() {
  93. display_->SetChatMessage("system", "");
  94. display_->SetEmotion("neutral");
  95. GetBacklight()->RestoreBrightness();
  96. });
  97. power_save_timer_->OnShutdownRequest([this]() {
  98. if (power_status_ == kDeviceBatterySupply) {
  99. GetBacklight()->SetBrightness(0);
  100. esp_timer_stop(power_manager_->timer_handle_);
  101. esp_io_expander_set_dir( io_exp_handle, XIO_CHG_CTRL, IO_EXPANDER_OUTPUT);
  102. esp_io_expander_set_level(io_exp_handle, XIO_CHG_CTRL, 0);
  103. vTaskDelay(pdMS_TO_TICKS(100));
  104. esp_io_expander_set_level(io_exp_handle, XIO_SYS_POW, 0);
  105. }
  106. });
  107. power_save_timer_->SetEnabled(true);
  108. }
  109. void audio_volume_change(bool direction) {
  110. auto codec = GetAudioCodec();
  111. auto volume = codec->output_volume();
  112. if (direction) {
  113. volume += 10;
  114. if (volume > 100) {
  115. volume = 100;
  116. }
  117. codec->SetOutputVolume(volume);
  118. } else {
  119. volume -= 10;
  120. if (volume < 0) {
  121. volume = 0;
  122. }
  123. codec->SetOutputVolume(volume);
  124. }
  125. GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
  126. }
  127. void audio_volume_minimum(){
  128. GetAudioCodec()->SetOutputVolume(0);
  129. GetDisplay()->ShowNotification(Lang::Strings::MUTED);
  130. }
  131. void audio_volume_maxmum(){
  132. GetAudioCodec()->SetOutputVolume(100);
  133. GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
  134. }
  135. esp_err_t IoExpanderSetLevel(uint16_t pin_mask, uint8_t level) {
  136. return esp_io_expander_set_level(io_exp_handle, pin_mask, level);
  137. }
  138. uint8_t IoExpanderGetLevel(uint16_t pin_mask) {
  139. uint32_t pin_val = 0;
  140. esp_io_expander_get_level(io_exp_handle, DRV_IO_EXP_INPUT_MASK, &pin_val);
  141. pin_mask &= DRV_IO_EXP_INPUT_MASK;
  142. return (uint8_t)((pin_val & pin_mask) ? 1 : 0);
  143. }
  144. void InitializeIoExpander() {
  145. esp_err_t ret = ESP_OK;
  146. esp_io_expander_new_i2c_tca95xx_16bit(i2c_bus_, ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_000, &io_exp_handle);
  147. ret |= esp_io_expander_set_dir(io_exp_handle, DRV_IO_EXP_OUTPUT_MASK, IO_EXPANDER_OUTPUT);
  148. ret |= esp_io_expander_set_dir(io_exp_handle, DRV_IO_EXP_INPUT_MASK, IO_EXPANDER_INPUT);
  149. ret |= esp_io_expander_set_level(io_exp_handle, XIO_SYS_POW, 1);
  150. ret |= esp_io_expander_set_level(io_exp_handle, XIO_EN_3V3A, 1);
  151. ret |= esp_io_expander_set_level(io_exp_handle, XIO_EN_4G, 1);
  152. ret |= esp_io_expander_set_level(io_exp_handle, XIO_SPK_EN, 1);
  153. ret |= esp_io_expander_set_level(io_exp_handle, XIO_USB_SEL, 1);
  154. ret |= esp_io_expander_set_level(io_exp_handle, XIO_VBUS_EN, 0);
  155. assert(ret == ESP_OK);
  156. }
  157. void InitializeI2c() {
  158. // Initialize I2C peripheral
  159. i2c_master_bus_config_t i2c_bus_cfg = {
  160. .i2c_port = (i2c_port_t)I2C_NUM_0,
  161. .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
  162. .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
  163. .clk_source = I2C_CLK_SRC_DEFAULT,
  164. .glitch_ignore_cnt = 7,
  165. .intr_priority = 0,
  166. .trans_queue_depth = 0,
  167. .flags = {
  168. .enable_internal_pullup = 1,
  169. },
  170. };
  171. ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
  172. }
  173. void InitializeButtons() {
  174. instance_ = this;
  175. button_config_t l_btn_cfg = {
  176. .long_press_time = 800,
  177. .short_press_time = 500
  178. };
  179. button_config_t m_btn_cfg = {
  180. .long_press_time = 800,
  181. .short_press_time = 500
  182. };
  183. button_config_t r_btn_cfg = {
  184. .long_press_time = 800,
  185. .short_press_time = 500
  186. };
  187. button_driver_t* xio_l_btn_driver_ = nullptr;
  188. button_driver_t* xio_m_btn_driver_ = nullptr;
  189. button_handle_t l_btn_handle = NULL;
  190. button_handle_t m_btn_handle = NULL;
  191. button_handle_t r_btn_handle = NULL;
  192. xio_l_btn_driver_ = (button_driver_t*)calloc(1, sizeof(button_driver_t));
  193. xio_l_btn_driver_->enable_power_save = false;
  194. xio_l_btn_driver_->get_key_level = [](button_driver_t *button_driver) -> uint8_t {
  195. return !instance_->IoExpanderGetLevel(XIO_KEY_L);
  196. };
  197. ESP_ERROR_CHECK(iot_button_create(&l_btn_cfg, xio_l_btn_driver_, &l_btn_handle));
  198. xio_m_btn_driver_ = (button_driver_t*)calloc(1, sizeof(button_driver_t));
  199. xio_m_btn_driver_->enable_power_save = false;
  200. xio_m_btn_driver_->get_key_level = [](button_driver_t *button_driver) -> uint8_t {
  201. return instance_->IoExpanderGetLevel(XIO_KEY_M);
  202. };
  203. ESP_ERROR_CHECK(iot_button_create(&m_btn_cfg, xio_m_btn_driver_, &m_btn_handle));
  204. button_gpio_config_t r_cfg = {
  205. .gpio_num = R_BUTTON_GPIO,
  206. .active_level = BUTTON_INACTIVE,
  207. .enable_power_save = false,
  208. .disable_pull = false
  209. };
  210. ESP_ERROR_CHECK(iot_button_new_gpio_device(&r_btn_cfg, &r_cfg, &r_btn_handle));
  211. iot_button_register_cb(l_btn_handle, BUTTON_PRESS_DOWN, nullptr, [](void* button_handle, void* usr_data) {
  212. auto self = static_cast<atk_dnesp32s3_box2_4g*>(usr_data);
  213. self->power_save_timer_->WakeUp();
  214. self->audio_volume_change(false);
  215. }, this);
  216. iot_button_register_cb(l_btn_handle, BUTTON_LONG_PRESS_START, nullptr, [](void* button_handle, void* usr_data) {
  217. auto self = static_cast<atk_dnesp32s3_box2_4g*>(usr_data);
  218. self->power_save_timer_->WakeUp();
  219. self->audio_volume_minimum();
  220. }, this);
  221. iot_button_register_cb(m_btn_handle, BUTTON_PRESS_DOWN, nullptr, [](void* button_handle, void* usr_data) {
  222. auto self = static_cast<atk_dnesp32s3_box2_4g*>(usr_data);
  223. self->power_save_timer_->WakeUp();
  224. auto& app = Application::GetInstance();
  225. if (self->GetNetworkType() == NetworkType::WIFI) {
  226. if (app.GetDeviceState() == kDeviceStateStarting || app.GetDeviceState() == kDeviceStateWifiConfiguring) {
  227. }
  228. else {
  229. app.ToggleChatState();
  230. }
  231. } else {
  232. app.ToggleChatState();
  233. }
  234. }, this);
  235. iot_button_register_cb(m_btn_handle, BUTTON_DOUBLE_CLICK, nullptr, [](void* button_handle, void* usr_data) {
  236. auto self = static_cast<atk_dnesp32s3_box2_4g*>(usr_data);
  237. self->power_save_timer_->WakeUp();
  238. auto& app = Application::GetInstance();
  239. if (app.GetDeviceState() == kDeviceStateStarting || app.GetDeviceState() == kDeviceStateWifiConfiguring) {
  240. self->SwitchNetworkType();
  241. }
  242. }, this);
  243. iot_button_register_cb(m_btn_handle, BUTTON_LONG_PRESS_START, nullptr, [](void* button_handle, void* usr_data) {
  244. auto self = static_cast<atk_dnesp32s3_box2_4g*>(usr_data);
  245. auto& app = Application::GetInstance();
  246. if (self->GetNetworkType() == NetworkType::WIFI) {
  247. if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
  248. auto& wifi_board = static_cast<WifiBoard&>(self->GetCurrentBoard());
  249. wifi_board.ResetWifiConfiguration();
  250. }
  251. }
  252. if (self->power_status_ == kDeviceBatterySupply) {
  253. auto backlight = Board::GetInstance().GetBacklight();
  254. backlight->SetBrightness(0);
  255. esp_timer_stop(self->power_manager_->timer_handle_);
  256. esp_io_expander_set_dir(self->io_exp_handle, XIO_CHG_CTRL, IO_EXPANDER_OUTPUT);
  257. esp_io_expander_set_level(self->io_exp_handle, XIO_CHG_CTRL, 0);
  258. vTaskDelay(pdMS_TO_TICKS(100));
  259. esp_io_expander_set_level(self->io_exp_handle, XIO_SYS_POW, 0);
  260. vTaskDelay(pdMS_TO_TICKS(100));
  261. }
  262. }, this);
  263. iot_button_register_cb(r_btn_handle, BUTTON_PRESS_DOWN, nullptr, [](void* button_handle, void* usr_data) {
  264. auto self = static_cast<atk_dnesp32s3_box2_4g*>(usr_data);
  265. self->power_save_timer_->WakeUp();
  266. self->audio_volume_change(true);
  267. }, this);
  268. iot_button_register_cb(r_btn_handle, BUTTON_LONG_PRESS_START, nullptr, [](void* button_handle, void* usr_data) {
  269. auto self = static_cast<atk_dnesp32s3_box2_4g*>(usr_data);
  270. self->power_save_timer_->WakeUp();
  271. self->audio_volume_maxmum();
  272. }, this);
  273. }
  274. void InitializeSt7789Display() {
  275. ESP_LOGI(TAG, "Install panel IO");
  276. /*RD PIN */
  277. gpio_config_t gpio_init_struct;
  278. gpio_init_struct.intr_type = GPIO_INTR_DISABLE;
  279. gpio_init_struct.mode = GPIO_MODE_INPUT_OUTPUT;
  280. gpio_init_struct.pin_bit_mask = 1ull << LCD_PIN_RD;
  281. gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE;
  282. gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE;
  283. gpio_config(&gpio_init_struct);
  284. gpio_set_level(LCD_PIN_RD, 1);
  285. /* BL PIN */
  286. gpio_init_struct.pin_bit_mask = 1ull << DISPLAY_BACKLIGHT_PIN;
  287. gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE;
  288. gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE;
  289. gpio_config(&gpio_init_struct);
  290. esp_lcd_i80_bus_handle_t i80_bus = NULL;
  291. esp_lcd_i80_bus_config_t bus_config = {
  292. .dc_gpio_num = LCD_PIN_DC,
  293. .wr_gpio_num = LCD_PIN_WR,
  294. .clk_src = LCD_CLK_SRC_DEFAULT,
  295. .data_gpio_nums = {
  296. LCD_PIN_D0,
  297. LCD_PIN_D1,
  298. LCD_PIN_D2,
  299. LCD_PIN_D3,
  300. LCD_PIN_D4,
  301. LCD_PIN_D5,
  302. LCD_PIN_D6,
  303. LCD_PIN_D7,
  304. },
  305. .bus_width = 8,
  306. .max_transfer_bytes = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t),
  307. .psram_trans_align = 64,
  308. .sram_trans_align = 4,
  309. };
  310. ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
  311. esp_lcd_panel_io_i80_config_t io_config = {
  312. .cs_gpio_num = LCD_PIN_CS,
  313. .pclk_hz = (20 * 1000 * 1000),
  314. .trans_queue_depth = 7,
  315. .on_color_trans_done = nullptr,
  316. .user_ctx = nullptr,
  317. .lcd_cmd_bits = 8,
  318. .lcd_param_bits = 8,
  319. .dc_levels = {
  320. .dc_idle_level = 1,
  321. .dc_cmd_level = 0,
  322. .dc_dummy_level = 0,
  323. .dc_data_level = 1,
  324. },
  325. .flags = {
  326. .cs_active_high = 0,
  327. .pclk_active_neg = 0,
  328. .pclk_idle_low = 0,
  329. },
  330. };
  331. ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &panel_io));
  332. esp_lcd_panel_dev_config_t panel_config = {
  333. .reset_gpio_num = LCD_PIN_RST,
  334. .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
  335. .bits_per_pixel = 16,
  336. };
  337. ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));
  338. esp_lcd_panel_reset(panel);
  339. esp_lcd_panel_init(panel);
  340. esp_lcd_panel_invert_color(panel, true);
  341. esp_lcd_panel_set_gap(panel, 0, 0);
  342. esp_lcd_panel_io_tx_param(panel_io, 0xCF, (uint8_t[]) {0x00,0x83,0x30}, 3);
  343. esp_lcd_panel_io_tx_param(panel_io, 0xED, (uint8_t[]) {0x64,0x03,0x12,0x81}, 4);
  344. esp_lcd_panel_io_tx_param(panel_io, 0xE8, (uint8_t[]) {0x85,0x01,0x79}, 3);
  345. esp_lcd_panel_io_tx_param(panel_io, 0xCB, (uint8_t[]) {0x39,0x2C,0x00,0x34,0x02}, 5);
  346. esp_lcd_panel_io_tx_param(panel_io, 0xF7, (uint8_t[]) {0x20}, 1);
  347. esp_lcd_panel_io_tx_param(panel_io, 0xEA, (uint8_t[]) {0x00,0x00}, 2);
  348. esp_lcd_panel_io_tx_param(panel_io, 0xbb, (uint8_t[]) {0x20}, 1);
  349. esp_lcd_panel_io_tx_param(panel_io, 0xc3, (uint8_t[]) {0x00}, 1);
  350. esp_lcd_panel_io_tx_param(panel_io, 0xC4, (uint8_t[]) {0x20}, 1);
  351. esp_lcd_panel_io_tx_param(panel_io, 0xC5, (uint8_t[]) {0x20}, 1);
  352. esp_lcd_panel_io_tx_param(panel_io, 0xC6, (uint8_t[]) {0x10}, 1);
  353. esp_lcd_panel_io_tx_param(panel_io, 0xC7, (uint8_t[]) {0xB0}, 1);
  354. esp_lcd_panel_io_tx_param(panel_io, 0x36, (uint8_t[]) {0x60}, 1);
  355. esp_lcd_panel_io_tx_param(panel_io, 0x3A, (uint8_t[]) {0x55}, 1);
  356. esp_lcd_panel_io_tx_param(panel_io, 0xB1, (uint8_t[]) {0x00,0x1B}, 2);
  357. esp_lcd_panel_io_tx_param(panel_io, 0xF2, (uint8_t[]) {0x08}, 1);
  358. esp_lcd_panel_io_tx_param(panel_io, 0x26, (uint8_t[]) {0x01}, 1);
  359. esp_lcd_panel_io_tx_param(panel_io, 0xE0, (uint8_t[]) {0xD0,0x00,0x02,0x07,0x0A,0x28,0x32,0x44,0x42,0x06,0x0E,0x12,0x14,0x17}, 14);
  360. esp_lcd_panel_io_tx_param(panel_io, 0xE1, (uint8_t[]) {0xD0,0x00,0x02,0x07,0x0A,0x28,0x31,0x54,0x47,0x0E,0x1C,0x17,0x1B,0x1E}, 14);
  361. esp_lcd_panel_io_tx_param(panel_io, 0xB7, (uint8_t[]) {0x07}, 1);
  362. esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
  363. esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
  364. display_ = new SpiLcdDisplay(panel_io, panel,
  365. DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
  366. {
  367. .text_font = &font_puhui_20_4,
  368. .icon_font = &font_awesome_20_4,
  369. .emoji_font = DISPLAY_HEIGHT >= 240 ? font_emoji_64_init() : font_emoji_32_init(),
  370. });
  371. }
  372. public:
  373. atk_dnesp32s3_box2_4g() :
  374. DualNetworkBoard(Module_4G_TX_PIN, Module_4G_RX_PIN) {
  375. InitializeI2c();
  376. InitializeIoExpander();
  377. InitializePowerSaveTimer();
  378. InitializePowerManager();
  379. InitializeSt7789Display();
  380. InitializeButtons();
  381. GetBacklight()->RestoreBrightness();
  382. InitializeBoardPowerManager();
  383. }
  384. virtual AudioCodec* GetAudioCodec() override {
  385. static Es8389AudioCodec audio_codec(
  386. i2c_bus_,
  387. I2C_NUM_0,
  388. AUDIO_INPUT_SAMPLE_RATE,
  389. AUDIO_OUTPUT_SAMPLE_RATE,
  390. AUDIO_I2S_GPIO_MCLK,
  391. AUDIO_I2S_GPIO_BCLK,
  392. AUDIO_I2S_GPIO_WS,
  393. AUDIO_I2S_GPIO_DOUT,
  394. AUDIO_I2S_GPIO_DIN,
  395. GPIO_NUM_NC,
  396. AUDIO_CODEC_ES8389_ADDR
  397. );
  398. return &audio_codec;
  399. }
  400. virtual Display* GetDisplay() override {
  401. return display_;
  402. }
  403. virtual Backlight* GetBacklight() override {
  404. static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
  405. return &backlight;
  406. }
  407. virtual bool GetBatteryLevel(int& level, bool& charging, bool& discharging) override {
  408. static bool last_discharging = false;
  409. charging = power_manager_->IsCharging();
  410. discharging = power_manager_->IsDischarging();
  411. if (discharging != last_discharging) {
  412. power_save_timer_->SetEnabled(discharging);
  413. last_discharging = discharging;
  414. }
  415. level = power_manager_->GetBatteryLevel();
  416. return true;
  417. }
  418. virtual void SetPowerSaveMode(bool enabled) override {
  419. if (!enabled) {
  420. power_save_timer_->WakeUp();
  421. }
  422. DualNetworkBoard::SetPowerSaveMode(enabled);
  423. }
  424. };
  425. DECLARE_BOARD(atk_dnesp32s3_box2_4g);
  426. // 定义静态成员变量
  427. atk_dnesp32s3_box2_4g* atk_dnesp32s3_box2_4g::instance_ = nullptr;