2024-04-29 11:38:27 -04:00
|
|
|
#include "battery.hpp"
|
|
|
|
#include "event_m0.hpp"
|
|
|
|
#include "portapack.hpp"
|
|
|
|
#include "ads1110.hpp"
|
2024-07-15 16:17:55 -04:00
|
|
|
#include "max17055.hpp"
|
2024-04-29 11:38:27 -04:00
|
|
|
|
|
|
|
// uncomment if you want to emulate batt management system
|
|
|
|
// #define USE_BATT_EMULATOR
|
|
|
|
|
|
|
|
extern I2C portapack::i2c0;
|
|
|
|
|
|
|
|
namespace battery {
|
|
|
|
|
2024-07-17 05:18:57 -04:00
|
|
|
constexpr uint32_t BATTERY_UPDATE_INTERVAL = 20000;
|
2024-04-29 11:38:27 -04:00
|
|
|
BatteryManagement::BatteryModules BatteryManagement::detected_ = BatteryManagement::BATT_NONE;
|
|
|
|
|
|
|
|
ads1110::ADS1110 battery_ads1110{portapack::i2c0, 0x48};
|
2024-07-15 16:17:55 -04:00
|
|
|
max17055::MAX17055 battery_max17055{portapack::i2c0, 0x36};
|
2024-04-29 11:38:27 -04:00
|
|
|
|
|
|
|
Thread* BatteryManagement::thread = nullptr;
|
2024-08-28 05:32:24 -04:00
|
|
|
bool BatteryManagement::calcOverride = false;
|
2024-04-29 11:38:27 -04:00
|
|
|
|
2024-07-17 05:18:57 -04:00
|
|
|
void BatteryManagement::detect() {
|
2024-04-29 11:38:27 -04:00
|
|
|
// try to detect supported modules
|
|
|
|
detected_ = BATT_NONE;
|
2024-09-20 05:59:17 -04:00
|
|
|
if (battery_max17055.detect()) {
|
|
|
|
battery_max17055.init();
|
|
|
|
detected_ = BATT_MAX17055;
|
|
|
|
return;
|
|
|
|
}
|
2024-04-29 11:38:27 -04:00
|
|
|
if (battery_ads1110.detect()) {
|
|
|
|
battery_ads1110.init();
|
|
|
|
detected_ = BATT_ADS1110;
|
2024-07-17 05:18:57 -04:00
|
|
|
return;
|
|
|
|
}
|
2024-04-29 11:38:27 -04:00
|
|
|
|
|
|
|
// add new supported module detect + init here
|
|
|
|
|
|
|
|
#ifdef USE_BATT_EMULATOR
|
|
|
|
if (detected_ == BATT_NONE) {
|
|
|
|
detected_ = BATT_EMULATOR;
|
2024-07-17 05:18:57 -04:00
|
|
|
return;
|
2024-04-29 11:38:27 -04:00
|
|
|
}
|
|
|
|
#endif
|
2024-07-17 05:18:57 -04:00
|
|
|
}
|
2024-04-29 11:38:27 -04:00
|
|
|
|
2024-08-28 05:32:24 -04:00
|
|
|
void BatteryManagement::init(bool override) {
|
|
|
|
calcOverride = override;
|
2024-07-17 05:18:57 -04:00
|
|
|
detect();
|
|
|
|
// sets timer to query and broadcats this info
|
|
|
|
create_thread();
|
2024-04-29 11:38:27 -04:00
|
|
|
}
|
|
|
|
|
2024-09-20 05:59:17 -04:00
|
|
|
bool BatteryManagement::reset_learned() {
|
|
|
|
if (detected_ == BATT_MAX17055) {
|
|
|
|
return battery_max17055.reset_learned();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-08-28 05:32:24 -04:00
|
|
|
// set if the default percentage calculation should be overrided by voltage based one
|
|
|
|
void BatteryManagement::set_calc_override(bool override) {
|
|
|
|
calcOverride = override;
|
|
|
|
}
|
|
|
|
|
2024-04-29 11:38:27 -04:00
|
|
|
// sets the values, it the currend module supports it.
|
2024-07-17 05:18:57 -04:00
|
|
|
void BatteryManagement::getBatteryInfo(uint8_t& valid_mask, uint8_t& batteryPercentage, uint16_t& voltage, int32_t& current) {
|
2024-07-15 16:17:55 -04:00
|
|
|
if (detected_ == BATT_NONE) {
|
2024-07-17 05:18:57 -04:00
|
|
|
valid_mask = BATT_VALID_NONE;
|
|
|
|
return;
|
2024-07-15 16:17:55 -04:00
|
|
|
} else if (detected_ == BATT_ADS1110) {
|
2024-08-28 05:32:24 -04:00
|
|
|
battery_ads1110.getBatteryInfo(valid_mask, voltage);
|
|
|
|
batteryPercentage = calc_percent_voltage(voltage);
|
2024-07-17 05:18:57 -04:00
|
|
|
return;
|
2024-07-15 16:17:55 -04:00
|
|
|
} else if (detected_ == BATT_MAX17055) {
|
2024-07-17 05:18:57 -04:00
|
|
|
battery_max17055.getBatteryInfo(valid_mask, batteryPercentage, voltage, current);
|
2024-08-28 05:32:24 -04:00
|
|
|
if (calcOverride) {
|
|
|
|
valid_mask &= ~BATT_VALID_PERCENT; // indicate it is voltage based
|
|
|
|
batteryPercentage = calc_percent_voltage(voltage);
|
|
|
|
}
|
2024-07-17 05:18:57 -04:00
|
|
|
return;
|
2024-04-29 11:38:27 -04:00
|
|
|
}
|
|
|
|
// add new module query here
|
|
|
|
|
|
|
|
#ifdef USE_BATT_EMULATOR
|
|
|
|
if (detected_ == BATT_EMULATOR) {
|
|
|
|
batteryPercentage += 5; // %
|
|
|
|
if (batteryPercentage > 100) batteryPercentage = 0;
|
|
|
|
voltage = rand() % 1000 + 3000; // mV
|
|
|
|
current = rand() % 150; // mA
|
|
|
|
isCharging = rand() % 2;
|
2024-08-28 05:32:24 -04:00
|
|
|
valid_mask = 7;
|
2024-04-29 11:38:27 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
(void)current;
|
|
|
|
}
|
|
|
|
|
2024-09-20 05:59:17 -04:00
|
|
|
uint16_t BatteryManagement::get_cycles() {
|
|
|
|
if (detected_ == BATT_MAX17055) {
|
|
|
|
return (uint16_t)battery_max17055.getValue("Cycles");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
float BatteryManagement::get_tte() {
|
|
|
|
if (detected_ == BATT_MAX17055) {
|
|
|
|
return battery_max17055.getValue("TTE");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
float BatteryManagement::get_ttf() {
|
|
|
|
if (detected_ == BATT_MAX17055) {
|
|
|
|
return battery_max17055.getValue("TTF");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-07-15 16:17:55 -04:00
|
|
|
uint16_t BatteryManagement::read_register(const uint8_t reg) {
|
|
|
|
if (detected_ == BATT_MAX17055) {
|
|
|
|
return battery_max17055.read_register(reg);
|
|
|
|
}
|
|
|
|
return 0xFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BatteryManagement::write_register(const uint8_t reg, const uint16_t value) {
|
|
|
|
if (detected_ == BATT_MAX17055) {
|
|
|
|
return battery_max17055.write_register(reg, value);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-04-29 11:38:27 -04:00
|
|
|
uint8_t BatteryManagement::getPercent() {
|
|
|
|
if (detected_ == BATT_NONE) return 102;
|
2024-07-17 05:18:57 -04:00
|
|
|
uint8_t validity = 0;
|
2024-04-29 11:38:27 -04:00
|
|
|
uint8_t batteryPercentage = 0;
|
|
|
|
uint16_t voltage = 0;
|
|
|
|
int32_t current = 0;
|
2024-07-17 05:18:57 -04:00
|
|
|
getBatteryInfo(validity, batteryPercentage, voltage, current);
|
|
|
|
if ((validity & BATT_VALID_VOLTAGE) != BATT_VALID_VOLTAGE) return 102;
|
2024-08-28 05:32:24 -04:00
|
|
|
if (calcOverride || ((validity & BATT_VALID_PERCENT) != BATT_VALID_PERCENT)) {
|
|
|
|
validity &= ~BATT_VALID_PERCENT; // indicate it is voltage based
|
|
|
|
batteryPercentage = calc_percent_voltage(voltage);
|
|
|
|
}
|
|
|
|
return batteryPercentage;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t BatteryManagement::calc_percent_voltage(uint16_t voltage) {
|
|
|
|
// Calculate the remaining battery percentage
|
|
|
|
uint8_t batteryPercentage = (float)(voltage - BATTERY_MIN_VOLTAGE) / (float)(BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE) * 100.0;
|
|
|
|
// Limit the values to the valid range
|
|
|
|
batteryPercentage = (batteryPercentage > 100) ? 100 : batteryPercentage;
|
2024-04-29 11:38:27 -04:00
|
|
|
return batteryPercentage;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t BatteryManagement::getVoltage() {
|
|
|
|
if (detected_ == BATT_NONE) return 0;
|
2024-07-17 05:18:57 -04:00
|
|
|
uint8_t validity = 0;
|
2024-04-29 11:38:27 -04:00
|
|
|
uint8_t batteryPercentage = 0;
|
|
|
|
uint16_t voltage = 0;
|
|
|
|
int32_t current = 0;
|
2024-07-17 05:18:57 -04:00
|
|
|
getBatteryInfo(validity, batteryPercentage, voltage, current);
|
|
|
|
if ((validity & BATT_VALID_VOLTAGE) != BATT_VALID_VOLTAGE) return 0;
|
2024-04-29 11:38:27 -04:00
|
|
|
return voltage;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg_t BatteryManagement::timer_fn(void* arg) {
|
|
|
|
(void)arg;
|
2024-07-17 05:18:57 -04:00
|
|
|
uint8_t validity = 0;
|
2024-04-29 11:38:27 -04:00
|
|
|
uint8_t batteryPercentage = 102;
|
|
|
|
uint16_t voltage = 0;
|
|
|
|
int32_t current = 0;
|
|
|
|
chThdSleepMilliseconds(1000); // wait ui for fully load
|
|
|
|
while (1) {
|
2024-07-17 05:18:57 -04:00
|
|
|
if (!detected_) {
|
|
|
|
detect(); // try to detect it again, it maybe disconnected while pp was powered up
|
|
|
|
chThdSleepMilliseconds(500);
|
|
|
|
}
|
|
|
|
if (detected_) {
|
|
|
|
BatteryManagement::getBatteryInfo(validity, batteryPercentage, voltage, current);
|
2024-04-29 11:38:27 -04:00
|
|
|
// send local message
|
2024-07-17 05:18:57 -04:00
|
|
|
BatteryStateMessage msg{validity, batteryPercentage, current >= 0, voltage};
|
2024-04-29 11:38:27 -04:00
|
|
|
EventDispatcher::send_message(msg);
|
|
|
|
}
|
|
|
|
chThdSleepMilliseconds(BATTERY_UPDATE_INTERVAL);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BatteryManagement::create_thread() {
|
|
|
|
thread = chThdCreateFromHeap(NULL, 512, NORMALPRIO, BatteryManagement::timer_fn, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace battery
|