Add battery % with change events
This commit is contained in:
+32
-1
@@ -14,6 +14,21 @@
|
|||||||
|
|
||||||
namespace drivers {
|
namespace drivers {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Battery voltage, in millivolts, at which the battery charger IC will stop
|
||||||
|
* charging.
|
||||||
|
*/
|
||||||
|
static const uint32_t kFullChargeMilliVolts = 4200;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Battery voltage, in millivolts, at which *we* will consider the battery to
|
||||||
|
* be completely discharged. This is intentionally higher than the charger IC
|
||||||
|
* cut-off and the protection on the battery itself; we want to make sure we
|
||||||
|
* finish up and have everything unmounted and snoozing before the BMS cuts us
|
||||||
|
* off.
|
||||||
|
*/
|
||||||
|
static const uint32_t kEmptyChargeMilliVolts = 3200; // BMS limit is 3100.
|
||||||
|
|
||||||
static const adc_bitwidth_t kAdcBitWidth = ADC_BITWIDTH_12;
|
static const adc_bitwidth_t kAdcBitWidth = ADC_BITWIDTH_12;
|
||||||
static const adc_unit_t kAdcUnit = ADC_UNIT_1;
|
static const adc_unit_t kAdcUnit = ADC_UNIT_1;
|
||||||
// Max battery voltage should be a little over 2V due to our divider, so we need
|
// Max battery voltage should be a little over 2V due to our divider, so we need
|
||||||
@@ -44,6 +59,8 @@ Battery::Battery() {
|
|||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting(
|
ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting(
|
||||||
&calibration_config, &adc_calibration_handle_));
|
&calibration_config, &adc_calibration_handle_));
|
||||||
|
|
||||||
|
UpdatePercent();
|
||||||
}
|
}
|
||||||
|
|
||||||
Battery::~Battery() {
|
Battery::~Battery() {
|
||||||
@@ -60,7 +77,21 @@ auto Battery::Millivolts() -> uint32_t {
|
|||||||
ESP_ERROR_CHECK(
|
ESP_ERROR_CHECK(
|
||||||
adc_cali_raw_to_voltage(adc_calibration_handle_, raw, &voltage));
|
adc_cali_raw_to_voltage(adc_calibration_handle_, raw, &voltage));
|
||||||
|
|
||||||
return voltage;
|
// Voltage divider halves the battery voltage to get it into the ADC's range.
|
||||||
|
return voltage * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Battery::UpdatePercent() -> bool {
|
||||||
|
auto old_percent = percent_;
|
||||||
|
// FIXME: So what we *should* do here is measure the actual real-life
|
||||||
|
// time from full battery -> empty battery, store it in NVS, then rely on
|
||||||
|
// that. If someone could please do this, it would be lovely. Thanks!
|
||||||
|
uint32_t mV = std::max(Millivolts(), kEmptyChargeMilliVolts);
|
||||||
|
percent_ = static_cast<uint_fast8_t>(std::min<double>(
|
||||||
|
std::max<double>(0.0, mV - kEmptyChargeMilliVolts) /
|
||||||
|
(kFullChargeMilliVolts - kEmptyChargeMilliVolts) * 100.0,
|
||||||
|
100.0));
|
||||||
|
return old_percent != percent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace drivers
|
} // namespace drivers
|
||||||
|
|||||||
@@ -26,9 +26,14 @@ class Battery {
|
|||||||
*/
|
*/
|
||||||
auto Millivolts() -> uint32_t;
|
auto Millivolts() -> uint32_t;
|
||||||
|
|
||||||
|
auto UpdatePercent() -> bool;
|
||||||
|
auto Percent() -> uint_fast8_t { return percent_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
adc_oneshot_unit_handle_t adc_handle_;
|
adc_oneshot_unit_handle_t adc_handle_;
|
||||||
adc_cali_handle_t adc_calibration_handle_;
|
adc_cali_handle_t adc_calibration_handle_;
|
||||||
|
|
||||||
|
uint_fast8_t percent_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace drivers
|
} // namespace drivers
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-only
|
* SPDX-License-Identifier: GPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "audio_fsm.hpp"
|
#include "audio_fsm.hpp"
|
||||||
#include "bluetooth.hpp"
|
#include "bluetooth.hpp"
|
||||||
@@ -12,6 +14,10 @@
|
|||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "event_queue.hpp"
|
#include "event_queue.hpp"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/portmacro.h"
|
||||||
|
#include "freertos/projdefs.h"
|
||||||
|
#include "freertos/timers.h"
|
||||||
#include "gpios.hpp"
|
#include "gpios.hpp"
|
||||||
#include "lvgl/lvgl.h"
|
#include "lvgl/lvgl.h"
|
||||||
#include "nvs.hpp"
|
#include "nvs.hpp"
|
||||||
@@ -32,6 +38,12 @@ namespace states {
|
|||||||
|
|
||||||
static const char kTag[] = "BOOT";
|
static const char kTag[] = "BOOT";
|
||||||
|
|
||||||
|
static const TickType_t kBatteryCheckPeriod = pdMS_TO_TICKS(60 * 1000);
|
||||||
|
|
||||||
|
static void battery_timer_cb(TimerHandle_t timer) {
|
||||||
|
events::System().Dispatch(internal::BatteryTimerFired{});
|
||||||
|
}
|
||||||
|
|
||||||
auto Booting::entry() -> void {
|
auto Booting::entry() -> void {
|
||||||
ESP_LOGI(kTag, "beginning tangara boot");
|
ESP_LOGI(kTag, "beginning tangara boot");
|
||||||
ESP_LOGI(kTag, "installing early drivers");
|
ESP_LOGI(kTag, "installing early drivers");
|
||||||
@@ -62,6 +74,12 @@ auto Booting::entry() -> void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(kTag, "battery is at %u%% (= %lu mV)", sBattery->Percent(),
|
||||||
|
sBattery->Millivolts());
|
||||||
|
TimerHandle_t battery_timer = xTimerCreate("battery", kBatteryCheckPeriod,
|
||||||
|
true, NULL, battery_timer_cb);
|
||||||
|
xTimerStart(battery_timer, portMAX_DELAY);
|
||||||
|
|
||||||
ESP_LOGI(kTag, "starting bluetooth");
|
ESP_LOGI(kTag, "starting bluetooth");
|
||||||
sBluetooth.reset(new drivers::Bluetooth(sNvs.get()));
|
sBluetooth.reset(new drivers::Bluetooth(sNvs.get()));
|
||||||
// sBluetooth->Enable();
|
// sBluetooth->Enable();
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ void Idle::react(const internal::IdleTimeout& ev) {
|
|||||||
sGpios->WriteBuffered(drivers::IGpios::Pin::kSdMuxSwitch, true);
|
sGpios->WriteBuffered(drivers::IGpios::Pin::kSdMuxSwitch, true);
|
||||||
sGpios->WriteBuffered(drivers::IGpios::Pin::kSdMuxDisable, true);
|
sGpios->WriteBuffered(drivers::IGpios::Pin::kSdMuxDisable, true);
|
||||||
|
|
||||||
|
|
||||||
// Pull down to prevent sourcing current uselessly from input pins.
|
// Pull down to prevent sourcing current uselessly from input pins.
|
||||||
sGpios->WriteBuffered(drivers::IGpios::Pin::kSdCardDetect, false);
|
sGpios->WriteBuffered(drivers::IGpios::Pin::kSdCardDetect, false);
|
||||||
sGpios->WriteBuffered(drivers::IGpios::Pin::kKeyUp, false);
|
sGpios->WriteBuffered(drivers::IGpios::Pin::kKeyUp, false);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ struct HasPhonesChanged : tinyfsm::Event {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ChargingStatusChanged : tinyfsm::Event {};
|
struct ChargingStatusChanged : tinyfsm::Event {};
|
||||||
|
struct BatteryPercentChanged : tinyfsm::Event {};
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
@@ -61,6 +62,8 @@ struct SamdInterrupt : tinyfsm::Event {};
|
|||||||
|
|
||||||
struct IdleTimeout : tinyfsm::Event {};
|
struct IdleTimeout : tinyfsm::Event {};
|
||||||
|
|
||||||
|
struct BatteryTimerFired : tinyfsm::Event {};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
} // namespace system_fsm
|
} // namespace system_fsm
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ class SystemState : public tinyfsm::Fsm<SystemState> {
|
|||||||
void react(const FatalError&);
|
void react(const FatalError&);
|
||||||
void react(const internal::GpioInterrupt&);
|
void react(const internal::GpioInterrupt&);
|
||||||
void react(const internal::SamdInterrupt&);
|
void react(const internal::SamdInterrupt&);
|
||||||
|
void react(const internal::BatteryTimerFired&);
|
||||||
|
|
||||||
virtual void react(const DisplayReady&) {}
|
virtual void react(const DisplayReady&) {}
|
||||||
virtual void react(const BootComplete&) {}
|
virtual void react(const BootComplete&) {}
|
||||||
|
|||||||
@@ -95,6 +95,16 @@ void SystemState::react(const internal::SamdInterrupt&) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SystemState::react(const internal::BatteryTimerFired&) {
|
||||||
|
ESP_LOGI(kTag, "checking battery");
|
||||||
|
if (sBattery->UpdatePercent()) {
|
||||||
|
ESP_LOGI(kTag, "battery now at %u%%", sBattery->Percent());
|
||||||
|
BatteryPercentChanged ev{};
|
||||||
|
events::Ui().Dispatch(ev);
|
||||||
|
events::System().Dispatch(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace system_fsm
|
} // namespace system_fsm
|
||||||
|
|
||||||
FSM_INITIAL_STATE(system_fsm::SystemState, system_fsm::states::Booting)
|
FSM_INITIAL_STATE(system_fsm::SystemState, system_fsm::states::Booting)
|
||||||
|
|||||||
Reference in New Issue
Block a user