/** * @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 "Power.h" static portMUX_TYPE mux; Power::Power() { this->freePowerBudget = this->totalPowerBudget; } void Power::begin() { if (powerInstance == nullptr) { // Double check locking https://www.aristeia.com/Papers/DDJ%5FJul%5FAug%5F2004%5Frevised.pdf taskENTER_CRITICAL(&mux); if (powerInstance == nullptr) { powerInstance = new Power(); } taskEXIT_CRITICAL(&mux); } else { // Power.begin() was called twice! Serial.println("Power.begin() was called twice! No harm done, but this is a bug."); } } Power *Power::getPowerManager() { return powerInstance; } bool Power::tryAccquirePowerAllowance(uint16_t neededPower) { if (this->freePowerBudget >= neededPower) { this->freePowerBudget -= neededPower; return true; } else { return false; } } void Power::releasePower(uint16_t power) { if (this->freePowerBudget + power <= this->totalPowerBudget) { this->freePowerBudget += power; } else // TODO: Maybe we should actually throw an error here, since obviouslsy someone used us wrong. { this->freePowerBudget = this->totalPowerBudget; } // Check if there are tasks waiting for power checkWaitingTasks(); } bool Power::waitForPowerAllowance(uint16_t neededPower, TickType_t ticksToWait) { if (tryAccquirePowerAllowance(neededPower)) { return true; } else { // Suspend the task while waiting for power to be available TaskHandle_t currentTask = xTaskGetCurrentTaskHandle(); TickType_t initialTickCount = xTaskGetTickCount(); waitingTasks.push(currentTask); uint32_t notificationValue; BaseType_t notificationStatus = xTaskNotifyWait(0, 0, ¬ificationValue, ticksToWait); // Code below will be executed after the task is woken up while (notificationStatus == pdPASS) { if (notificationValue == POWER_AVAILABLE) { // We were woken up because new power is available, check if it is enough if (tryAccquirePowerAllowance(neededPower)) { return true; } else { // Still not enough power available for us. Wait the remaining ticks. xTaskNotifyWait(0, 0, ¬ificationValue, ticksToWait - (xTaskGetTickCount() - initialTickCount)); } } } if (notificationStatus == pdFALSE) { // We waited long enough... return false; } else { // Should be impossible to reach throw "Reached impossible state"; } } } void Power::checkWaitingTasks(void) { // Check if there are tasks waiting for power if (!waitingTasks.empty()) { TaskHandle_t task = waitingTasks.front(); waitingTasks.pop(); xTaskNotify(task, POWER_AVAILABLE, eSetValueWithOverwrite); } }