Merge remote-tracking branch 'upstream/master' into mueller_MutexImprovements

This commit is contained in:
Robin Müller 2020-08-07 22:07:37 +02:00
commit 9d90348175
36 changed files with 1201 additions and 732 deletions

View File

@ -1,9 +1,9 @@
#include <framework/action/ActionHelper.h>
#include <framework/action/HasActionsIF.h>
#include <framework/objectmanager/ObjectManagerIF.h>
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) :
owner(setOwner), queueToUse(useThisQueue), ipcStore(
NULL) {
owner(setOwner), queueToUse(useThisQueue), ipcStore(nullptr) {
}
ActionHelper::~ActionHelper() {
@ -16,16 +16,18 @@ ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
ActionMessage::getStoreId(command));
return HasReturnvaluesIF::RETURN_OK;
} else {
return CommandMessage::UNKNOW_COMMAND;
return CommandMessage::UNKNOWN_COMMAND;
}
}
ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == NULL) {
if (ipcStore == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
setQueueToUse(queueToUse_);
if(queueToUse_ != nullptr) {
setQueueToUse(queueToUse_);
}
return HasReturnvaluesIF::RETURN_OK;
}
@ -67,7 +69,8 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t act
}
}
ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data, bool hideSender) {
ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
ActionId_t replyId, SerializeIF* data, bool hideSender) {
CommandMessage reply;
store_address_t storeAddress;
uint8_t *dataPtr;

View File

@ -35,10 +35,10 @@ public:
ReturnValue_t handleActionMessage(CommandMessage* command);
/**
* Helper initialize function. Must be called before use of any other helper function
* @param queueToUse_ Pointer to the messageQueue to be used
* @param queueToUse_ Pointer to the messageQueue to be used, optional if queue was set in constructor
* @return Returns RETURN_OK if successful
*/
ReturnValue_t initialize(MessageQueueIF* queueToUse_);
ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr);
/**
* Function to be called from the owner to send a step message. Success or failure will be determined by the result value.
*

View File

@ -1,5 +1,5 @@
#ifndef HASACTIONSIF_H_
#define HASACTIONSIF_H_
#ifndef FRAMEWORK_ACTION_HASACTIONSIF_H_
#define FRAMEWORK_ACTION_HASACTIONSIF_H_
#include <framework/action/ActionHelper.h>
#include <framework/action/ActionMessage.h>
@ -7,27 +7,35 @@
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/ipc/MessageQueueIF.h>
/**
* \brief Interface for component which uses actions
* @brief
* Interface for component which uses actions
*
* This interface is used to execute actions in the component. Actions, in the sense of this interface, are activities with a well-defined beginning and
* end in time. They may adjust sub-states of components, but are not supposed to change
* the main mode of operation, which is handled with the HasModesIF described below.
* @details
* This interface is used to execute actions in the component. Actions, in the
* sense of this interface, are activities with a well-defined beginning and
* end in time. They may adjust sub-states of components, but are not supposed
* to change the main mode of operation, which is handled with the HasModesIF
* described below.
*
* The HasActionsIF allows components to define such actions and make them available
* for other components to use. Implementing the interface is straightforward: Theres a
* single executeAction call, which provides an identifier for the action to execute, as well
* as arbitrary parameters for input. Aside from direct, software-based
* actions, it is used in device handler components as an interface to forward commands to
* devices.
* Implementing components of the interface are supposed to check identifier (ID) and
* parameters and immediately start execution of the action. It is, however, not required to
* immediately finish execution. Instead, this may be deferred to a later point in time, at
* which the component needs to inform the caller about finished or failed execution.
* The HasActionsIF allows components to define such actions and make them
* available for other components to use. Implementing the interface is
* straightforward: Theres a single executeAction call, which provides an
* identifier for the action to execute, as well as arbitrary parameters for
* input.
* Aside from direct, software-based actions, it is used in device handler
* components as an interface to forward commands to devices.
* Implementing components of the interface are supposed to check identifier
* (ID) and parameters and immediately start execution of the action.
* It is, however, not required to immediately finish execution.
* Instead, this may be deferred to a later point in time, at which the
* component needs to inform the caller about finished or failed execution.
*
* @ingroup interfaces
*/
class HasActionsIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_ACTIONS_IF;
static const ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1);//!<
static const ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1);
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4);
@ -39,12 +47,14 @@ public:
virtual MessageQueueId_t getCommandQueue() const = 0;
/**
* Execute or initialize the execution of a certain function.
* Returning #EXECUTION_FINISHED or a failure code, nothing else needs to be done.
* When needing more steps, return RETURN_OK and issue steps and completion manually. One "step failed" or completion report must
* be issued!
* Returning #EXECUTION_FINISHED or a failure code, nothing else needs to
* be done. When needing more steps, return RETURN_OK and issue steps and
* completion manually.
* One "step failed" or completion report must be issued!
*/
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size) = 0;
virtual ReturnValue_t executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0;
};
#endif /* HASACTIONSIF_H_ */
#endif /* FRAMEWORK_ACTION_HASACTIONSIF_H_ */

View File

@ -1,5 +1,5 @@
#ifndef HYBRIDITERATOR_H_
#define HYBRIDITERATOR_H_
#ifndef FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_
#define FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_
#include <framework/container/ArrayList.h>
#include <framework/container/SinglyLinkedList.h>
@ -8,34 +8,32 @@ template<typename T, typename count_t = uint8_t>
class HybridIterator: public LinkedElement<T>::Iterator,
public ArrayList<T, count_t>::Iterator {
public:
HybridIterator() :
value(NULL), linked(NULL), end(NULL) {
}
HybridIterator() {}
HybridIterator(typename LinkedElement<T>::Iterator *iter) :
LinkedElement<T>::Iterator(*iter), value(
iter->value), linked(true), end(NULL) {
LinkedElement<T>::Iterator(*iter), value(iter->value),
linked(true) {
}
HybridIterator(LinkedElement<T> *start) :
LinkedElement<T>::Iterator(start), value(
start->value), linked(true), end(NULL) {
LinkedElement<T>::Iterator(start), value(start->value),
linked(true) {
}
HybridIterator(typename ArrayList<T, count_t>::Iterator start,
typename ArrayList<T, count_t>::Iterator end) :
ArrayList<T, count_t>::Iterator(start), value(start.value), linked(
false), end(end.value) {
ArrayList<T, count_t>::Iterator(start), value(start.value),
linked(false), end(end.value) {
if (value == this->end) {
value = NULL;
}
}
HybridIterator(T *firstElement, T *lastElement) :
ArrayList<T, count_t>::Iterator(firstElement), value(firstElement), linked(
false), end(++lastElement) {
ArrayList<T, count_t>::Iterator(firstElement), value(firstElement),
linked(false), end(++lastElement) {
if (value == end) {
value = NULL;
}
@ -44,17 +42,17 @@ public:
HybridIterator& operator++() {
if (linked) {
LinkedElement<T>::Iterator::operator++();
if (LinkedElement<T>::Iterator::value != NULL) {
if (LinkedElement<T>::Iterator::value != nullptr) {
value = LinkedElement<T>::Iterator::value->value;
} else {
value = NULL;
value = nullptr;
}
} else {
ArrayList<T, count_t>::Iterator::operator++();
value = ArrayList<T, count_t>::Iterator::value;
if (value == end) {
value = NULL;
value = nullptr;
}
}
return *this;
@ -66,11 +64,11 @@ public:
return tmp;
}
bool operator==(HybridIterator other) {
return value == other->value;
bool operator==(const HybridIterator& other) const {
return value == other.value;
}
bool operator!=(HybridIterator other) {
bool operator!=(const HybridIterator& other) const {
return !(*this == other);
}
@ -82,11 +80,11 @@ public:
return value;
}
T* value;
T* value = nullptr;
private:
bool linked;
T *end;
bool linked = false;
T *end = nullptr;
};
#endif /* HYBRIDITERATOR_H_ */
#endif /* FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ */

View File

@ -35,7 +35,7 @@ ReturnValue_t ChildHandlerBase::initialize() {
parent->registerChild(getObjectId());
}
healthHelper.setParentQeueue(parentQueue);
healthHelper.setParentQueue(parentQueue);
modeHelper.setParentQueue(parentQueue);

View File

@ -236,7 +236,7 @@ void DeviceHandlerBase::readCommandQueue() {
return;
}
replyReturnvalueToCommand(CommandMessage::UNKNOW_COMMAND);
replyReturnvalueToCommand(CommandMessage::UNKNOWN_COMMAND);
}
@ -1085,7 +1085,7 @@ ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage(
void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) {
modeHelper.setParentQueue(parentQueueId);
healthHelper.setParentQeueue(parentQueueId);
healthHelper.setParentQueue(parentQueueId);
}
bool DeviceHandlerBase::isAwaitingReply() {
@ -1149,7 +1149,7 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data,
}
ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size) {
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) {
ReturnValue_t result = acceptExternalDeviceCommands();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;

View File

@ -484,7 +484,7 @@ public:
/** @brief Implementation required for HasActionIF */
ReturnValue_t executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data,
uint32_t size) override;
size_t size) override;
Mode_t getTransitionSourceMode() const;
Submode_t getTransitionSourceSubMode() const;

View File

@ -38,7 +38,7 @@ MessageQueueId_t HealthDevice::getCommandQueue() const {
}
void HealthDevice::setParentQueue(MessageQueueId_t parentQueue) {
healthHelper.setParentQeueue(parentQueue);
healthHelper.setParentQueue(parentQueue);
}
bool HealthDevice::hasHealthChanged() {

View File

@ -1,5 +1,5 @@
# This file needs FRAMEWORK_PATH and API set correctly
# Valid API settings: rtems, linux, freeRTOS
# This file needs FRAMEWORK_PATH and OS_FSFW set correctly by another Makefile.
# Valid API settings: rtems, linux, freeRTOS, host
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/action/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/container/*.cpp)
@ -12,7 +12,6 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/eventmatching/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/fdir/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/framework.mk/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/globalfunctions/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/globalfunctions/matching/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/globalfunctions/math/*.cpp)
@ -26,14 +25,16 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/objectmanager/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/*.cpp)
# select the OS
ifeq ($(OS),rtems)
ifeq ($(OS_FSFW),rtems)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/rtems/*.cpp)
else ifeq ($(OS),linux)
else ifeq ($(OS_FSFW),linux)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/linux/*.cpp)
else ifeq ($(OS),freeRTOS)
else ifeq ($(OS_FSFW),freeRTOS)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/FreeRTOS/*.cpp)
else ifeq ($(OS_FSFW),host)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/host/*.cpp)
else
$(error invalid OS specified, valid OS are rtems, linux, freeRTOS)
$(error invalid OS specified, valid OS are rtems, linux, freeRTOS, host)
endif
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/parameters/*.cpp)

View File

@ -29,11 +29,11 @@ HasHealthIF::HealthState HealthHelper::getHealth() {
}
ReturnValue_t HealthHelper::initialize(MessageQueueId_t parentQueue) {
setParentQeueue(parentQueue);
setParentQueue(parentQueue);
return initialize();
}
void HealthHelper::setParentQeueue(MessageQueueId_t parentQueue) {
void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) {
this->parentQueue = parentQueue;
}

View File

@ -78,7 +78,7 @@ public:
/**
* @param parentQueue the Queue id of the parent object. Set to 0 if no parent present
*/
void setParentQeueue(MessageQueueId_t parentQueue);
void setParentQueue(MessageQueueId_t parentQueue);
/**
*

View File

@ -111,7 +111,7 @@ size_t CommandMessage::getMinimumMessageSize() const {
void CommandMessage::setToUnknownCommand() {
Command_t initialCommand = getCommand();
clearCommandMessage();
setReplyRejected(UNKNOW_COMMAND, initialCommand);
setReplyRejected(UNKNOWN_COMMAND, initialCommand);
}
void CommandMessage::setReplyRejected(ReturnValue_t reason,
@ -120,3 +120,12 @@ void CommandMessage::setReplyRejected(ReturnValue_t reason,
setParameter(reason);
setParameter2(initialCommand);
}
ReturnValue_t CommandMessage::getReplyRejectedReason(
Command_t *initialCommand) const {
ReturnValue_t reason = getParameter();
if(initialCommand != nullptr) {
*initialCommand = getParameter2();
}
return reason;
}

View File

@ -20,7 +20,7 @@ typedef ReturnValue_t Command_t;
class CommandMessage : public MessageQueueMessage {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE;
static const ReturnValue_t UNKNOW_COMMAND = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01);
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::COMMAND;
@ -124,6 +124,9 @@ public:
*/
void setToUnknownCommand();
void setReplyRejected(ReturnValue_t reason, Command_t initialCommand = CMD_NONE);
ReturnValue_t getReplyRejectedReason(
Command_t *initialCommand = nullptr) const;
size_t getMinimumMessageSize() const;
};

View File

@ -21,7 +21,8 @@ public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF;
static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 );
static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 );
static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 );
static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); //!< Can be used if the initialization of a SystemObject failed.
static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 );
protected:

View File

@ -1,6 +1,7 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include "FixedTimeslotTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h>
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
@ -18,16 +19,19 @@ FixedTimeslotTask::~FixedTimeslotTask() {
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));
// Task should not start until explicitly requested
// in FreeRTOS, tasks start as soon as they are created if the scheduler 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()
// if it is not set and we get here, the scheduler was started 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
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* 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(). If it is not set and we get here, the scheduler was started
* 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);
}
@ -58,11 +62,6 @@ ReturnValue_t FixedTimeslotTask::startTask() {
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) {
if(slotTimeMs == 0) {
// FreeRTOS throws a sanity error for zero values, so we set
// the time to one millisecond.
slotTimeMs = 1;
}
pst.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK;
}
@ -81,8 +80,9 @@ ReturnValue_t FixedTimeslotTask::checkSequence() const {
}
void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
auto slotListIter = pst.current;
// A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry.
FixedSlotSequence::SlotListIter slotListIter = pst.current;
//The start time for the first entry is read.
uint32_t intervalMs = slotListIter->pollingTimeMs;
@ -90,32 +90,67 @@ void FixedTimeslotTask::taskFunctionality() {
TickType_t xLastWakeTime;
/* 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.
After this assignment, xLastWakeTime is updated automatically internally within
vTaskDelayUntil(). */
count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount();
// wait for first entry's start time
vTaskDelayUntil(&xLastWakeTime, interval);
if(interval > 0) {
vTaskDelayUntil(&xLastWakeTime, interval);
}
/* Enter the loop that defines the task behavior. */
for (;;) {
//The component for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
if (pst.slotFollowsImmediately()) {
//Do nothing
} else {
// 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);
//TODO deadline missed check
}
this->pst.executeAndAdvance();
if (not pst.slotFollowsImmediately()) {
// Get the interval till execution of the next slot.
intervalMs = this->pst.getIntervalToPreviousSlotMs();
interval = pdMS_TO_TICKS(intervalMs);
checkMissedDeadline(xLastWakeTime, interval);
// Wait for the interval. This exits immediately if a deadline was
// missed while also updating the last wake time.
vTaskDelayUntil(&xLastWakeTime, interval);
}
}
}
void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand
* it. */
TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval;
// Time to wake has not overflown.
if(timeToWake > xLastWakeTime) {
/* If the current time has overflown exclusively or the current
* tick count is simply larger than the time to wake, a deadline was
* missed */
if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) {
handleMissedDeadline();
}
}
/* Time to wake has overflown. A deadline was missed if the current time
* is larger than the time to wake */
else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) {
handleMissedDeadline();
}
}
void FixedTimeslotTask::handleMissedDeadline() {
#ifdef DEBUG
sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms));
return HasReturnvaluesIF::RETURN_OK;

View File

@ -1,26 +1,27 @@
#ifndef POLLINGTASK_H_
#define POLLINGTASK_H_
#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#include <framework/devicehandlers/FixedSlotSequence.h>
#include <framework/tasks/FixedTimeslotTaskIF.h>
#include <framework/tasks/Typedef.h>
extern "C" {
#include "FreeRTOS.h"
#include "task.h"
}
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
class FixedTimeslotTask: public FixedTimeslotTaskIF {
public:
/**
* @brief The standard constructor of the class.
*
* @details This is the general constructor of the class. In addition to the TaskBase parameters,
* the following variables are passed:
*
* @param (*setDeadlineMissedFunc)() The function pointer to the deadline missed function that shall be assigned.
*
* @param getPst The object id of the completely initialized polling sequence.
* Keep in mind that you need to call before vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h".
* @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN
* @param setPriority Number of priorities specified by
* configMAX_PRIORITIES. High taskPriority_ number means high priority.
* @param setStack Stack size in words (not bytes!).
* Lower limit specified by configMINIMAL_STACK_SIZE
* @param overallPeriod Period in seconds.
* @param setDeadlineMissedFunc Callback if a deadline was missed.
* @return Pointer to the newly created task.
*/
FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod,
@ -28,16 +29,18 @@ public:
/**
* @brief The destructor of the class.
*
* @details The destructor frees all heap memory that was allocated on thread initialization for the PST and
* the device handlers. This is done by calling the PST's destructor.
* @details
* The destructor frees all heap memory that was allocated on thread
* initialization for the PST and the device handlers. This is done by
* calling the PST's destructor.
*/
virtual ~FixedTimeslotTask(void);
ReturnValue_t startTask(void);
/**
* 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();
/**
@ -46,13 +49,14 @@ public:
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep);
int8_t executionStep) override;
uint32_t getPeriodMs() const;
uint32_t getPeriodMs() const override;
ReturnValue_t checkSequence() const;
ReturnValue_t checkSequence() const override;
ReturnValue_t sleepFor(uint32_t ms) override;
ReturnValue_t sleepFor(uint32_t ms);
protected:
bool started;
TaskHandle_t handle;
@ -60,32 +64,35 @@ protected:
FixedSlotSequence pst;
/**
* @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.
* Currently, only one function for missing any deadline is allowed.
* If not used, it shall be declared NULL.
* @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. Currently, only one function for missing
* any deadline is allowed. If not used, it shall be declared NULL.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the entry point in a new polling thread.
*
* @details This method, that is the generalOSAL::checkAndRestartPeriod( this->periodId, interval ); entry point in the new thread, is here set to generate
* and link the Polling Sequence Table to the thread object and start taskFunctionality()
* on success. If operation of the task is ended for some reason,
* the destructor is called to free allocated memory.
* @brief This is the entry point for a new task.
* @details
* This method starts the task by calling taskFunctionality(), as soon as
* all requirements (task scheduler has started and startTask()
* has been called) are met.
*/
static void taskEntryPoint(void* argument);
/**
* @brief This function holds the main functionality of the thread.
*
*
* @details Holding the main functionality of the task, this method is most important.
* It links the functionalities provided by FixedSlotSequence with the OS's System Calls
* to keep the timing of the periods.
* @details
* Core function holding the main functionality of the task
* It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods.
*/
void taskFunctionality(void);
void checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval);
void handleMissedDeadline();
};
#endif /* POLLINGTASK_H_ */
#endif /* FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ */

View File

@ -1,17 +1,19 @@
#include "PeriodicTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/tasks/ExecutableObjectIF.h>
#include "PeriodicTask.h"
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(
setDeadlineMissedFunc) {
BaseType_t status = xTaskCreate(taskEntryPoint, name, setStack, this, setPriority, &handle);
setDeadlineMissedFunc)
{
BaseType_t status = xTaskCreate(taskEntryPoint, name,
setStack, this, setPriority, &handle);
if(status != pdPASS){
sif::debug << "PeriodicTask Insufficient heap memory remaining. Status: "
<< status << std::endl;
sif::debug << "PeriodicTask Insufficient heap memory remaining. "
"Status: " << status << std::endl;
}
}
@ -21,16 +23,19 @@ PeriodicTask::~PeriodicTask(void) {
}
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));
// Task should not start until explicitly requested
// in FreeRTOS, tasks start as soon as they are created if the scheduler 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()
// if it is not set and we get here, the scheduler was started 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
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* 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(). If it is not set and we get here, the scheduler was started
* 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);
}
@ -59,31 +64,72 @@ void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
/* 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.
After this assignment, xLastWakeTime is updated automatically internally within
vTaskDelayUntil(). */
count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */
for (;;) {
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
for (auto const& object: objectList) {
object->performOperation();
}
//TODO deadline missed check
checkMissedDeadline(xLastWakeTime, xPeriod);
vTaskDelayUntil(&xLastWakeTime, xPeriod);
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ReturnValue_t PeriodicTask::addComponent(object_id_t object, bool setTaskIF) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == NULL) {
if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implements ExecutableObjectIF!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
if(setTaskIF) {
newObject->setTaskIF(this);
}
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000;
}
void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand
* it. */
TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval;
// Time to wake has not overflown.
if(timeToWake > xLastWakeTime) {
/* If the current time has overflown exclusively or the current
* tick count is simply larger than the time to wake, a deadline was
* missed */
if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) {
handleMissedDeadline();
}
}
/* Time to wake has overflown. A deadline was missed if the current time
* is larger than the time to wake */
else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) {
handleMissedDeadline();
}
}
void PeriodicTask::handleMissedDeadline() {
#ifdef DEBUG
sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}

View File

@ -1,48 +1,49 @@
#ifndef MULTIOBJECTTASK_H_
#define MULTIOBJECTTASK_H_
#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/tasks/PeriodicTaskIF.h>
#include <framework/tasks/Typedef.h>
#include <FreeRTOS.h>
#include "task.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <vector>
class ExecutableObjectIF;
/**
* @brief This class represents a specialized task for periodic activities of multiple objects.
*
* @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute
* multiple objects that implement the ExecutableObjectIF interface. The objects must be
* added prior to starting the task.
*
* @brief This class represents a specialized task for
* periodic activities of multiple objects.
* @ingroup task_handling
*/
class PeriodicTask: public PeriodicTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details The class is initialized without allocated objects. These need to be added
* with #addObject.
* In the underlying TaskBase class, a new operating system task is created.
* In addition to the TaskBase parameters, the period, the pointer to the
* aforementioned initialization function and an optional "deadline-missed"
* function pointer is passed.
* @param priority Sets the priority of a task. Values range from a low 0 to a high 99.
* @param stack_size The stack size reserved by the operating system for the task.
* @param setPeriod The length of the period with which the task's functionality will be
* executed. It is expressed in clock ticks.
* @param setDeadlineMissedFunc The function pointer to the deadline missed function
* that shall be assigned.
* Keep in Mind that you need to call before this vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h".
* TODO: why does this need to be called before vTaskStartScheduler?
* @details
* The class is initialized without allocated objects.
* These need to be added with #addComponent.
* @param priority
* Sets the priority of a task. Values depend on freeRTOS configuration,
* high number means high priority.
* @param stack_size
* The stack size reserved by the operating system for the task.
* @param setPeriod
* The length of the period with which the task's
* functionality will be executed. It is expressed in clock ticks.
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall
* be assigned.
*/
PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with the task object's
* lifetime, so the destructor is empty.
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~PeriodicTask(void);
@ -53,58 +54,72 @@ public:
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @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,
bool setTaskIF = true) override;
uint32_t getPeriodMs() const;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms);
ReturnValue_t sleepFor(uint32_t ms) override;
protected:
bool started;
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.
*/
ObjectList objectList;
/**
* @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;
/**
* @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed.
* So, each may react individually on a timing failure. The pointer may be NULL,
* then nothing happens on missing the deadline. The deadline is equal to the next execution
* of the periodic task.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed so each may react individually on a timing failure.
* 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);
/**
* @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
* to the task context. The taskFunctionality method is called afterwards.
* @details
* 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.
*/
static void taskEntryPoint(void* argument);
/**
* @brief The function containing the actual functionality of the task.
* @details The method sets and starts
* the task's period, then enters a loop that is repeated as long as the isRunning
* attribute is true. Within the loop, all performOperation methods of the added
* objects are called. Afterwards the checkAndRestartPeriod system call blocks the task
* until the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
* @details
* The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called.
* Afterwards the checkAndRestartPeriod system call blocks the task until
* the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
void checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval);
void handleMissedDeadline();
};
#endif /* MULTIOBJECTTASK_H_ */
#endif /* PERIODICTASK_H_ */

View File

@ -21,13 +21,18 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) {
return NULL;
}
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object,
bool addTaskIF) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == NULL) {
if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
if(setTaskIF) {
newObject->setTaskIF(this);
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -39,11 +39,12 @@ public:
* @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object);
ReturnValue_t addComponent(object_id_t object,
bool addTaskIF = true) override;
uint32_t getPeriodMs() const;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms);
ReturnValue_t sleepFor(uint32_t ms) override;
private:
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.

View File

@ -1,18 +1,13 @@
/**
* @file SerialArrayListAdapter.h
* @brief This file defines the SerialArrayListAdapter class.
* @date 22.07.2014
* @author baetz
*/
#ifndef SERIALARRAYLISTADAPTER_H_
#define SERIALARRAYLISTADAPTER_H_
#ifndef FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_
#define FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_
#include <framework/container/ArrayList.h>
#include <framework/serialize/SerializeIF.h>
#include <utility>
/**
* \ingroup serialize
* @ingroup serialize
* @author baetz
*/
template<typename T, typename count_t = uint8_t>
class SerialArrayListAdapter : public SerializeIF {
@ -25,14 +20,15 @@ public:
return serialize(adaptee, buffer, size, maxSize, streamEndianness);
}
static ReturnValue_t serialize(const ArrayList<T, count_t>* list, uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) {
static ReturnValue_t serialize(const ArrayList<T, count_t>* list,
uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::serialize(&list->size,
buffer, size, maxSize, streamEndianness);
count_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) {
result = SerializeAdapter::serialize(&list->entries[i], buffer, size,
maxSize, streamEndianness);
result = SerializeAdapter::serialize(&list->entries[i], buffer,
size, maxSize, streamEndianness);
++i;
}
return result;
@ -58,11 +54,15 @@ public:
return deSerialize(adaptee, buffer, size, streamEndianness);
}
static ReturnValue_t deSerialize(ArrayList<T, count_t>* list, const uint8_t** buffer, size_t* size,
static ReturnValue_t deSerialize(ArrayList<T, count_t>* list,
const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
count_t tempSize = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&tempSize,
buffer, size, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if (tempSize > list->maxSize()) {
return SerializeIF::TOO_MANY_ELEMENTS;
}
@ -82,4 +82,4 @@ private:
#endif /* SERIALARRAYLISTADAPTER_H_ */
#endif /* FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_ */

View File

@ -1,11 +1,58 @@
#include <framework/timemanager/Clock.h>
#include <framework/serviceinterface/ServiceInterfaceBuffer.h>
#include <cstring>
#include <inttypes.h>
// to be implemented by bsp
extern "C" void printChar(const char*);
extern "C" void printChar(const char*, bool errStream);
#ifndef UT699
ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage,
bool addCrToPreamble, bool buffered , bool errStream, uint16_t port):
isActive(true), logMessage(setMessage),
addCrToPreamble(addCrToPreamble), buffered(buffered),
errStream(errStream) {
if(buffered) {
// Set pointers if the stream is buffered.
setp( buf, buf + BUF_SIZE );
}
preamble.reserve(MAX_PREAMBLE_SIZE);
preamble.resize(MAX_PREAMBLE_SIZE);
}
void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) {
char array[BUF_SIZE];
uint32_t length = end - begin;
if (length > sizeof(array)) {
length = sizeof(array);
}
memcpy(array, begin, length);
for(; begin != end; begin++){
if(errStream) {
printChar(begin, true);
}
else {
printChar(begin, false);
}
}
}
#endif
int ServiceInterfaceBuffer::overflow(int c) {
if(not buffered and this->isActive) {
if (c != Traits::eof()) {
if(errStream) {
printChar(reinterpret_cast<const char*>(&c), true);
}
else {
printChar(reinterpret_cast<const char*>(&c), false);
}
}
return 0;
}
// Handle output
putChars(pbase(), pptr());
if (c != Traits::eof()) {
@ -20,52 +67,70 @@ int ServiceInterfaceBuffer::overflow(int c) {
}
int ServiceInterfaceBuffer::sync(void) {
if (this->isActive) {
Clock::TimeOfDay_t loggerTime;
Clock::getDateAndTime(&loggerTime);
char preamble[96] = { 0 };
sprintf(preamble, "%s: | %lu:%02lu:%02lu.%03lu | ",
this->log_message.c_str(), (unsigned long) loggerTime.hour,
(unsigned long) loggerTime.minute,
(unsigned long) loggerTime.second,
(unsigned long) loggerTime.usecond /1000);
// Write log_message and time
this->putChars(preamble, preamble + sizeof(preamble));
// Handle output
this->putChars(pbase(), pptr());
if(not this->isActive and not buffered) {
if(not buffered) {
setp(buf, buf + BUF_SIZE - 1);
}
return 0;
}
if(not buffered) {
return 0;
}
size_t preambleSize = 0;
std::string* preamble = getPreamble(&preambleSize);
// Write logMessage and time
this->putChars(preamble->data(), preamble->data() + preambleSize);
// Handle output
this->putChars(pbase(), pptr());
// This tells that buffer is empty again
setp(buf, buf + BUF_SIZE - 1);
return 0;
}
#ifndef UT699
ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) {
this->log_message = set_message;
this->isActive = true;
setp( buf, buf + BUF_SIZE );
bool ServiceInterfaceBuffer::isBuffered() const {
return buffered;
}
void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) {
char array[BUF_SIZE];
uint32_t length = end - begin;
if (length > sizeof(array)) {
length = sizeof(array);
std::string* ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) {
Clock::TimeOfDay_t loggerTime;
Clock::getDateAndTime(&loggerTime);
size_t currentSize = 0;
char* parsePosition = &preamble[0];
if(addCrToPreamble) {
preamble[0] = '\r';
currentSize += 1;
parsePosition += 1;
}
memcpy(array, begin, length);
for( ; begin != end; begin++){
printChar(begin);
int32_t charCount = sprintf(parsePosition,
"%s: | %02" SCNu32 ":%02" SCNu32