void taskSystem(void) { // Calculate system load if (totalWaitingTasksSamples > 0) { averageSystemLoadPercent = 100 * totalWaitingTasks / totalWaitingTasksSamples; totalWaitingTasksSamples = 0; totalWaitingTasks = 0; } realtimeGuardInterval = 0; #ifdef USE_REALTIME_GUARD_INTERVAL // Calculate guard interval uint32_t maxNonRealtimeTaskTime = 0; for (const cfTask_t *task = queueFirst(); task != NULL; task = queueNext()) { if (task->staticPriority != TASK_PRIORITY_REALTIME) { maxNonRealtimeTaskTime = MAX(maxNonRealtimeTaskTime, task->averageExecutionTime); } } realtimeGuardInterval = constrain(maxNonRealtimeTaskTime, REALTIME_GUARD_INTERVAL_MIN, REALTIME_GUARD_INTERVAL_MAX) + REALTIME_GUARD_INTERVAL_MARGIN; #if defined SCHEDULER_DEBUG debug[2] = realtimeGuardInterval; #endif #endif }
void CMusicHandler::playMusic(std::string musicURI, bool loop) { if (current && current->isTrack( musicURI)) return; queueNext(this, "", musicURI, loop); }
void CMusicHandler::queueNext(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped) { try { queueNext(make_unique<MusicEntry>(owner, setName, musicURI, looped)); } catch(std::exception &e) { logGlobal->errorStream() << "Failed to queue music. setName=" << setName << "\tmusicURI=" << musicURI; logGlobal->errorStream() << "Exception: " << e.what(); } }
void CMusicHandler::playMusicFromSet(std::string whichSet, bool loop) { auto selectedSet = musicsSet.find(whichSet); if (selectedSet == musicsSet.end()) { logGlobal->errorStream() << "Error: playing music from non-existing set: " << whichSet; return; } if (current && current->isSet(whichSet)) return; // in this mode - play random track from set queueNext(this, whichSet, "", loop); }
void CMusicHandler::playMusicFromSet(std::string whichSet, int entryID, bool loop) { auto selectedSet = musicsSet.find(whichSet); if (selectedSet == musicsSet.end()) { logGlobal->errorStream() << "Error: playing music from non-existing set: " << whichSet; return; } auto selectedEntry = selectedSet->second.find(entryID); if (selectedEntry == selectedSet->second.end()) { logGlobal->errorStream() << "Error: playing non-existing entry " << entryID << " from set: " << whichSet; return; } if (current && current->isTrack( selectedEntry->second)) return; // in this mode - play specific track from set queueNext(this, "", selectedEntry->second, loop); }
void scheduler(void) { // Cache currentTime currentTime = micros(); // Check for realtime tasks uint32_t timeToNextRealtimeTask = UINT32_MAX; for (const cfTask_t *task = queueFirst(); task != NULL && task->staticPriority >= TASK_PRIORITY_REALTIME; task = queueNext()) { const uint32_t nextExecuteAt = task->lastExecutedAt + task->desiredPeriod; if ((int32_t)(currentTime - nextExecuteAt) >= 0) { timeToNextRealtimeTask = 0; } else { const uint32_t newTimeInterval = nextExecuteAt - currentTime; timeToNextRealtimeTask = MIN(timeToNextRealtimeTask, newTimeInterval); } } const bool outsideRealtimeGuardInterval = (timeToNextRealtimeTask > realtimeGuardInterval); // The task to be invoked cfTask_t *selectedTask = NULL; uint16_t selectedTaskDynamicPriority = 0; // Update task dynamic priorities uint16_t waitingTasks = 0; for (cfTask_t *task = queueFirst(); task != NULL; task = queueNext()) { // Task has checkFunc - event driven if (task->checkFunc != NULL) { // Increase priority for event driven tasks if (task->dynamicPriority > 0) { task->taskAgeCycles = 1 + ((currentTime - task->lastSignaledAt) / task->desiredPeriod); task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles; waitingTasks++; } else if (task->checkFunc(currentTime - task->lastExecutedAt)) { task->lastSignaledAt = currentTime; task->taskAgeCycles = 1; task->dynamicPriority = 1 + task->staticPriority; waitingTasks++; } else { task->taskAgeCycles = 0; } } else { // Task is time-driven, dynamicPriority is last execution age (measured in desiredPeriods) // Task age is calculated from last execution task->taskAgeCycles = ((currentTime - task->lastExecutedAt) / task->desiredPeriod); if (task->taskAgeCycles > 0) { task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles; waitingTasks++; } } if (task->dynamicPriority > selectedTaskDynamicPriority) { const bool taskCanBeChosenForScheduling = (outsideRealtimeGuardInterval) || (task->taskAgeCycles > 1) || (task->staticPriority == TASK_PRIORITY_REALTIME); if (taskCanBeChosenForScheduling) { selectedTaskDynamicPriority = task->dynamicPriority; selectedTask = task; } } } totalWaitingTasksSamples++; totalWaitingTasks += waitingTasks; currentTask = selectedTask; if (selectedTask != NULL) { // Found a task that should be run selectedTask->taskLatestDeltaTime = currentTime - selectedTask->lastExecutedAt; selectedTask->lastExecutedAt = currentTime; selectedTask->dynamicPriority = 0; // Execute task const uint32_t currentTimeBeforeTaskCall = micros(); selectedTask->taskFunc(); const uint32_t taskExecutionTime = micros() - currentTimeBeforeTaskCall; selectedTask->averageExecutionTime = ((uint32_t)selectedTask->averageExecutionTime * 31 + taskExecutionTime) / 32; #ifndef SKIP_TASK_STATISTICS selectedTask->totalExecutionTime += taskExecutionTime; // time consumed by scheduler + task selectedTask->maxExecutionTime = MAX(selectedTask->maxExecutionTime, taskExecutionTime); #endif #if defined SCHEDULER_DEBUG debug[3] = (micros() - currentTime) - taskExecutionTime; } else { debug[3] = (micros() - currentTime); #endif } GET_SCHEDULER_LOCALS(); }
void scheduler(void) { // Cache currentTime const timeUs_t currentTimeUs = micros(); // Check for realtime tasks timeUs_t timeToNextRealtimeTask = TIMEUS_MAX; for (const cfTask_t *task = queueFirst(); task != NULL && task->staticPriority >= TASK_PRIORITY_REALTIME; task = queueNext()) { const timeUs_t nextExecuteAt = task->lastExecutedAt + task->desiredPeriod; if ((int32_t)(currentTimeUs - nextExecuteAt) >= 0) { timeToNextRealtimeTask = 0; } else { const timeUs_t newTimeInterval = nextExecuteAt - currentTimeUs; timeToNextRealtimeTask = MIN(timeToNextRealtimeTask, newTimeInterval); } } const bool outsideRealtimeGuardInterval = (timeToNextRealtimeTask > 0); // The task to be invoked cfTask_t *selectedTask = NULL; uint16_t selectedTaskDynamicPriority = 0; // Update task dynamic priorities uint16_t waitingTasks = 0; for (cfTask_t *task = queueFirst(); task != NULL; task = queueNext()) { // Task has checkFunc - event driven if (task->checkFunc) { const timeUs_t currentTimeBeforeCheckFuncCallUs = micros(); // Increase priority for event driven tasks if (task->dynamicPriority > 0) { task->taskAgeCycles = 1 + ((timeDelta_t)(currentTimeUs - task->lastSignaledAt)) / task->desiredPeriod; task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles; waitingTasks++; } else if (task->checkFunc(currentTimeBeforeCheckFuncCallUs, currentTimeBeforeCheckFuncCallUs - task->lastExecutedAt)) { #ifndef SKIP_TASK_STATISTICS const timeUs_t checkFuncExecutionTime = micros() - currentTimeBeforeCheckFuncCallUs; checkFuncMovingSumExecutionTime -= checkFuncMovingSumExecutionTime / TASK_MOVING_SUM_COUNT; checkFuncMovingSumExecutionTime += checkFuncExecutionTime; checkFuncTotalExecutionTime += checkFuncExecutionTime; // time consumed by scheduler + task checkFuncMaxExecutionTime = MAX(checkFuncMaxExecutionTime, checkFuncExecutionTime); #endif task->lastSignaledAt = currentTimeBeforeCheckFuncCallUs; task->taskAgeCycles = 1; task->dynamicPriority = 1 + task->staticPriority; waitingTasks++; } else { task->taskAgeCycles = 0; } } else { // Task is time-driven, dynamicPriority is last execution age (measured in desiredPeriods) // Task age is calculated from last execution task->taskAgeCycles = ((timeDelta_t)(currentTimeUs - task->lastExecutedAt)) / task->desiredPeriod; if (task->taskAgeCycles > 0) { task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles; waitingTasks++; } } if (task->dynamicPriority > selectedTaskDynamicPriority) { const bool taskCanBeChosenForScheduling = (outsideRealtimeGuardInterval) || (task->taskAgeCycles > 1) || (task->staticPriority == TASK_PRIORITY_REALTIME); if (taskCanBeChosenForScheduling) { selectedTaskDynamicPriority = task->dynamicPriority; selectedTask = task; } } } totalWaitingTasksSamples++; totalWaitingTasks += waitingTasks; currentTask = selectedTask; if (selectedTask) { // Found a task that should be run selectedTask->taskLatestDeltaTime = (timeDelta_t)(currentTimeUs - selectedTask->lastExecutedAt); selectedTask->lastExecutedAt = currentTimeUs; selectedTask->dynamicPriority = 0; // Execute task const timeUs_t currentTimeBeforeTaskCall = micros(); selectedTask->taskFunc(currentTimeBeforeTaskCall); #ifndef SKIP_TASK_STATISTICS const timeUs_t taskExecutionTime = micros() - currentTimeBeforeTaskCall; selectedTask->movingSumExecutionTime += taskExecutionTime - selectedTask->movingSumExecutionTime / TASK_MOVING_SUM_COUNT; selectedTask->totalExecutionTime += taskExecutionTime; // time consumed by scheduler + task selectedTask->maxExecutionTime = MAX(selectedTask->maxExecutionTime, taskExecutionTime); #endif #if defined(SCHEDULER_DEBUG) DEBUG_SET(DEBUG_SCHEDULER, 2, micros() - currentTimeUs - taskExecutionTime); // time spent in scheduler } else { DEBUG_SET(DEBUG_SCHEDULER, 2, micros() - currentTimeUs); #endif } }