dezibot/src/power/PowerScheduler.h

126 lines
4.6 KiB
C++

/**
* @file PowerScheduler.hpp
* @author Phillip Kühne
* @brief The actual power scheduler class, which keeps track of the power
* budget and allocates power to different components.
* @version 0.1
* @date 2024-12-21
*
* @copyright (c) 2024
*
*/
#include "PowerParameters.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <Arduino.h>
#include <vector>
#ifndef PowerScheduler_h
#define PowerScheduler_h
class PowerScheduler {
private:
static constexpr uint16_t DEFAULT_SLACK_TIME_MS = 100;
PowerScheduler(float i_limit_ma, float i_max_ma);
public:
~PowerScheduler();
/// @brief Initialize the singleton instance of the power manager
/// @return reference to the power manager
static PowerScheduler &getPowerScheduler(float i_limit_ma = 0,
float i_max_ma = 0);
/// @brief Get the current free current budget (to C1 discharge)
/// @return the amount of power that is currently available (in mA)
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)
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
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
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
bool waitForCurrentAllowance(PowerParameters::PowerConsumers consumer,
uint16_t neededCurrent,
uint16_t maxSlackTimeMs = DEFAULT_SLACK_TIME_MS,
uint16_t requestedDurationMs = 0);
/// @brief Put the ESP32 into deep sleep mode, without a method to wake up
/// again. Basically this is a shutdown.
void beginPermanentDeepSleep(void);
//// @brief Get currently granted power
/// @return the amount of power that is currently allocated (in mA)
float getCurrentCurrent(void);
/// @brief Power consumer data structure
struct CurrentAllowance {
PowerParameters::PowerConsumers consumer;
uint16_t maxSlackTimeMs;
uint16_t requestedDurationMs;
TaskHandle_t taskHandle;
uint16_t neededCurrent;
TickType_t requestedAt;
TickType_t grantedAt;
bool granted;
};
// @brief waiting task wakeup reasons
enum PowerWakeupReasons {
POWER_AVAILABLE = 1,
POWER_EXPIRED = 2,
};
// @brief Responsible for recalculating the current budgets
void recalculateCurrentBudgets(void);
// @brief Get current consumption of a consumer
float getConsumerCurrent(PowerParameters::PowerConsumers consumer);
// @brief Retrieve the current allowance for a given consumer
CurrentAllowance *
getCurrentAllowance(PowerParameters::PowerConsumers consumer);
// @brief Retrieve the current allowance for a given task
CurrentAllowance *getCurrentAllowance(TaskHandle_t taskHandle);
// @brief Retrieve the allowance that will expire next
CurrentAllowance *getNextExpiringAllowance(void);
protected:
// Current above which there will be no new scheduling
uint16_t limitCurrent;
// Absolute maximum current that can be allocated
uint16_t maximumCurrent;
// Current budget that is currently available to limitCurrent
int16_t freeLimitCurrentBudget;
// Current budget that is currently available to maximumCurrent
int16_t freeMaximumCurrentBudget;
// @brief Responsible for selecting the next task to be granted power
void checkWaitingTasks(void);
// @brief Mutex to protect the power scheduler from concurrent access
static portMUX_TYPE mux;
std::vector<PowerScheduler::CurrentAllowance> currentAllowances;
};
static PowerScheduler *powerSchedulerInstance;
#endif // PowerScheduler_h