#include "wifi_board.h" #include "audio_codecs/no_audio_codec.h" #include "display/lcd_display.h" #include "system_reset.h" #include "application.h" #include "button.h" #include "config.h" #include "power_save_timer.h" #include "iot/thing_manager.h" #include "led/single_led.h" #include "assets/lang_config.h" #include "../xingzhi-cube-1.54tft-wifi/power_manager.h" #include #include #include #include #include #include #include "settings.h" #define TAG "XINGZHI_CUBE_0_85TFT_WIFI" LV_FONT_DECLARE(font_puhui_16_4); LV_FONT_DECLARE(font_awesome_16_4); static const nv3023_lcd_init_cmd_t lcd_init_cmds[] = { {0xff, (uint8_t[]){0xa5}, 1, 0}, {0x3E, (uint8_t[]){0x09}, 1, 0}, {0x3A, (uint8_t[]){0x65}, 1, 0}, {0x82, (uint8_t[]){0x00}, 1, 0}, {0x98, (uint8_t[]){0x00}, 1, 0}, {0x63, (uint8_t[]){0x0f}, 1, 0}, {0x64, (uint8_t[]){0x0f}, 1, 0}, {0xB4, (uint8_t[]){0x34}, 1, 0}, {0xB5, (uint8_t[]){0x30}, 1, 0}, {0x83, (uint8_t[]){0x03}, 1, 0}, {0x86, (uint8_t[]){0x04}, 1, 0}, {0x87, (uint8_t[]){0x16}, 1, 0}, {0x88, (uint8_t[]){0x0A}, 1, 0}, {0x89, (uint8_t[]){0x27}, 1, 0}, {0x93, (uint8_t[]){0x63}, 1, 0}, {0x96, (uint8_t[]){0x81}, 1, 0}, {0xC3, (uint8_t[]){0x10}, 1, 0}, {0xE6, (uint8_t[]){0x00}, 1, 0}, {0x99, (uint8_t[]){0x01}, 1, 0}, {0x70, (uint8_t[]){0x09}, 1, 0}, {0x71, (uint8_t[]){0x1D}, 1, 0}, {0x72, (uint8_t[]){0x14}, 1, 0}, {0x73, (uint8_t[]){0x0a}, 1, 0}, {0x74, (uint8_t[]){0x11}, 1, 0}, {0x75, (uint8_t[]){0x16}, 1, 0}, {0x76, (uint8_t[]){0x38}, 1, 0}, {0x77, (uint8_t[]){0x0B}, 1, 0}, {0x78, (uint8_t[]){0x08}, 1, 0}, {0x79, (uint8_t[]){0x3E}, 1, 0}, {0x7a, (uint8_t[]){0x07}, 1, 0}, {0x7b, (uint8_t[]){0x0D}, 1, 0}, {0x7c, (uint8_t[]){0x16}, 1, 0}, {0x7d, (uint8_t[]){0x0F}, 1, 0}, {0x7e, (uint8_t[]){0x14}, 1, 0}, {0x7f, (uint8_t[]){0x05}, 1, 0}, {0xa0, (uint8_t[]){0x04}, 1, 0}, {0xa1, (uint8_t[]){0x28}, 1, 0}, {0xa2, (uint8_t[]){0x0c}, 1, 0}, {0xa3, (uint8_t[]){0x11}, 1, 0}, {0xa4, (uint8_t[]){0x0b}, 1, 0}, {0xa5, (uint8_t[]){0x23}, 1, 0}, {0xa6, (uint8_t[]){0x45}, 1, 0}, {0xa7, (uint8_t[]){0x07}, 1, 0}, {0xa8, (uint8_t[]){0x0a}, 1, 0}, {0xa9, (uint8_t[]){0x3b}, 1, 0}, {0xaa, (uint8_t[]){0x0d}, 1, 0}, {0xab, (uint8_t[]){0x18}, 1, 0}, {0xac, (uint8_t[]){0x14}, 1, 0}, {0xad, (uint8_t[]){0x0F}, 1, 0}, {0xae, (uint8_t[]){0x19}, 1, 0}, {0xaf, (uint8_t[]){0x08}, 1, 0}, {0xff, (uint8_t[]){0x00}, 1, 0}, {0x11, (uint8_t[]){0x00}, 0, 120}, {0x29, (uint8_t[]){0x00}, 0, 10} }; class XINGZHI_CUBE_0_85TFT_WIFI : public WifiBoard { private: Button boot_button_; Button volume_up_button_; Button volume_down_button_; SpiLcdDisplay* display_; PowerSaveTimer* power_save_timer_; PowerManager* power_manager_; esp_lcd_panel_io_handle_t panel_io_ = nullptr; esp_lcd_panel_handle_t panel_ = nullptr; void InitializePowerManager() { power_manager_ = new PowerManager(GPIO_NUM_38); power_manager_->OnChargingStatusChanged([this](bool is_charging) { if (is_charging) { power_save_timer_->SetEnabled(false); } else { power_save_timer_->SetEnabled(true); } }); } void InitializePowerSaveTimer() { rtc_gpio_init(GPIO_NUM_21); rtc_gpio_set_direction(GPIO_NUM_21, RTC_GPIO_MODE_OUTPUT_ONLY); rtc_gpio_set_level(GPIO_NUM_21, 1); power_save_timer_ = new PowerSaveTimer(-1, 60, 300); power_save_timer_->OnEnterSleepMode([this]() { ESP_LOGI(TAG, "Enabling sleep mode"); display_->SetChatMessage("system", ""); display_->SetEmotion("sleepy"); GetBacklight()->SetBrightness(1); }); power_save_timer_->OnExitSleepMode([this]() { display_->SetChatMessage("system", ""); display_->SetEmotion("neutral"); GetBacklight()->RestoreBrightness(); }); power_save_timer_->OnShutdownRequest([this]() { ESP_LOGI(TAG, "Shutting down"); rtc_gpio_set_level(GPIO_NUM_21, 0); // 启用保持功能,确保睡眠期间电平不变 rtc_gpio_hold_en(GPIO_NUM_21); esp_lcd_panel_disp_on_off(panel_, false); //关闭显示 esp_deep_sleep_start(); }); power_save_timer_->SetEnabled(true); } void InitializeSpi() { spi_bus_config_t buscfg = {}; buscfg.mosi_io_num = DISPLAY_SDA; buscfg.miso_io_num = GPIO_NUM_NC; buscfg.sclk_io_num = DISPLAY_SCL; buscfg.quadwp_io_num = GPIO_NUM_NC; buscfg.quadhd_io_num = GPIO_NUM_NC; buscfg.max_transfer_sz = DISPLAY_HEIGHT * 80 *sizeof(uint16_t); ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO)); } void InitializeButtons() { boot_button_.OnClick([this]() { power_save_timer_->WakeUp(); auto& app = Application::GetInstance(); if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) { ResetWifiConfiguration(); } app.ToggleChatState(); }); } void InitializeNv3023Display() { ESP_LOGD(TAG, "Install panel IO"); esp_lcd_panel_io_spi_config_t io_config = NV3023_PANEL_IO_SPI_CONFIG(DISPLAY_CS, DISPLAY_DC, NULL, NULL); ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI3_HOST, &io_config, &panel_io_)); ESP_LOGD(TAG, "Install LCD driver"); esp_lcd_panel_dev_config_t panel_config = {}; nv3023_vendor_config_t vendor_config = { // Uncomment these lines if use custom initialization commands .init_cmds = lcd_init_cmds, .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(nv3023_lcd_init_cmd_t), }; panel_config.reset_gpio_num = DISPLAY_RES; panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR; panel_config.bits_per_pixel = 16; panel_config.vendor_config = &vendor_config; ESP_ERROR_CHECK(esp_lcd_new_panel_nv3023(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_, false)); ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(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_16_4, .icon_font = &font_awesome_16_4, .emoji_font = font_emoji_32_init(), }); } void InitializeIot() { auto& thing_manager = iot::ThingManager::GetInstance(); thing_manager.AddThing(iot::CreateThing("Speaker")); thing_manager.AddThing(iot::CreateThing("Screen")); thing_manager.AddThing(iot::CreateThing("Battery")); } void Initializegpio21_45() { rtc_gpio_init(GPIO_NUM_21); rtc_gpio_set_direction(GPIO_NUM_21, RTC_GPIO_MODE_OUTPUT_ONLY); rtc_gpio_set_level(GPIO_NUM_21, 1); //gpio_num_t sp_45 = GPIO_NUM_45; gpio_config_t io_conf = {}; io_conf.intr_type = GPIO_INTR_DISABLE; io_conf.mode = GPIO_MODE_OUTPUT; io_conf.pin_bit_mask = (1ULL << GPIO_NUM_45); io_conf.pull_up_en = GPIO_PULLUP_DISABLE; io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; gpio_config(&io_conf); gpio_set_level(GPIO_NUM_45, 0); } public: XINGZHI_CUBE_0_85TFT_WIFI(): boot_button_(BOOT_BUTTON_GPIO), volume_up_button_(VOLUME_UP_BUTTON_GPIO), volume_down_button_(VOLUME_DOWN_BUTTON_GPIO) { Initializegpio21_45(); // 初始时,拉高21引脚,保证4g模块正常工作 InitializePowerManager(); InitializePowerSaveTimer(); InitializeSpi(); InitializeButtons(); InitializeNv3023Display(); InitializeIot(); GetBacklight()->RestoreBrightness(); } virtual AudioCodec* GetAudioCodec() override { 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); return &audio_codec; } virtual Display* GetDisplay() override { return display_; } virtual Backlight* GetBacklight() override { static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT); return &backlight; } virtual bool GetBatteryLevel(int& level, bool& charging, bool& discharging) override { static bool last_discharging = false; charging = power_manager_->IsCharging(); discharging = power_manager_->IsDischarging(); if (discharging != last_discharging) { power_save_timer_->SetEnabled(discharging); last_discharging = discharging; } level = power_manager_->GetBatteryLevel(); return true; } virtual void SetPowerSaveMode(bool enabled) override { if (!enabled) { power_save_timer_->WakeUp(); } WifiBoard::SetPowerSaveMode(enabled); } }; DECLARE_BOARD(XINGZHI_CUBE_0_85TFT_WIFI);