dezibot/src/power/Power.h

192 lines
6.2 KiB
C++

/**
* @file Power.h
* @author Phillip Kühne
* @brief This component provides utilities for keeping track of power usage
* consumption.
* @version 0.1
* @date 2024-11-23
*/
#include "PowerScheduler.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc/adc_oneshot.h"
#include "freertos/semphr.h"
#ifndef Power_h
#define Power_h
#define TAG "Power"
enum TaskResumptionReason { POWER_AVAILABLE, TIMEOUT };
class Power {
private:
static SemaphoreHandle_t powerMutex;
static constexpr uint16_t MUTEX_TIMEOUT_MS = 1;
// RAII for mutex
class PowerMutex {
private:
SemaphoreHandle_t &mutex;
bool locked;
public:
PowerMutex(SemaphoreHandle_t &mutex) : mutex(mutex), locked(false) {
locked =
(xSemaphoreTake(mutex, pdMS_TO_TICKS(MUTEX_TIMEOUT_MS)) == pdTRUE);
if (!locked) {
ESP_LOGW(TAG, "Could not take power mutex");
}
}
~PowerMutex() {
if (locked) {
xSemaphoreGive(mutex);
}
}
bool isLocked() { return locked; }
};
protected:
/// @brief PowerScheduler instance to manage power consumption
static PowerScheduler *powerScheduler;
/*
* Power State
*/
/// @brief last time of power state update
static TickType_t lastPowerStateUpdate;
/// @brief remaining Charge in coulombs
static float coloumbsRemaining;
/// @brief remaining Charge in percent
static float percentRemaining;
static bool busPowered;
static bool chargingState;
/// @brief Circular array of last calculated values for current state of
/// charge
static float lastSOC[PowerParameters::Battery::AVERAGING_SAMPLES];
static int latestSoCIndex;
/// @brief Add calculated value to circular array, pushing out oldest value
static void addSoCSample(float soc);
/// @brief initialize the power state
static void initPowerState(void);
public:
static void begin(void);
Power();
~Power();
/// @brief Get the current free current budget (to C1 discharge)
/// @return the amount of power that is currently available (in mA)
static float getFreeLimitCurrentBudget(void);
/// @brief Get the current hard maximum free current (to C2 discharge)
/// @return the maximum amount of power that can be allocated (in mA)
static float getFreeMaximumCurrentBudget(void);
/// @brief Request an allowance of a certain number of milliamperes from the
/// power scheduler without waiting for it (meaning it will not be scheduled
/// for future allocation). Only one can be active per consumer.
/// @param neededCurrent the amount of current we want to be accounted for
/// (in mA)
/// @return whether the current could be successfully allocated
static bool
tryAccquireCurrentAllowance(PowerParameters::PowerConsumers consumer,
uint16_t neededcurrent,
uint16_t requestedDurationMs = 0);
/// @brief "Return" the current currently allocated to a consumer
/// @param consumer the active consumer to release the current for
static void releaseCurrent(PowerParameters::PowerConsumers consumer);
/// @brief Wait for a certain amount of current to be available. This will
/// "reseve a spot in the queue". Only one can be active per consumer.
/// @param neededCurrent the amount of power we want to be accounted for (in
/// mW)
/// @param TicksToWait the amount of time to wait for the power to become
/// available
/// @return whether the power could be successfully allocatedy
static bool waitForCurrentAllowance(PowerParameters::PowerConsumers consumer,
uint16_t neededCurrent,
uint16_t maxSlackTimeMs,
uint16_t requestedDurationMs);
/// @brief Put the ESP32 into deep sleep mode, without a method to wake up
/// again. Basically this is a shutdown.
static void beginPermanentDeepSleep(void);
//// @brief Get currently granted power
/// @return the amount of power that is currently allocated (in mA)
static float getCurrentCurrent(void);
/// @brief Responsible for recalculating the current budgets
/// @note these change based on the current state of charge
static void recalculateCurrentBudgets(void);
// @brief Get current consumption of a consumer
static float getConsumerCurrent(PowerParameters::PowerConsumers consumer);
/// @brief Get battery voltage measurement.
/// @return Battery Terminal Voltage in Volts
static float getBatteryVoltage();
/// @brief Get estimated battery charge state as percentage
/// @return Battery charge state in percent
static float getBatteryChargePercent();
/// @brief Get estimated battery charge state as percentage based on
// voltage directly
/// @return Battery charge state in percent
static float getBatteryVoltageChargePercent();
/// @brief Get estimated battery charge state as coulombs
/// @return Battery charge state in coulombs
static float getBatteryChargeCoulombs();
/// @brief get available current (after voltage conversion and efficiency
/// losses, referencing 1C discharge)
/// @return available current in milliamps
static float getMax3V3Current();
/// @brief update Power State
/// @note needs to be public for task creation
static void updatePowerStateHandler();
/// @brief dump power statistics to serial
static void dumpPowerStatistics();
/// @brief dump consumer statistics to serial
static void dumpConsumerStatistics();
/// @brief get wether power is supplied via USB
/// @return true if power is supplied via USB
static bool isUSBPowered();
/// @brief get wether power is supplied via battery
/// @return true if power is supplied via battery
static bool isBatteryPowered();
/// @brief get wether the battery is currently charging
/// @return true if the battery is charging
static bool isBatteryCharging();
/// @brief get wether the battery is currently discharging
/// @return true if the battery is discharging
static bool isBatteryDischarging();
/// @brief get wether the battery is currently fully charged
/// @return true if the battery is fully charged
static bool isBatteryFullyCharged();
};
extern Power power;
#endif // Power