summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-07-24 15:29:45 +1000
committerjacqueline <me@jacqueline.id.au>2024-07-24 15:29:45 +1000
commit0cc75366848e9205ac88884afcc128925024ccec (patch)
tree82fcd90d7f427c5f40112b8d8aa6293535372702 /src
parenteb5d0d50cd5a8d807897c08438e932083e5197c2 (diff)
downloadtangara-fw-0cc75366848e9205ac88884afcc128925024ccec.tar.gz
Add a settings screen with power+battery info
Mostly for debugging, but also u can toggle fast charging off and on now
Diffstat (limited to 'src')
-rw-r--r--src/drivers/include/drivers/nvs.hpp4
-rw-r--r--src/drivers/include/drivers/samd.hpp13
-rw-r--r--src/drivers/nvs.cpp12
-rw-r--r--src/drivers/samd.cpp74
-rw-r--r--src/tangara/app_console/app_console.cpp21
-rw-r--r--src/tangara/battery/battery.cpp2
-rw-r--r--src/tangara/battery/battery.hpp1
-rw-r--r--src/tangara/system_fsm/booting.cpp6
-rw-r--r--src/tangara/ui/ui_fsm.cpp34
-rw-r--r--src/tangara/ui/ui_fsm.hpp2
10 files changed, 126 insertions, 43 deletions
diff --git a/src/drivers/include/drivers/nvs.hpp b/src/drivers/include/drivers/nvs.hpp
index 8eb28cc9..e298ffc3 100644
--- a/src/drivers/include/drivers/nvs.hpp
+++ b/src/drivers/include/drivers/nvs.hpp
@@ -90,6 +90,9 @@ class NvsStorage {
auto LraCalibration() -> std::optional<LraData>;
auto LraCalibration(const LraData&) -> void;
+ auto FastCharge() -> bool;
+ auto FastCharge(bool) -> void;
+
auto PreferredBluetoothDevice() -> std::optional<bluetooth::MacAndName>;
auto PreferredBluetoothDevice(std::optional<bluetooth::MacAndName>) -> void;
@@ -150,6 +153,7 @@ class NvsStorage {
Setting<uint16_t> display_rows_;
Setting<uint8_t> haptic_motor_type_;
Setting<LraData> lra_calibration_;
+ Setting<uint8_t> fast_charge_;
Setting<uint8_t> brightness_;
Setting<uint8_t> sensitivity_;
diff --git a/src/drivers/include/drivers/samd.hpp b/src/drivers/include/drivers/samd.hpp
index 897e78d6..ff479225 100644
--- a/src/drivers/include/drivers/samd.hpp
+++ b/src/drivers/include/drivers/samd.hpp
@@ -10,6 +10,7 @@
#include <optional>
#include <string>
+#include "drivers/nvs.hpp"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
@@ -17,9 +18,7 @@ namespace drivers {
class Samd {
public:
- static auto Create() -> Samd* { return new Samd(); }
-
- Samd();
+ Samd(NvsStorage& nvs);
~Samd();
auto Version() -> std::string;
@@ -37,8 +36,14 @@ class Samd {
kChargingFast,
// The battery is full charged, and we are still plugged in.
kFullCharge,
+ // Charging failed.
+ kFault,
+ // The battery status returned isn't a known enum value.
+ kUnknown,
};
+ static auto chargeStatusToString(ChargeStatus) -> std::string;
+
auto GetChargeStatus() -> std::optional<ChargeStatus>;
auto UpdateChargeStatus() -> void;
@@ -68,6 +73,8 @@ class Samd {
Samd& operator=(const Samd&) = delete;
private:
+ NvsStorage& nvs_;
+
uint8_t version_;
std::optional<ChargeStatus> charge_status_;
UsbStatus usb_status_;
diff --git a/src/drivers/nvs.cpp b/src/drivers/nvs.cpp
index e3c4aa06..6fac8c61 100644
--- a/src/drivers/nvs.cpp
+++ b/src/drivers/nvs.cpp
@@ -40,6 +40,7 @@ static constexpr char kKeyDisplayRows[] = "disprows";
static constexpr char kKeyHapticMotorType[] = "hapticmtype";
static constexpr char kKeyLraCalibration[] = "lra_cali";
static constexpr char kKeyDbAutoIndex[] = "dbautoindex";
+static constexpr char kKeyFastCharge[] = "fastchg";
static auto nvs_get_string(nvs_handle_t nvs, const char* key)
-> std::optional<std::string> {
@@ -239,6 +240,7 @@ NvsStorage::NvsStorage(nvs_handle_t handle)
display_rows_(kKeyDisplayRows),
haptic_motor_type_(kKeyHapticMotorType),
lra_calibration_(kKeyLraCalibration),
+ fast_charge_(kKeyFastCharge),
brightness_(kKeyBrightness),
sensitivity_(kKeyScrollSensitivity),
amp_max_vol_(kKeyAmpMaxVolume),
@@ -444,6 +446,16 @@ auto NvsStorage::OutputMode(Output out) -> void {
nvs_commit(handle_);
}
+auto NvsStorage::FastCharge() -> bool {
+ std::lock_guard<std::mutex> lock{mutex_};
+ return fast_charge_.get().value_or(true);
+}
+
+auto NvsStorage::FastCharge(bool en) -> void {
+ std::lock_guard<std::mutex> lock{mutex_};
+ fast_charge_.set(en);
+}
+
auto NvsStorage::ScreenBrightness() -> uint_fast8_t {
std::lock_guard<std::mutex> lock{mutex_};
return std::clamp<uint8_t>(brightness_.get().value_or(50), 0, 100);
diff --git a/src/drivers/samd.cpp b/src/drivers/samd.cpp
index e4aa73ad..c2308760 100644
--- a/src/drivers/samd.cpp
+++ b/src/drivers/samd.cpp
@@ -5,11 +5,13 @@
*/
#include "drivers/samd.hpp"
+#include <stdint.h>
#include <cstdint>
#include <optional>
#include <string>
+#include "drivers/nvs.hpp"
#include "esp_err.h"
#include "esp_log.h"
#include "hal/gpio_types.h"
@@ -32,7 +34,29 @@ namespace drivers {
static constexpr gpio_num_t kIntPin = GPIO_NUM_35;
-Samd::Samd() {
+auto Samd::chargeStatusToString(ChargeStatus status) -> std::string {
+ switch (status) {
+ case ChargeStatus::kNoBattery:
+ return "no_battery";
+ case ChargeStatus::kBatteryCritical:
+ return "critical";
+ case ChargeStatus::kDischarging:
+ return "discharging";
+ case ChargeStatus::kChargingRegular:
+ return "charge_regular";
+ case ChargeStatus::kChargingFast:
+ return "charge_fast";
+ case ChargeStatus::kFullCharge:
+ return "full_charge";
+ case ChargeStatus::kFault:
+ return "fault";
+ case ChargeStatus::kUnknown:
+ default:
+ return "unknown";
+ }
+}
+
+Samd::Samd(NvsStorage& nvs) : nvs_(nvs) {
gpio_set_direction(kIntPin, GPIO_MODE_INPUT);
// Being able to interface with the SAMD properly is critical. To ensure we
@@ -51,7 +75,7 @@ Samd::Samd() {
UpdateChargeStatus();
UpdateUsbStatus();
- SetFastChargeEnabled(true);
+ SetFastChargeEnabled(nvs.FastCharge());
}
Samd::~Samd() {}
@@ -78,16 +102,38 @@ auto Samd::UpdateChargeStatus() -> void {
return;
}
- // FIXME: Ideally we should be using the three 'charge status' bits to work
- // out whether we're actually charging, or if we've got a full charge,
- // critically low charge, etc.
+ // Lower two bits are the usb power status, next three are the BMS status.
+ // See 'gpio.c' in the SAMD21 firmware for how these bits get packed.
+ uint8_t charge_state = (raw_res & 0b11100) >> 2;
uint8_t usb_state = raw_res & 0b11;
- if (usb_state == 0) {
- charge_status_ = ChargeStatus::kDischarging;
- } else if (usb_state == 1) {
- charge_status_ = ChargeStatus::kChargingRegular;
- } else {
- charge_status_ = ChargeStatus::kChargingFast;
+ switch (charge_state) {
+ case 0b000:
+ charge_status_ = ChargeStatus::kNoBattery;
+ break;
+ case 0b001:
+ // BMS says we're charging; work out how fast we're charging.
+ if (usb_state >= 0b10 && nvs_.FastCharge()) {
+ charge_status_ = ChargeStatus::kChargingFast;
+ } else {
+ charge_status_ = ChargeStatus::kChargingRegular;
+ }
+ break;
+ case 0b010:
+ charge_status_ = ChargeStatus::kFullCharge;
+ break;
+ case 0b011:
+ charge_status_ = ChargeStatus::kFault;
+ break;
+ case 0b100:
+ charge_status_ = ChargeStatus::kBatteryCritical;
+ break;
+ case 0b101:
+ charge_status_ = ChargeStatus::kDischarging;
+ break;
+ case 0b110:
+ case 0b111:
+ charge_status_ = ChargeStatus::kUnknown;
+ break;
}
}
@@ -127,9 +173,15 @@ auto Samd::ResetToFlashSamd() -> void {
}
auto Samd::SetFastChargeEnabled(bool en) -> void {
+ // Always update NVS, so that the setting is right after the SAMD firmware is
+ // updated.
+ nvs_.FastCharge(en);
+
if (version_ < 4) {
return;
}
+ ESP_LOGI(kTag, "set fast charge %u", en);
+
I2CTransaction transaction;
transaction.start()
.write_addr(kAddress, I2C_MASTER_WRITE)
diff --git a/src/tangara/app_console/app_console.cpp b/src/tangara/app_console/app_console.cpp
index 11862143..21dec56a 100644
--- a/src/tangara/app_console/app_console.cpp
+++ b/src/tangara/app_console/app_console.cpp
@@ -465,26 +465,7 @@ int CmdSamd(int argc, char** argv) {
} else if (cmd == "charge") {
auto res = samd.GetChargeStatus();
if (res) {
- switch (res.value()) {
- case drivers::Samd::ChargeStatus::kNoBattery:
- std::cout << "kNoBattery" << std::endl;
- break;
- case drivers::Samd::ChargeStatus::kBatteryCritical:
- std::cout << "kBatteryCritical" << std::endl;
- break;
- case drivers::Samd::ChargeStatus::kDischarging:
- std::cout << "kDischarging" << std::endl;
- break;
- case drivers::Samd::ChargeStatus::kChargingRegular:
- std::cout << "kChargingRegular" << std::endl;
- break;
- case drivers::Samd::ChargeStatus::kChargingFast:
- std::cout << "kChargingFast" << std::endl;
- break;
- case drivers::Samd::ChargeStatus::kFullCharge:
- std::cout << "kFullCharge" << std::endl;
- break;
- }
+ std::cout << drivers::Samd::chargeStatusToString(*res) << std::endl;
} else {
std::cout << "unknown" << std::endl;
}
diff --git a/src/tangara/battery/battery.cpp b/src/tangara/battery/battery.cpp
index 3cfdb20c..9bde86a8 100644
--- a/src/tangara/battery/battery.cpp
+++ b/src/tangara/battery/battery.cpp
@@ -93,6 +93,8 @@ auto Battery::Update() -> void {
.percent = percent,
.millivolts = mV,
.is_charging = is_charging,
+ .raw_status =
+ charge_state.value_or(drivers::Samd::ChargeStatus::kUnknown),
};
EmitEvent();
}
diff --git a/src/tangara/battery/battery.hpp b/src/tangara/battery/battery.hpp
index 80b0f2d2..c4f631e0 100644
--- a/src/tangara/battery/battery.hpp
+++ b/src/tangara/battery/battery.hpp
@@ -27,6 +27,7 @@ class Battery {
uint_fast8_t percent;
uint32_t millivolts;
bool is_charging;
+ drivers::Samd::ChargeStatus raw_status;
bool operator==(const BatteryState& other) const {
return percent == other.percent && is_charging == other.is_charging;
diff --git a/src/tangara/system_fsm/booting.cpp b/src/tangara/system_fsm/booting.cpp
index a3fed9fa..1f99e3ab 100644
--- a/src/tangara/system_fsm/booting.cpp
+++ b/src/tangara/system_fsm/booting.cpp
@@ -87,7 +87,7 @@ auto Booting::entry() -> void {
ESP_LOGI(kTag, "installing remaining drivers");
drivers::spiffs_mount();
- sServices->samd(std::unique_ptr<drivers::Samd>(drivers::Samd::Create()));
+ sServices->samd(std::make_unique<drivers::Samd>(sServices->nvs()));
sServices->touchwheel(
std::unique_ptr<drivers::TouchWheel>{drivers::TouchWheel::Create()});
sServices->haptics(std::make_unique<drivers::Haptics>(sServices->nvs()));
@@ -96,8 +96,8 @@ auto Booting::entry() -> void {
sServices->battery(std::make_unique<battery::Battery>(
sServices->samd(), std::unique_ptr<drivers::AdcBattery>(adc)));
- sServices->track_queue(
- std::make_unique<audio::TrackQueue>(sServices->bg_worker(), sServices->database()));
+ sServices->track_queue(std::make_unique<audio::TrackQueue>(
+ sServices->bg_worker(), sServices->database()));
sServices->tag_parser(std::make_unique<database::TagParserImpl>());
sServices->collator(locale::CreateCollator());
sServices->tts(std::make_unique<tts::Provider>());
diff --git a/src/tangara/ui/ui_fsm.cpp b/src/tangara/ui/ui_fsm.cpp
index cd39dc9c..38e9b8e1 100644
--- a/src/tangara/ui/ui_fsm.cpp
+++ b/src/tangara/ui/ui_fsm.cpp
@@ -101,6 +101,15 @@ static auto lvgl_delay_cb(uint32_t ms) -> void {
lua::Property UiState::sBatteryPct{0};
lua::Property UiState::sBatteryMv{0};
lua::Property UiState::sBatteryCharging{false};
+lua::Property UiState::sPowerChargeState{"unknown"};
+lua::Property UiState::sPowerFastChargeEnabled{
+ false, [](const lua::LuaValue& val) {
+ if (!std::holds_alternative<bool>(val)) {
+ return false;
+ }
+ sServices->samd().SetFastChargeEnabled(std::get<bool>(val));
+ return true;
+ }};
lua::Property UiState::sBluetoothEnabled{
false, [](const lua::LuaValue& val) {
@@ -406,6 +415,13 @@ void UiState::react(const system_fsm::BatteryStateChanged& ev) {
sBatteryPct.setDirect(static_cast<int>(ev.new_state.percent));
sBatteryMv.setDirect(static_cast<int>(ev.new_state.millivolts));
sBatteryCharging.setDirect(ev.new_state.is_charging);
+ sPowerChargeState.setDirect(
+ drivers::Samd::chargeStatusToString(ev.new_state.raw_status));
+
+ // FIXME: Avoid calling these event handlers before boot.
+ if (sServices) {
+ sPowerFastChargeEnabled.setDirect(sServices->nvs().FastCharge());
+ }
}
void UiState::react(const audio::QueueUpdate&) {
@@ -414,7 +430,8 @@ void UiState::react(const audio::QueueUpdate&) {
sQueueSize.setDirect(static_cast<int>(queue_size));
int current_pos = queue.currentPosition();
- // If there is nothing in the queue, the position should be 0, otherwise, add one because lua
+ // If there is nothing in the queue, the position should be 0, otherwise, add
+ // one because lua
if (queue_size > 0) {
current_pos++;
}
@@ -564,11 +581,14 @@ void Lua::entry() {
auto& registry = lua::Registry::instance(*sServices);
sLua = registry.uiThread();
- registry.AddPropertyModule("power", {
- {"battery_pct", &sBatteryPct},
- {"battery_millivolts", &sBatteryMv},
- {"plugged_in", &sBatteryCharging},
- });
+ registry.AddPropertyModule("power",
+ {
+ {"battery_pct", &sBatteryPct},
+ {"battery_millivolts", &sBatteryMv},
+ {"plugged_in", &sBatteryCharging},
+ {"charge_state", &sPowerChargeState},
+ {"fast_charge", &sPowerFastChargeEnabled},
+ });
registry.AddPropertyModule(
"bluetooth", {
{"enabled", &sBluetoothEnabled},
@@ -663,6 +683,8 @@ void Lua::entry() {
}
sBluetoothKnownDevices.setDirect(bt.knownDevices());
+ sPowerFastChargeEnabled.setDirect(sServices->nvs().FastCharge());
+
if (sServices->sd() == drivers::SdState::kMounted) {
sLua->RunScript("/sdcard/config.lua");
}
diff --git a/src/tangara/ui/ui_fsm.hpp b/src/tangara/ui/ui_fsm.hpp
index cef9a13a..41f0db3a 100644
--- a/src/tangara/ui/ui_fsm.hpp
+++ b/src/tangara/ui/ui_fsm.hpp
@@ -101,6 +101,8 @@ class UiState : public tinyfsm::Fsm<UiState> {
static lua::Property sBatteryPct;
static lua::Property sBatteryMv;
static lua::Property sBatteryCharging;
+ static lua::Property sPowerChargeState;
+ static lua::Property sPowerFastChargeEnabled;
static lua::Property sBluetoothEnabled;
static lua::Property sBluetoothConnecting;