From 874adc80b88880306d5e6c8b69fa61d754ba8eb6 Mon Sep 17 00:00:00 2001 From: Terrence Date: Tue, 19 Nov 2024 08:50:47 +0800 Subject: [PATCH] add power save timer --- CMakeLists.txt | 2 +- main/application.cc | 2 + main/boards/kevin-box-2/axp2101.cc | 43 ++++++++++--------- main/boards/kevin-box-2/axp2101.h | 4 ++ main/boards/kevin-box-2/kevin_box_board.cc | 48 ++++++++++++++++++++-- main/display/display.cc | 2 +- versions.py | 2 +- 7 files changed, 74 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2881dd30..83395293 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) -set(PROJECT_VER "0.9.0") +set(PROJECT_VER "0.9.1") include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(xiaozhi) diff --git a/main/application.cc b/main/application.cc index 5edc7525..bd7de61c 100644 --- a/main/application.cc +++ b/main/application.cc @@ -61,6 +61,8 @@ void Application::CheckNewVersion() { display->SetIcon(FONT_AWESOME_DOWNLOAD); display->SetStatus("新版本 " + ota_.GetFirmwareVersion()); + + // 预先关闭音频输出,避免升级过程有音频操作 board.GetAudioCodec()->EnableOutput(false); ota_.StartUpgrade([display](int progress, size_t speed) { diff --git a/main/boards/kevin-box-2/axp2101.cc b/main/boards/kevin-box-2/axp2101.cc index dbe0edee..a07da194 100644 --- a/main/boards/kevin-box-2/axp2101.cc +++ b/main/boards/kevin-box-2/axp2101.cc @@ -1,46 +1,46 @@ #include "axp2101.h" +#include "board.h" +#include "display.h" #include -static const char *TAG = "AXP2101"; +static const char *TAG = "Axp2101"; Axp2101::Axp2101(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) { + // ** EFUSE defaults ** + WriteReg(0x22, 0b110); // PWRON > OFFLEVEL as POWEROFF Source enable + WriteReg(0x27, 0x10); // hold 4s to power off - WriteReg(0x93, 0x1c); // 配置aldo2输出为3.3v + WriteReg(0x93, 0x1C); // 配置 aldo2 输出为 3.3V - uint8_t value = ReadReg(0x90); // XPOWERS_AXP2101_LDO_ONOFF_CTRL0 + uint8_t value = ReadReg(0x90); // XPOWERS_AXP2101_LDO_ONOFF_CTRL0 value = value | 0x02; // set bit 1 (ALDO2) WriteReg(0x90, value); // and power channels now enabled - WriteReg(0x64, 0x03); // CV charger voltage setting to 42V - value = ReadReg(0x62); - ESP_LOGI(TAG, "axp2101 read 0x62 get: 0x%X", value); + WriteReg(0x64, 0x03); // CV charger voltage setting to 4.2V WriteReg(0x61, 0x05); // set Main battery precharge current to 125mA - WriteReg(0x62, 0x10); // set Main battery charger current to 900mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA ) + WriteReg(0x62, 0x10); // set Main battery charger current to 1000mA ( 0x08-200mA, 0x09-300mA, 0x0A-400mA ) WriteReg(0x63, 0x15); // set Main battery term charge current to 125mA - value = ReadReg(0x62); - ESP_LOGI(TAG, "axp2101 read 0x62 get: 0x%X", value); - - value = ReadReg(0x18); - ESP_LOGI(TAG, "axp2101 read 0x18 get: 0x%X", value); - value = value & 0b11100000; - value = value | 0b00001110; - WriteReg(0x18, value); - value = ReadReg(0x18); - ESP_LOGI(TAG, "axp2101 read 0x18 get: 0x%X", value); WriteReg(0x14, 0x00); // set minimum system voltage to 4.1V (default 4.7V), for poor USB cables WriteReg(0x15, 0x00); // set input voltage limit to 3.88v, for poor USB cables - WriteReg(0x16, 0x05); // set input voltage limit to 3.88v, for poor USB cables + WriteReg(0x16, 0x05); // set input current limit to 2000mA WriteReg(0x24, 0x01); // set Vsys for PWROFF threshold to 3.2V (default - 2.6V and kill battery) WriteReg(0x50, 0x14); // set TS pin to EXTERNAL input (not temperature) } +int Axp2101::GetBatteryCurrentDirection() { + return (ReadReg(0x01) & 0b01100000) >> 5; +} + bool Axp2101::IsCharging() { - uint8_t value = ReadReg(0x01); - return (value & 0b01100000) == 0b00100000; + return GetBatteryCurrentDirection() == 1; +} + +bool Axp2101::IsDischarging() { + return GetBatteryCurrentDirection() == 2; } bool Axp2101::IsChargingDone() { @@ -49,8 +49,7 @@ bool Axp2101::IsChargingDone() { } int Axp2101::GetBatteryLevel() { - uint8_t value = ReadReg(0xA4); - return value; + return ReadReg(0xA4); } void Axp2101::PowerOff() { diff --git a/main/boards/kevin-box-2/axp2101.h b/main/boards/kevin-box-2/axp2101.h index 7a39fe0e..db9a497e 100644 --- a/main/boards/kevin-box-2/axp2101.h +++ b/main/boards/kevin-box-2/axp2101.h @@ -7,9 +7,13 @@ class Axp2101 : public I2cDevice { public: Axp2101(i2c_master_bus_handle_t i2c_bus, uint8_t addr); bool IsCharging(); + bool IsDischarging(); bool IsChargingDone(); int GetBatteryLevel(); void PowerOff(); + +private: + int GetBatteryCurrentDirection(); }; #endif diff --git a/main/boards/kevin-box-2/kevin_box_board.cc b/main/boards/kevin-box-2/kevin_box_board.cc index 61a4db0f..5a0c8c06 100644 --- a/main/boards/kevin-box-2/kevin_box_board.cc +++ b/main/boards/kevin-box-2/kevin_box_board.cc @@ -11,6 +11,7 @@ #include #include #include +#include static const char *TAG = "KevinBoxBoard"; @@ -23,6 +24,41 @@ private: Button volume_up_button_; Button volume_down_button_; uint8_t _data_buffer[2]; + esp_timer_handle_t power_save_timer_ = nullptr; + + void InitializePowerSaveTimer() { + esp_timer_create_args_t power_save_timer_args = { + .callback = [](void *arg) { + auto board = static_cast(arg); + board->PowerSaveCheck(); + }, + .arg = this, + .dispatch_method = ESP_TIMER_TASK, + .name = "Power Save Timer", + .skip_unhandled_events = false, + }; + ESP_ERROR_CHECK(esp_timer_create(&power_save_timer_args, &power_save_timer_)); + ESP_ERROR_CHECK(esp_timer_start_periodic(power_save_timer_, 1000000)); + } + + void PowerSaveCheck() { + // 电池放电模式下,如果待机超过一定时间,则自动关机 + const int seconds_to_shutdown = 600; + static int seconds = 0; + if (Application::GetInstance().GetChatState() != kChatStateIdle) { + seconds = 0; + return; + } + if (!axp2101_->IsDischarging()) { + seconds = 0; + return; + } + + seconds++; + if (seconds >= seconds_to_shutdown) { + axp2101_->PowerOff(); + } + } void MountStorage() { // Mount the storage partition @@ -86,10 +122,6 @@ private: Application::GetInstance().ToggleChatState(); }); - boot_button_.OnLongPress([this]() { - axp2101_->PowerOff(); - }); - volume_up_button_.OnClick([this]() { auto codec = GetAudioCodec(); auto volume = codec->output_volume() + 10; @@ -140,6 +172,7 @@ public: Enable4GModule(); InitializeButtons(); + InitializePowerSaveTimer(); Ml307Board::Initialize(); } @@ -162,8 +195,15 @@ public: } virtual bool GetBatteryLevel(int &level, bool& charging) override { + static int last_level = 0; + static bool last_charging = false; level = axp2101_->GetBatteryLevel(); charging = axp2101_->IsCharging(); + if (level != last_level || charging != last_charging) { + last_level = level; + last_charging = charging; + ESP_LOGI(TAG, "Battery level: %d, charging: %d", level, charging); + } return true; } }; diff --git a/main/display/display.cc b/main/display/display.cc index fdc0155a..5b21cedc 100644 --- a/main/display/display.cc +++ b/main/display/display.cc @@ -120,7 +120,7 @@ void Display::Update() { } } - // 仅在聊天状态为空闲时,更新网络图标 + // 仅在聊天状态为空闲时,读取网络状态(避免升级时占用 UART 资源) auto chat_state = Application::GetInstance().GetChatState(); if (chat_state == kChatStateIdle || chat_state == kChatStateUnknown) { icon = board.GetNetworkStateIcon(); diff --git a/versions.py b/versions.py index 2429e93d..63877602 100644 --- a/versions.py +++ b/versions.py @@ -64,7 +64,7 @@ def get_board_name(folder): return "bread-compact-wifi" elif "KevinBox1" in basename: return "kevin-box-1" - if basename.startswith("v0.7") or basename.startswith("v0.8"): + if basename.startswith("v0.7") or basename.startswith("v0.8") or basename.startswith("v0.9"): return basename.split("_")[1] raise Exception(f"Unknown board name: {basename}")