Add battery % with change events

custom
jacqueline 2 years ago
parent 9c105cf613
commit ee949829d9
  1. 33
      src/drivers/battery.cpp
  2. 5
      src/drivers/include/battery.hpp
  3. 18
      src/system_fsm/booting.cpp
  4. 1
      src/system_fsm/idle.cpp
  5. 3
      src/system_fsm/include/system_events.hpp
  6. 1
      src/system_fsm/include/system_fsm.hpp
  7. 10
      src/system_fsm/system_fsm.cpp

@ -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)

Loading…
Cancel
Save