continued with hk data pool

added deadline missed check for fixed timeslot task,
improved doc for both periodic task and fixed timeslot task
This commit is contained in:
Robin Müller 2020-06-19 14:25:03 +02:00
parent 84b8d733c0
commit 60ae2d4565
20 changed files with 261 additions and 100 deletions

View File

@ -53,6 +53,10 @@ ReturnValue_t DataSetBase::read(uint32_t lockTimeout) {
return result; return result;
} }
uint16_t DataSetBase::getFillCount() const {
return fillCount;
}
ReturnValue_t DataSetBase::readVariable(uint16_t count) { ReturnValue_t DataSetBase::readVariable(uint16_t count) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
// These checks are often performed by the respective // These checks are often performed by the respective

View File

@ -101,6 +101,8 @@ public:
*/ */
virtual ReturnValue_t unlockDataPool() override; virtual ReturnValue_t unlockDataPool() override;
virtual uint16_t getFillCount() const;
/* SerializeIF implementations */ /* SerializeIF implementations */
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
const size_t maxSize, bool bigEndian) const override; const size_t maxSize, bool bigEndian) const override;

View File

@ -43,6 +43,7 @@ public:
*/ */
virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0; virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0;
virtual uint16_t getFillCount() const = 0;
private: private:
/** /**
* @brief Most underlying data structures will have a pool like structure * @brief Most underlying data structures will have a pool like structure

View File

@ -33,7 +33,7 @@ LocalDataPoolManager::~LocalDataPoolManager() {}
ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() {
if(not mapInitialized) { if(not mapInitialized) {
ReturnValue_t result = ReturnValue_t result =
owner->initializeHousekeepingPoolEntries(localDpMap); owner->initializePoolEntries(localDpMap);
if(result == HasReturnvaluesIF::RETURN_OK) { if(result == HasReturnvaluesIF::RETURN_OK) {
mapInitialized = true; mapInitialized = true;
} }
@ -48,6 +48,14 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(
HousekeepingMessage& message) { HousekeepingMessage& message) {
Command_t command = message.getCommand(); Command_t command = message.getCommand();
switch(command) { switch(command) {
// I think those are the only commands which can be handled here..
case(HousekeepingMessage::ADD_HK_REPORT_STRUCT):
case(HousekeepingMessage::ADD_DIAGNOSTICS_REPORT_STRUCT):
// We should use OwnsLocalPoolDataIF to specify those functions..
return HasReturnvaluesIF::RETURN_OK;
case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES):
case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES):
return generateSetStructurePacket(message.getSid());
case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT):
case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT):
return generateHousekeepingPacket(message.getSid()); return generateHousekeepingPacket(message.getSid());
@ -114,13 +122,41 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid) {
return result; return result;
} }
ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid) {
LocalDataSet* dataSet = dynamic_cast<LocalDataSet*>(
owner->getDataSetHandle(sid));
if(dataSet == nullptr) {
sif::warning << "HousekeepingManager::generateHousekeepingPacket:"
" Set ID not found" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
size_t expectedSize = dataSet->getFillCount() * sizeof(lp_id_t);
uint8_t* storePtr = nullptr;
store_address_t storeId;
ReturnValue_t result = ipcStore->getFreeElement(&storeId,
expectedSize,&storePtr);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "HousekeepingManager::generateHousekeepingPacket: "
"Could not get free element from IPC store." << std::endl;
return result;
}
size_t size = 0;
result = dataSet->serializeLocalPoolIds(&storePtr, &size,
expectedSize, false);
if(expectedSize != size) {
sif::error << "HousekeepingManager::generateSetStructurePacket: "
"Expected size is not equal to serialized size" << std::endl;
}
return result;
}
ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(
store_address_t *storeId, LocalDataSet* dataSet) { store_address_t *storeId, LocalDataSet* dataSet) {
size_t hkSize = dataSet->getSerializedSize(); size_t hkSize = dataSet->getSerializedSize();
uint8_t* storePtr = nullptr; uint8_t* storePtr = nullptr;
ReturnValue_t result = ipcStore->getFreeElement(storeId, hkSize,&storePtr); ReturnValue_t result = ipcStore->getFreeElement(storeId, hkSize,&storePtr);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "HousekeepingManager::generateHousekeepingPacket: " sif::error << "HousekeepingManager::generateHousekeepingPacket: "
"Could not get free element from IPC store." << std::endl; "Could not get free element from IPC store." << std::endl;
return result; return result;
} }

View File

@ -56,6 +56,8 @@ public:
LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete; LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete;
ReturnValue_t generateHousekeepingPacket(sid_t sid); ReturnValue_t generateHousekeepingPacket(sid_t sid);
ReturnValue_t generateSetStructurePacket(sid_t sid);
ReturnValue_t handleHousekeepingMessage(HousekeepingMessage& message); ReturnValue_t handleHousekeepingMessage(HousekeepingMessage& message);
/** /**

View File

@ -1,5 +1,6 @@
#include <framework/datapoollocal/LocalDataPoolManager.h> #include <framework/datapoollocal/LocalDataPoolManager.h>
#include <framework/datapoollocal/LocalDataSet.h> #include <framework/datapoollocal/LocalDataSet.h>
#include <framework/serialize/SerializeAdapter.h>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
@ -67,6 +68,21 @@ ReturnValue_t LocalDataSet::unlockDataPool() {
return mutex->unlockMutex(); return mutex->unlockMutex();
} }
ReturnValue_t LocalDataSet::serializeLocalPoolIds(uint8_t** buffer,
size_t* size, const size_t maxSize, bool bigEndian) const {
for (uint16_t count = 0; count < fillCount; count++) {
lp_id_t currentPoolId = registeredVariables[count]->getDataPoolId();
auto result = AutoSerializeAdapter::serialize(&currentPoolId, buffer,
size, maxSize, bigEndian);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization"
" error!" << std::endl;
return result;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
void LocalDataSet::bitSetter(uint8_t* byte, uint8_t position, void LocalDataSet::bitSetter(uint8_t* byte, uint8_t position,
bool value) const { bool value) const {
if(position > 7) { if(position > 7) {

View File

@ -68,7 +68,10 @@ public:
* @return * @return
*/ */
ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer, ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer,
size_t* size, const size_t maxSize, bool bigEndian) const ; size_t* size, const size_t maxSize, bool bigEndian) const;
ReturnValue_t serializeLocalPoolIds(uint8_t** buffer,
size_t* size, const size_t maxSize, bool bigEndian) const;
protected: protected:
private: private:
/** /**

View File

@ -42,12 +42,36 @@ public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF;
/** Command queue for housekeeping messages. */
virtual MessageQueueId_t getCommandQueue() const = 0; virtual MessageQueueId_t getCommandQueue() const = 0;
virtual ReturnValue_t initializeHousekeepingPoolEntries(
LocalDataPool& localDataPoolMap) = 0; /** Is used by pool owner to initialize the pool map once */
//virtual float setMinimalHkSamplingFrequency() = 0; virtual ReturnValue_t initializePoolEntries(
LocalDataPool& localDataPoolMap) = 0;
/** Can be used to get a handle to the local data pool manager. */
virtual LocalDataPoolManager* getHkManagerHandle() = 0; virtual LocalDataPoolManager* getHkManagerHandle() = 0;
/**
* This function is used by the pool manager to get a valid dataset
* from a SID
* @param sid Corresponding structure ID
* @return
*/
virtual DataSetIF* getDataSetHandle(sid_t sid) = 0; virtual DataSetIF* getDataSetHandle(sid_t sid) = 0;
/* These function can be implemented by pool owner, as they are required
* by the housekeeping message interface */
virtual ReturnValue_t addDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t removeDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t changeCollectionInterval(sid_t sid,
dur_seconds_t newInterval) {
return HasReturnvaluesIF::RETURN_FAILED;
};
}; };
#endif /* FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ */ #endif /* FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ */

View File

@ -1350,7 +1350,7 @@ void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {
} }
void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){
executingTask = task_; executingTask = task_;
} }
// Default implementations empty. // Default implementations empty.
@ -1360,7 +1360,7 @@ void DeviceHandlerBase::debugInterface(uint8_t positionTracker,
void DeviceHandlerBase::performOperationHook() { void DeviceHandlerBase::performOperationHook() {
} }
ReturnValue_t DeviceHandlerBase::initializeHousekeepingPoolEntries( ReturnValue_t DeviceHandlerBase::initializePoolEntries(
LocalDataPool &localDataPoolMap) { LocalDataPool &localDataPoolMap) {
return RETURN_OK; return RETURN_OK;
} }
@ -1369,6 +1369,19 @@ LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() {
return &hkManager; return &hkManager;
} }
ReturnValue_t DeviceHandlerBase::addDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t DeviceHandlerBase::removeDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t DeviceHandlerBase::changeCollectionInterval(sid_t sid,
dur_seconds_t newInterval) {
return HasReturnvaluesIF::RETURN_OK;
}
DataSetIF* DeviceHandlerBase::getDataSetHandle(sid_t sid) { DataSetIF* DeviceHandlerBase::getDataSetHandle(sid_t sid) {
auto iter = deviceReplyMap.find(sid.ownerSetId); auto iter = deviceReplyMap.find(sid.ownerSetId);
if(iter != deviceReplyMap.end()) { if(iter != deviceReplyMap.end()) {

View File

@ -477,12 +477,17 @@ protected:
* @param localDataPoolMap * @param localDataPoolMap
* @return * @return
*/ */
virtual ReturnValue_t initializeHousekeepingPoolEntries( virtual ReturnValue_t initializePoolEntries(
LocalDataPool& localDataPoolMap) override; LocalDataPool& localDataPoolMap) override;
/** Get the HK manager object handle */ /** Get the HK manager object handle */
virtual LocalDataPoolManager* getHkManagerHandle() override; virtual LocalDataPoolManager* getHkManagerHandle() override;
virtual ReturnValue_t addDataSet(sid_t sid) override;
virtual ReturnValue_t removeDataSet(sid_t sid) override;
virtual ReturnValue_t changeCollectionInterval(sid_t sid,
dur_seconds_t newInterval) override;
/** /**
* @brief Hook function for child handlers which is called once per * @brief Hook function for child handlers which is called once per
* performOperation(). Default implementation is empty. * performOperation(). Default implementation is empty.
@ -703,7 +708,9 @@ protected:
bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown.
PeriodicTaskIF* executingTask = nullptr;//!< Pointer to the task which executes this component, is invalid before setTaskIF was called. //! Pointer to the task which executes this component, is invalid
//! before setTaskIF was called.
PeriodicTaskIF* executingTask = nullptr;
static object_id_t powerSwitcherId; //!< Object which switches power on and off. static object_id_t powerSwitcherId; //!< Object which switches power on and off.

View File

@ -8,13 +8,16 @@
const uint16_t EventManager::POOL_SIZES[N_POOLS] = { const uint16_t EventManager::POOL_SIZES[N_POOLS] = {
sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher), sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher),
sizeof(ReporterRangeMatcher) }; sizeof(ReporterRangeMatcher) };
//If one checks registerListener calls, there are around 40 (to max 50) objects registering for certain events. // If one checks registerListener calls, there are around 40 (to max 50)
//Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. So a good guess is 75 to a max of 100 pools required for each, which fits well. // objects registering for certain events.
// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher.
// So a good guess is 75 to a max of 100 pools required for each, which fits well.
// SHOULDDO: Shouldn't this be in the config folder and passed via ctor?
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 }; const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 };
EventManager::EventManager(object_id_t setObjectId) : EventManager::EventManager(object_id_t setObjectId) :
SystemObject(setObjectId), eventReportQueue(NULL), mutex(NULL), factoryBackend( SystemObject(setObjectId),
0, POOL_SIZES, N_ELEMENTS, false, true) { factoryBackend(0, POOL_SIZES, N_ELEMENTS, false, true) {
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
eventReportQueue = QueueFactory::instance()->createMessageQueue( eventReportQueue = QueueFactory::instance()->createMessageQueue(
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE); MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE);

View File

@ -36,11 +36,11 @@ public:
ReturnValue_t performOperation(uint8_t opCode); ReturnValue_t performOperation(uint8_t opCode);
protected: protected:
MessageQueueIF* eventReportQueue; MessageQueueIF* eventReportQueue = nullptr;
std::map<MessageQueueId_t, EventMatchTree> listenerList; std::map<MessageQueueId_t, EventMatchTree> listenerList;
MutexIF* mutex; MutexIF* mutex = nullptr;
static const uint8_t N_POOLS = 3; static const uint8_t N_POOLS = 3;
LocalPool<N_POOLS> factoryBackend; LocalPool<N_POOLS> factoryBackend;

View File

@ -1,6 +1,7 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include "FixedTimeslotTask.h" #include "FixedTimeslotTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h>
uint32_t FixedTimeslotTask::deadlineMissedCount = 0; uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
@ -18,16 +19,19 @@ FixedTimeslotTask::~FixedTimeslotTask() {
void FixedTimeslotTask::taskEntryPoint(void* argument) { void FixedTimeslotTask::taskEntryPoint(void* argument) {
//The argument is re-interpreted as FixedTimeslotTask. The Task object is global, so it is found from any place. // The argument is re-interpreted as FixedTimeslotTask. The Task object is
// global, so it is found from any place.
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument)); FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
// Task should not start until explicitly requested /* Task should not start until explicitly requested,
// in FreeRTOS, tasks start as soon as they are created if the scheduler is running * but in FreeRTOS, tasks start as soon as they are created if the scheduler
// but not if the scheduler is not running. * is running but not if the scheduler is not running.
// to be able to accommodate both cases we check a member which is set in #startTask() * To be able to accommodate both cases we check a member which is set in
// if it is not set and we get here, the scheduler was started before #startTask() was called and we need to suspend * #startTask(). If it is not set and we get here, the scheduler was started
// if it is set, the scheduler was not running before #startTask() was called and we can continue * before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we
* can continue */
if (!originalTask->started) { if (not originalTask->started) {
vTaskSuspend(NULL); vTaskSuspend(NULL);
} }
@ -81,7 +85,8 @@ ReturnValue_t FixedTimeslotTask::checkSequence() const {
} }
void FixedTimeslotTask::taskFunctionality() { void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry. // A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry.
SlotListIter slotListIter = pst.current; SlotListIter slotListIter = pst.current;
//The start time for the first entry is read. //The start time for the first entry is read.
@ -101,17 +106,30 @@ void FixedTimeslotTask::taskFunctionality() {
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
//The component for this slot is executed and the next one is chosen. //The component for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance(); this->pst.executeAndAdvance();
if (pst.slotFollowsImmediately()) { if (not pst.slotFollowsImmediately()) {
//Do nothing /* If all operations are finished and the difference of the
} else { * current time minus the last wake time is larger than the
// we need to wait before executing the current slot * expected wait period, a deadline was missed. */
//this gives us the time to wait: if(xTaskGetTickCount() - xLastWakeTime >=
intervalMs = this->pst.getIntervalToPreviousSlotMs(); pdMS_TO_TICKS(this->pst.getIntervalToPreviousSlotMs())) {
interval = pdMS_TO_TICKS(intervalMs); #ifdef DEBUG
vTaskDelayUntil(&xLastWakeTime, interval); sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) <<
//TODO deadline missed check " missed deadline!\n" << std::flush;
} #endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
// Continue immediately, no need to wait.
break;
}
// we need to wait before executing the current slot
//this gives us the time to wait:
intervalMs = this->pst.getIntervalToPreviousSlotMs();
interval = pdMS_TO_TICKS(intervalMs);
vTaskDelayUntil(&xLastWakeTime, interval);
}
} }
} }

View File

@ -1,12 +1,12 @@
#ifndef POLLINGTASK_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#define POLLINGTASK_H_ #define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#include <framework/devicehandlers/FixedSlotSequence.h> #include <framework/devicehandlers/FixedSlotSequence.h>
#include <framework/tasks/FixedTimeslotTaskIF.h> #include <framework/tasks/FixedTimeslotTaskIF.h>
#include <framework/tasks/Typedef.h> #include <framework/tasks/Typedef.h>
#include <FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include "task.h" #include <freertos/task.h>
class FixedTimeslotTask: public FixedTimeslotTaskIF { class FixedTimeslotTask: public FixedTimeslotTaskIF {
public: public:
@ -29,16 +29,18 @@ public:
/** /**
* @brief The destructor of the class. * @brief The destructor of the class.
* * @details
* @details The destructor frees all heap memory that was allocated on thread initialization for the PST and * The destructor frees all heap memory that was allocated on thread
* the device handlers. This is done by calling the PST's destructor. * initialization for the PST and the device handlers. This is done by
* calling the PST's destructor.
*/ */
virtual ~FixedTimeslotTask(void); virtual ~FixedTimeslotTask(void);
ReturnValue_t startTask(void); ReturnValue_t startTask(void);
/** /**
* This static function can be used as #deadlineMissedFunc. * This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time. * It counts missedDeadlines and prints the number of missed deadlines
* every 10th time.
*/ */
static void missedDeadlineCounter(); static void missedDeadlineCounter();
/** /**
@ -62,30 +64,29 @@ protected:
FixedSlotSequence pst; FixedSlotSequence pst;
/** /**
* @brief This attribute holds a function pointer that is executed when a deadline was missed. * @brief This attribute holds a function pointer that is executed when
* * a deadline was missed.
* @details Another function may be announced to determine the actions to perform when a deadline was missed. * @details
* Currently, only one function for missing any deadline is allowed. * Another function may be announced to determine the actions to perform
* If not used, it shall be declared NULL. * when a deadline was missed. Currently, only one function for missing
* any deadline is allowed. If not used, it shall be declared NULL.
*/ */
void (*deadlineMissedFunc)(void); void (*deadlineMissedFunc)(void);
/** /**
* @brief This is the entry point in a new polling thread. * @brief This is the entry point for a new task.
* * @details
* @details This method, that is the generalOSAL::checkAndRestartPeriod( this->periodId, interval ); entry point in the new thread, is here set to generate * This method starts the task by calling taskFunctionality(), as soon as
* and link the Polling Sequence Table to the thread object and start taskFunctionality() * all requirements (task scheduler has started and startTask()
* on success. If operation of the task is ended for some reason, * has been called) are met.
* the destructor is called to free allocated memory.
*/ */
static void taskEntryPoint(void* argument); static void taskEntryPoint(void* argument);
/** /**
* @brief This function holds the main functionality of the thread. * @brief This function holds the main functionality of the thread.
* * @details
* * Core function holding the main functionality of the task
* @details Holding the main functionality of the task, this method is most important. * It links the functionalities provided by FixedSlotSequence with the
* It links the functionalities provided by FixedSlotSequence with the OS's System Calls * OS's System Calls to keep the timing of the periods.
* to keep the timing of the periods.
*/ */
void taskFunctionality(void); void taskFunctionality(void);
}; };

View File

@ -12,8 +12,8 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
BaseType_t status = xTaskCreate(taskEntryPoint, name, BaseType_t status = xTaskCreate(taskEntryPoint, name,
setStack, this, setPriority, &handle); setStack, this, setPriority, &handle);
if(status != pdPASS){ if(status != pdPASS){
sif::debug << "PeriodicTask Insufficient heap memory remaining. Status: " sif::debug << "PeriodicTask Insufficient heap memory remaining. "
<< status << std::endl; "Status: " << status << std::endl;
} }
} }
@ -23,14 +23,17 @@ PeriodicTask::~PeriodicTask(void) {
} }
void PeriodicTask::taskEntryPoint(void* argument) { void PeriodicTask::taskEntryPoint(void* argument) {
//The argument is re-interpreted as PeriodicTask. The Task object is global, so it is found from any place. // The argument is re-interpreted as PeriodicTask. The Task object is
// global, so it is found from any place.
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument)); PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
// Task should not start until explicitly requested /* Task should not start until explicitly requested,
// in FreeRTOS, tasks start as soon as they are created if the scheduler is running * but in FreeRTOS, tasks start as soon as they are created if the scheduler
// but not if the scheduler is not running. * is running but not if the scheduler is not running.
// to be able to accommodate both cases we check a member which is set in #startTask() * To be able to accommodate both cases we check a member which is set in
// if it is not set and we get here, the scheduler was started before #startTask() was called and we need to suspend * #startTask(). If it is not set and we get here, the scheduler was started
// if it is set, the scheduler was not running before #startTask() was called and we can continue * before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we
* can continue */
if (not originalTask->started) { if (not originalTask->started) {
vTaskSuspend(NULL); vTaskSuspend(NULL);
@ -61,9 +64,9 @@ void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime; TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
/* The xLastWakeTime variable needs to be initialized with the current tick /* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to explicitly. count. Note that this is the only time the variable is written to
After this assignment, xLastWakeTime is updated automatically internally within explicitly. After this assignment, xLastWakeTime is updated automatically
vTaskDelayUntil(). */ internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount(); xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
@ -76,12 +79,15 @@ void PeriodicTask::taskFunctionality() {
* current time minus the last wake time is larger than the * current time minus the last wake time is larger than the
* wait period, a deadline was missed. */ * wait period, a deadline was missed. */
if(xTaskGetTickCount() - xLastWakeTime >= xPeriod) { if(xTaskGetTickCount() - xLastWakeTime >= xPeriod) {
#ifdef DEBUG
sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush; " missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) { if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc(); this->deadlineMissedFunc();
} }
} }
vTaskDelayUntil(&xLastWakeTime, xPeriod); vTaskDelayUntil(&xLastWakeTime, xPeriod);
} }

View File

@ -5,10 +5,8 @@
#include <framework/tasks/PeriodicTaskIF.h> #include <framework/tasks/PeriodicTaskIF.h>
#include <framework/tasks/Typedef.h> #include <framework/tasks/Typedef.h>
extern "C" {
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
}
#include <vector> #include <vector>
@ -22,7 +20,8 @@ class ExecutableObjectIF;
class PeriodicTask: public PeriodicTaskIF { class PeriodicTask: public PeriodicTaskIF {
public: public:
/** /**
* @brief Standard constructor of the class. * Keep in Mind that you need to call before this vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h".
* @details * @details
* The class is initialized without allocated objects. * The class is initialized without allocated objects.
* These need to be added with #addComponent. * These need to be added with #addComponent.
@ -38,8 +37,9 @@ public:
* The function pointer to the deadline missed function that shall * The function pointer to the deadline missed function that shall
* be assigned. * be assigned.
*/ */
PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, PeriodicTask(const char *name, TaskPriority setPriority,
TaskPeriod setPeriod,void (*setDeadlineMissedFunc)()); TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
/** /**
* @brief Currently, the executed object's lifetime is not coupled with * @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty. * the task object's lifetime, so the destructor is empty.
@ -58,7 +58,9 @@ public:
* Adds an object to the list of objects to be executed. * Adds an object to the list of objects to be executed.
* The objects are executed in the order added. * The objects are executed in the order added.
* @param object Id of the object to add. * @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added. * @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/ */
ReturnValue_t addComponent(object_id_t object); ReturnValue_t addComponent(object_id_t object);
@ -69,40 +71,47 @@ protected:
bool started; bool started;
TaskHandle_t handle; TaskHandle_t handle;
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects. //! Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
/** /**
* @brief This attribute holds a list of objects to be executed. * @brief This attribute holds a list of objects to be executed.
*/ */
ObjectList objectList; ObjectList objectList;
/** /**
* @brief The period of the task. * @brief The period of the task.
* @details The period determines the frequency of the task's execution. It is expressed in clock ticks. * @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/ */
TaskPeriod period; TaskPeriod period;
/** /**
* @brief The pointer to the deadline-missed function. * @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed. * @details
* So, each may react individually on a timing failure. The pointer may be NULL, * This pointer stores the function that is executed if the task's deadline
* then nothing happens on missing the deadline. The deadline is equal to the next execution * is missed so each may react individually on a timing failure.
* of the periodic task. * The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/ */
void (*deadlineMissedFunc)(void); void (*deadlineMissedFunc)(void);
/** /**
* @brief This is the function executed in the new task's context. * @brief This is the function executed in the new task's context.
* @details It converts the argument back to the thread object type and copies the class instance * @details
* to the task context. The taskFunctionality method is called afterwards. * It converts the argument back to the thread object type and copies the
* class instance to the task context. The taskFunctionality method is
* called afterwards.
* @param A pointer to the task object itself is passed as argument. * @param A pointer to the task object itself is passed as argument.
*/ */
static void taskEntryPoint(void* argument); static void taskEntryPoint(void* argument);
/** /**
* @brief The function containing the actual functionality of the task. * @brief The function containing the actual functionality of the task.
* @details The method sets and starts * @details
* the task's period, then enters a loop that is repeated as long as the isRunning * The method sets and starts the task's period, then enters a loop that is
* attribute is true. Within the loop, all performOperation methods of the added * repeated as long as the isRunning attribute is true. Within the loop,
* objects are called. Afterwards the checkAndRestartPeriod system call blocks the task * all performOperation methods of the added objects are called.
* until the next period. * Afterwards the checkAndRestartPeriod system call blocks the task until
* On missing the deadline, the deadlineMissedFunction is executed. * the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
*/ */
void taskFunctionality(void); void taskFunctionality(void);
}; };

View File

@ -65,6 +65,21 @@
// No type specification necessary here. // No type specification necessary here.
class AutoSerializeAdapter { class AutoSerializeAdapter {
public: public:
/**
* Serialize object into buffer.
* @tparam T Type of object.
* @param object Object to serialize
* @param buffer
* Serialize into this buffer, pointer to pointer has to be passed,
* *buffer will be incremented automatically.
* @param size [out]
* Update passed size value, will be incremented by serialized size
* @param max_size
* Maximum size for range checking
* @param bigEndian
* Set to true if host-to-network conversion or vice-versa is needed
* @return
*/
template<typename T> template<typename T>
static ReturnValue_t serialize(const T* object, uint8_t** buffer, static ReturnValue_t serialize(const T* object, uint8_t** buffer,
size_t* size, const size_t max_size, bool bigEndian) { size_t* size, const size_t max_size, bool bigEndian) {

View File

@ -37,8 +37,10 @@ public:
/** /**
* @brief Function called during setup assignment of object to task * @brief Function called during setup assignment of object to task
* @details Has to be called from the function that assigns the object to a task and * @details
* enables the object implementation to overwrite this function and get a reference to the executing task * Has to be called from the function that assigns the object to a task and
* enables the object implementation to overwrite this function and get
* a reference to the executing task
* @param task_ Pointer to the taskIF of this task * @param task_ Pointer to the taskIF of this task
*/ */
virtual void setTaskIF(PeriodicTaskIF* task_) { virtual void setTaskIF(PeriodicTaskIF* task_) {

View File

@ -412,5 +412,6 @@ void CommandingServiceBase::checkTimeout() {
} }
} }
void CommandingServiceBase::setTaskIF(PeriodicTaskIF* task_) {
executingTask = task_;
}

View File

@ -97,9 +97,7 @@ public:
* Used to setup the reference of the task, that executes this component * Used to setup the reference of the task, that executes this component
* @param task_ Pointer to the taskIF of this task * @param task_ Pointer to the taskIF of this task
*/ */
virtual void setTaskIF(PeriodicTaskIF* task_){ virtual void setTaskIF(PeriodicTaskIF* task_);
executingTask = task_;
};
protected: protected:
/** /**