/** * @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 #include #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 currentAllowances; }; static PowerScheduler *powerSchedulerInstance; #endif // PowerScheduler_h