Merge remote-tracking branch 'upstram/master' into mueller/feature/CSBupdate

This commit is contained in:
Robin Müller 2020-08-01 16:46:27 +02:00
commit 4213e2e081
20 changed files with 614 additions and 280 deletions

View File

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

View File

@ -120,3 +120,12 @@ void CommandMessage::setReplyRejected(ReturnValue_t reason,
setParameter(reason); setParameter(reason);
setParameter2(initialCommand); setParameter2(initialCommand);
} }
ReturnValue_t CommandMessage::getReplyRejectedReason(
Command_t *initialCommand) const {
ReturnValue_t reason = getParameter();
if(initialCommand != nullptr) {
*initialCommand = getParameter2();
}
return reason;
}

View File

@ -124,6 +124,9 @@ public:
*/ */
void setToUnknownCommand(); void setToUnknownCommand();
void setReplyRejected(ReturnValue_t reason, Command_t initialCommand = CMD_NONE); void setReplyRejected(ReturnValue_t reason, Command_t initialCommand = CMD_NONE);
ReturnValue_t getReplyRejectedReason(
Command_t *initialCommand = nullptr) const;
size_t getMinimumMessageSize() 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 uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF;
static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 );
static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); 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 ); static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 );
protected: protected:

View File

@ -125,19 +125,18 @@ void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime,
* it. */ * it. */
TickType_t currentTickCount = xTaskGetTickCount(); TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval; TickType_t timeToWake = xLastWakeTime + interval;
// Tick count has overflown // Time to wake has not overflown.
if(currentTickCount < xLastWakeTime) { if(timeToWake > xLastWakeTime) {
// Time to wake has overflown as well. If the tick count /* If the current time has overflown exclusively or the current
// is larger than the time to wake, a deadline was missed. * tick count is simply larger than the time to wake, a deadline was
if(timeToWake < xLastWakeTime and * missed */
currentTickCount > timeToWake) { if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) {
handleMissedDeadline(); handleMissedDeadline();
} }
} }
// No tick count overflow. If the timeToWake has not overflown /* Time to wake has overflown. A deadline was missed if the current time
// and the current tick count is larger than the time to wake, * is larger than the time to wake */
// a deadline was missed. else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) {
else if(timeToWake > xLastWakeTime and currentTickCount > timeToWake) {
handleMissedDeadline(); handleMissedDeadline();
} }
} }

View File

@ -1,17 +1,19 @@
#include "PeriodicTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/tasks/ExecutableObjectIF.h> #include <framework/tasks/ExecutableObjectIF.h>
#include "PeriodicTask.h"
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) : void (*setDeadlineMissedFunc)()) :
started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(
setDeadlineMissedFunc) { setDeadlineMissedFunc)
{
BaseType_t status = xTaskCreate(taskEntryPoint, name, setStack, this, setPriority, &handle); BaseType_t status = xTaskCreate(taskEntryPoint, name,
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;
} }
} }
@ -21,16 +23,19 @@ 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 (!originalTask->started) { if (not originalTask->started) {
vTaskSuspend(NULL); vTaskSuspend(NULL);
} }
@ -59,31 +64,72 @@ 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 (;;) {
for (ObjectList::iterator it = objectList.begin(); for (auto const& object: objectList) {
it != objectList.end(); ++it) { object->performOperation();
(*it)->performOperation();
} }
//TODO deadline missed check
checkMissedDeadline(xLastWakeTime, xPeriod);
vTaskDelayUntil(&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>( ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object); object);
if (newObject == NULL) { if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implements ExecutableObjectIF!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(newObject);
if(setTaskIF) {
newObject->setTaskIF(this);
}
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
uint32_t PeriodicTask::getPeriodMs() const { uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000; 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_ #ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_
#define MULTIOBJECTTASK_H_ #define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_
#include <framework/objectmanager/ObjectManagerIF.h> #include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/tasks/PeriodicTaskIF.h> #include <framework/tasks/PeriodicTaskIF.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>
#include <vector> #include <vector>
class ExecutableObjectIF; class ExecutableObjectIF;
/** /**
* @brief This class represents a specialized task for periodic activities of multiple objects. * @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.
*
* @ingroup task_handling * @ingroup task_handling
*/ */
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()!
* @details The class is initialized without allocated objects. These need to be added * A lot of task parameters are set in "FreeRTOSConfig.h".
* with #addObject. * TODO: why does this need to be called before vTaskStartScheduler?
* In the underlying TaskBase class, a new operating system task is created. * @details
* In addition to the TaskBase parameters, the period, the pointer to the * The class is initialized without allocated objects.
* aforementioned initialization function and an optional "deadline-missed" * These need to be added with #addComponent.
* function pointer is passed. * @param priority
* @param priority Sets the priority of a task. Values range from a low 0 to a high 99. * Sets the priority of a task. Values depend on freeRTOS configuration,
* @param stack_size The stack size reserved by the operating system for the task. * high number means high priority.
* @param setPeriod The length of the period with which the task's functionality will be * @param stack_size
* executed. It is expressed in clock ticks. * The stack size reserved by the operating system for the task.
* @param setDeadlineMissedFunc The function pointer to the deadline missed function * @param setPeriod
* that shall be assigned. * 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, PeriodicTask(const char *name, TaskPriority setPriority,
void (*setDeadlineMissedFunc)()); TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
/** /**
* @brief Currently, the executed object's lifetime is not coupled with the task object's * @brief Currently, the executed object's lifetime is not coupled with
* lifetime, so the destructor is empty. * the task object's lifetime, so the destructor is empty.
*/ */
virtual ~PeriodicTask(void); virtual ~PeriodicTask(void);
@ -53,58 +54,72 @@ public:
* The address of the task object is passed as an argument * The address of the task object is passed as an argument
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask(void); ReturnValue_t startTask() override;
/** /**
* 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,
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: 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);
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; 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>( ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object); object);
if (newObject == NULL) { if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(newObject);
if(setTaskIF) {
newObject->setTaskIF(this);
}
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -39,11 +39,12 @@ public:
* @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 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: private:
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects. typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.

View File

@ -1,18 +1,13 @@
/** #ifndef FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_
* @file SerialArrayListAdapter.h #define FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_
* @brief This file defines the SerialArrayListAdapter class.
* @date 22.07.2014
* @author baetz
*/
#ifndef SERIALARRAYLISTADAPTER_H_
#define SERIALARRAYLISTADAPTER_H_
#include <framework/container/ArrayList.h> #include <framework/container/ArrayList.h>
#include <framework/serialize/SerializeIF.h> #include <framework/serialize/SerializeIF.h>
#include <utility> #include <utility>
/** /**
* \ingroup serialize * @ingroup serialize
* @author baetz
*/ */
template<typename T, typename count_t = uint8_t> template<typename T, typename count_t = uint8_t>
class SerialArrayListAdapter : public SerializeIF { class SerialArrayListAdapter : public SerializeIF {
@ -25,14 +20,15 @@ public:
return serialize(adaptee, buffer, size, maxSize, streamEndianness); return serialize(adaptee, buffer, size, maxSize, streamEndianness);
} }
static ReturnValue_t serialize(const ArrayList<T, count_t>* list, uint8_t** buffer, size_t* size, static ReturnValue_t serialize(const ArrayList<T, count_t>* list,
size_t maxSize, Endianness streamEndianness) { uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::serialize(&list->size, ReturnValue_t result = SerializeAdapter::serialize(&list->size,
buffer, size, maxSize, streamEndianness); buffer, size, maxSize, streamEndianness);
count_t i = 0; count_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) { while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) {
result = SerializeAdapter::serialize(&list->entries[i], buffer, size, result = SerializeAdapter::serialize(&list->entries[i], buffer,
maxSize, streamEndianness); size, maxSize, streamEndianness);
++i; ++i;
} }
return result; return result;
@ -58,11 +54,15 @@ public:
return deSerialize(adaptee, buffer, size, streamEndianness); 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) { Endianness streamEndianness) {
count_t tempSize = 0; count_t tempSize = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&tempSize, ReturnValue_t result = SerializeAdapter::deSerialize(&tempSize,
buffer, size, streamEndianness); buffer, size, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if (tempSize > list->maxSize()) { if (tempSize > list->maxSize()) {
return SerializeIF::TOO_MANY_ELEMENTS; 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/timemanager/Clock.h>
#include <framework/serviceinterface/ServiceInterfaceBuffer.h> #include <framework/serviceinterface/ServiceInterfaceBuffer.h>
#include <cstring> #include <cstring>
#include <inttypes.h>
// to be implemented by bsp // 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) { 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 // Handle output
putChars(pbase(), pptr()); putChars(pbase(), pptr());
if (c != Traits::eof()) { if (c != Traits::eof()) {
@ -20,52 +67,70 @@ int ServiceInterfaceBuffer::overflow(int c) {
} }
int ServiceInterfaceBuffer::sync(void) { int ServiceInterfaceBuffer::sync(void) {
if (this->isActive) { if(not this->isActive and not buffered) {
Clock::TimeOfDay_t loggerTime; if(not buffered) {
Clock::getDateAndTime(&loggerTime); setp(buf, buf + BUF_SIZE - 1);
char preamble[96] = { 0 }; }
sprintf(preamble, "%s: | %lu:%02lu:%02lu.%03lu | ", return 0;
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 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 // This tells that buffer is empty again
setp(buf, buf + BUF_SIZE - 1); setp(buf, buf + BUF_SIZE - 1);
return 0; return 0;
} }
#ifndef UT699 bool ServiceInterfaceBuffer::isBuffered() const {
return buffered;
ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) {
this->log_message = set_message;
this->isActive = true;
setp( buf, buf + BUF_SIZE );
} }
void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { std::string* ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) {
char array[BUF_SIZE]; Clock::TimeOfDay_t loggerTime;
uint32_t length = end - begin; Clock::getDateAndTime(&loggerTime);
if (length > sizeof(array)) { size_t currentSize = 0;
length = sizeof(array); char* parsePosition = &preamble[0];
if(addCrToPreamble) {
preamble[0] = '\r';
currentSize += 1;
parsePosition += 1;
} }
memcpy(array, begin, length); int32_t charCount = sprintf(parsePosition,
"%s: | %02" SCNu32 ":%02" SCNu32 ":%02" SCNu32 ".%03" SCNu32 " | ",
for( ; begin != end; begin++){ this->logMessage.c_str(), loggerTime.hour,
printChar(begin); loggerTime.minute,
loggerTime.second,
loggerTime.usecond /1000);
if(charCount < 0) {
printf("ServiceInterfaceBuffer: Failure parsing preamble\r\n");
return &preamble;
} }
if(charCount > MAX_PREAMBLE_SIZE) {
printf("ServiceInterfaceBuffer: Char count too large for maximum "
"preamble size");
return &preamble;
}
currentSize += charCount;
if(preambleSize != nullptr) {
*preambleSize = currentSize;
}
return &preamble;
} }
#endif
#ifdef UT699 #ifdef UT699
#include <framework/osal/rtems/Interrupt.h> #include <framework/osal/rtems/Interrupt.h>
ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) { ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message,
uint16_t port) {
this->log_message = set_message; this->log_message = set_message;
this->isActive = true; this->isActive = true;
setp( buf, buf + BUF_SIZE ); setp( buf, buf + BUF_SIZE );

View File

@ -1,51 +1,71 @@
#ifndef FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ #ifndef FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_
#define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ #define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <iostream> #include <iostream>
#include <iosfwd>
#include <sstream> #include <sstream>
#include <cstdio> #include <iomanip>
#ifndef UT699 #ifndef UT699
class ServiceInterfaceBuffer: public std::basic_streambuf<char,
std::char_traits<char> > { /**
* @brief This is the underlying stream buffer which implements the
* streambuf class and overloads the overflow() and sync() methods
* @details
* This class is used to modify the output of the stream, for example by adding.
* It also calls the char printing function which is implemented in the
* board supply package (BSP).
*/
class ServiceInterfaceBuffer:
public std::streambuf {
friend class ServiceInterfaceStream; friend class ServiceInterfaceStream;
public: public:
ServiceInterfaceBuffer(std::string set_message, uint16_t port); static constexpr uint8_t MAX_PREAMBLE_SIZE = 40;
ServiceInterfaceBuffer(std::string setMessage, bool addCrToPreamble,
bool buffered, bool errStream, uint16_t port);
protected: protected:
bool isActive; bool isActive;
// This is called when buffer becomes full. If //! This is called when buffer becomes full. If
// buffer is not used, then this is called every //! buffer is not used, then this is called every
// time when characters are put to stream. //! time when characters are put to stream.
virtual int overflow(int c = Traits::eof()); int overflow(int c = Traits::eof()) override;
// This function is called when stream is flushed, //! This function is called when stream is flushed,
// for example when std::endl is put to stream. //! for example when std::endl is put to stream.
virtual int sync(void); int sync(void) override;
bool isBuffered() const;
private: private:
// For additional message information //! For additional message information
std::string log_message; std::string logMessage;
std::string preamble;
// For EOF detection // For EOF detection
typedef std::char_traits<char> Traits; typedef std::char_traits<char> Traits;
// Work in buffer mode. It is also possible to work without buffer. //! This is useful for some terminal programs which do not have
//! implicit carriage return with newline characters.
bool addCrToPreamble;
//! Specifies whether the stream operates in buffered or unbuffered mode.
bool buffered;
//! This specifies to print to stderr and work in unbuffered mode.
bool errStream;
//! Needed for buffered mode.
static size_t const BUF_SIZE = 128; static size_t const BUF_SIZE = 128;
char buf[BUF_SIZE]; char buf[BUF_SIZE];
// In this function, the characters are parsed. //! In this function, the characters are parsed.
void putChars(char const* begin, char const* end); void putChars(char const* begin, char const* end);
std::string* getPreamble(size_t * preambleSize = nullptr);
}; };
#endif #endif
#ifdef UT699 #ifdef UT699
class ServiceInterfaceBuffer: public std::basic_streambuf<char, class ServiceInterfaceBuffer: public std::basic_streambuf<char,
std::char_traits<char> > { std::char_traits<char> > {

View File

@ -1,11 +1,32 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include <framework/serviceinterface/ServiceInterfaceStream.h>
ServiceInterfaceStream::ServiceInterfaceStream(std::string setMessage,
bool addCrToPreamble, bool buffered, bool errStream, uint16_t port) :
std::ostream(&streambuf),
streambuf(setMessage, addCrToPreamble, buffered, errStream, port) {}
void ServiceInterfaceStream::setActive( bool myActive) { void ServiceInterfaceStream::setActive( bool myActive) {
this->buf.isActive = myActive; this->streambuf.isActive = myActive;
} }
ServiceInterfaceStream::ServiceInterfaceStream(std::string set_message, std::string* ServiceInterfaceStream::getPreamble() {
uint16_t port) : return streambuf.getPreamble();
std::basic_ostream<char, std::char_traits<char> >(&buf), buf( }
set_message, port) {
void ServiceInterfaceStream::print(std::string error,
bool withPreamble, bool withNewline, bool flush) {
if(not streambuf.isBuffered() and withPreamble) {
*this << getPreamble() << error;
}
else {
*this << error;
}
if(withNewline) {
*this << "\n";
}
// if mode is non-buffered, no need to flush.
if(flush and streambuf.isBuffered()) {
this->flush();
}
} }

View File

@ -3,28 +3,56 @@
#include <framework/serviceinterface/ServiceInterfaceBuffer.h> #include <framework/serviceinterface/ServiceInterfaceBuffer.h>
#include <iostream> #include <iostream>
#include <iosfwd>
#include <sstream>
#include <cstdio> #include <cstdio>
// Unfortunately, there must be a forward declaration of log_fe /**
// (MUST be defined in main), to let the system know where to write to. * Generic service interface stream which can be used like std::cout or
namespace sif { * std::cerr but has additional capability. Add preamble and timestamp
extern std::ostream debug; * to output. Can be run in buffered or unbuffered mode.
extern std::ostream info; */
extern std::ostream warning; class ServiceInterfaceStream : public std::ostream {
extern std::ostream error;
}
class ServiceInterfaceStream : public std::basic_ostream< char, std::char_traits< char > > {
protected:
ServiceInterfaceBuffer buf;
public: public:
ServiceInterfaceStream( std::string set_message, uint16_t port = 1234 ); /**
* This constructor is used by specifying the preamble message.
* Optionally, the output can be directed to stderr and a CR character
* can be prepended to the preamble.
* @param setMessage message of preamble.
* @param addCrToPreamble Useful for applications like Puttty.
* @param buffered specify whether to use buffered mode.
* @param errStream specify which output stream to use (stderr or stdout).
*/
ServiceInterfaceStream(std::string setMessage,
bool addCrToPreamble = false, bool buffered = true,
bool errStream = false, uint16_t port = 1234);
//! An inactive stream will not print anything.
void setActive( bool ); void setActive( bool );
/**
* This can be used to retrieve the preamble in case it should be printed in
* the unbuffered mode.
* @return Preamle consisting of log message and timestamp.
*/
std::string* getPreamble();
/**
* This prints an error with a preamble. Useful if using the unbuffered
* mode. Flushes in default mode (prints immediately).
*/
void print(std::string error, bool withPreamble = true,
bool withNewline = true, bool flush = true);
protected:
ServiceInterfaceBuffer streambuf;
}; };
// Forward declaration of interface streams. These should be instantiated in
// main. They can then be used like std::cout or std::cerr.
namespace sif {
extern ServiceInterfaceStream debug;
extern ServiceInterfaceStream info;
extern ServiceInterfaceStream warning;
extern ServiceInterfaceStream error;
}
#endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */ #endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */

View File

@ -1,9 +1,11 @@
#ifndef PERIODICTASKIF_H_ #ifndef FRAMEWORK_TASK_PERIODICTASKIF_H_
#define PERIODICTASKIF_H_ #define FRAMEWORK_TASK_PERIODICTASKIF_H_
#include <framework/objectmanager/SystemObjectIF.h> #include <framework/objectmanager/SystemObjectIF.h>
#include <framework/timemanager/Clock.h>
#include <cstddef> #include <cstddef>
class ExecutableObjectIF; class ExecutableObjectIF;
/** /**
* New version of TaskIF * New version of TaskIF
* Follows RAII principles, i.e. there's no create or delete method. * Follows RAII principles, i.e. there's no create or delete method.
@ -17,11 +19,27 @@ public:
*/ */
virtual ~PeriodicTaskIF() { } virtual ~PeriodicTaskIF() { }
/** /**
* @brief With the startTask method, a created task can be started for the first time. * @brief With the startTask method, a created task can be started
* for the first time.
*/ */
virtual ReturnValue_t startTask() = 0; virtual ReturnValue_t startTask() = 0;
virtual ReturnValue_t addComponent(object_id_t object) {return HasReturnvaluesIF::RETURN_FAILED;}; /**
* Add a component (object) to a periodic task. The pointer to the
* task can be set optionally
* @param object
* Add an object to the task. The most important case is to add an
* executable object with a function which will be called regularly
* (see ExecutableObjectIF)
* @param setTaskIF
* Can be used to specify whether the task object pointer is passed
* to the component.
* @return
*/
virtual ReturnValue_t addComponent(object_id_t object,
bool setTaskIF = true) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t sleepFor(uint32_t ms) = 0; virtual ReturnValue_t sleepFor(uint32_t ms) = 0;

View File

@ -1,5 +1,6 @@
#include <framework/timemanager/CCSDSTime.h> #include <framework/timemanager/CCSDSTime.h>
#include <stdio.h> #include <stdio.h>
#include <inttypes.h>
#include <math.h> #include <math.h>
CCSDSTime::CCSDSTime() { CCSDSTime::CCSDSTime() {
@ -154,15 +155,17 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
if (length < 19) { if (length < 19) {
return RETURN_FAILED; return RETURN_FAILED;
} }
// Newlib nano can't parse uint8, see SCNu8 documentation and https://sourceware.org/newlib/README
// Suggestion: use uint16 all the time. This should work on all systems.
#ifdef NEWLIB_NANO_NO_C99_IO
uint16_t year; uint16_t year;
uint8_t month; uint16_t month;
uint16_t day; uint16_t day;
uint8_t hour; uint16_t hour;
uint8_t minute; uint16_t minute;
float second; float second;
//try Code A (yyyy-mm-dd) int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year,
int count = sscanf((char *) from, "%4hi-%2hhi-%2hiT%2hhi:%2hhi:%fZ", &year, &month, &day, &hour, &minute, &second);
&month, &day, &hour, &minute, &second);
if (count == 6) { if (count == 6) {
to->year = year; to->year = year;
to->month = month; to->month = month;
@ -174,9 +177,52 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
return RETURN_OK; return RETURN_OK;
} }
//try Code B (yyyy-ddd) // try Code B (yyyy-ddd)
count = sscanf((char *) from, "%4hi-%3hiT%2hhi:%2hhi:%fZ", &year, &day, count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &day,
&hour, &minute, &second); &hour, &minute, &second);
if (count == 5) {
uint8_t tempDay;
ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year,
reinterpret_cast<uint8_t *>(&month), reinterpret_cast<uint8_t *>(&tempDay));
if (result != RETURN_OK) {
return RETURN_FAILED;
}
to->year = year;
to->month = month;
to->day = tempDay;
to->hour = hour;
to->minute = minute;
to->second = second;
to->usecond = (second - floor(second)) * 1000000;
return RETURN_OK;
}
// Warning: Compiler/Linker fails ambiguously if library does not implement
// C99 I/O
#else
uint16_t year;
uint8_t month;
uint16_t day;
uint8_t hour;
uint8_t minute;
float second;
//try Code A (yyyy-mm-dd)
int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu8 "-%2" SCNu16
"T%2" SCNu8 ":%2" SCNu8 ":%fZ", &year, &month, &day,
&hour, &minute, &second);
if (count == 6) {
to->year = year;
to->month = month;
to->day = day;
to->hour = hour;
to->minute = minute;
to->second = second;
to->usecond = (second - floor(second)) * 1000000;
return RETURN_OK;
}
//try Code B (yyyy-ddd)
count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu8
":%2" SCNu8 ":%fZ", &year, &day, &hour, &minute, &second);
if (count == 5) { if (count == 5) {
uint8_t tempDay; uint8_t tempDay;
ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, &month, ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, &month,
@ -193,6 +239,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
to->usecond = (second - floor(second)) * 1000000; to->usecond = (second - floor(second)) * 1000000;
return RETURN_OK; return RETURN_OK;
} }
#endif
return UNSUPPORTED_TIME_FORMAT; return UNSUPPORTED_TIME_FORMAT;
} }

View File

@ -230,8 +230,8 @@ void CommandingServiceBase::handleRequestQueue() {
address = message.getStorageId(); address = message.getStorageId();
packet.setStoreAddress(address); packet.setStoreAddress(address);
if (packet.getSubService() == 0 if ((packet.getSubService() == 0)
or isValidSubservice(packet.getSubService()) != RETURN_OK) { or (isValidSubservice(packet.getSubService()) != RETURN_OK)) {
rejectPacket(TC_VERIFY::START_FAILURE, &packet, INVALID_SUBSERVICE); rejectPacket(TC_VERIFY::START_FAILURE, &packet, INVALID_SUBSERVICE);
continue; continue;
} }

View File

@ -116,7 +116,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) override;
protected: protected:
/** /**
@ -173,9 +173,7 @@ protected:
* This function is implemented by child services to specify how replies * This function is implemented by child services to specify how replies
* to a command from another software component are handled. * to a command from another software component are handled.
* @param reply * @param reply
* This is the reply which can be accessed via the command message * This is the reply in form of a generic read-only command message.
* interface. The internal message pointer can be passed to different
* command message implementations (see CommandMessageIF)
* @param previousCommand * @param previousCommand
* Command_t of related command * Command_t of related command
* @param state [out/in] * @param state [out/in]
@ -188,11 +186,12 @@ protected:
* @return * @return
* - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to * - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to
* generate TC verification success * generate TC verification success
* - @c INVALID_REPLY Calls handleUnrequestedReply * - @c INVALID_REPLY calls handleUnrequestedReply
* - Anything else triggers a TC verification failure. If RETURN_FAILED * - Anything else triggers a TC verification failure. If RETURN_FAILED or
* is returned and the command ID is CommandMessage::REPLY_REJECTED, * INVALID_REPLY is returned and the command ID is
* a failure verification message with the reason as the error parameter * CommandMessage::REPLY_REJECTED, a failure verification message
* and the initial command as failure parameter 1. * with the reason as the error parameter and the initial command as
* failure parameter 1 is generated.
*/ */
virtual ReturnValue_t handleReply(const CommandMessage* reply, virtual ReturnValue_t handleReply(const CommandMessage* reply,
Command_t previousCommand, uint32_t *state, Command_t previousCommand, uint32_t *state,
@ -255,6 +254,7 @@ protected:
uint32_t failureParameter1 = 0; uint32_t failureParameter1 = 0;
uint32_t failureParameter2 = 0; uint32_t failureParameter2 = 0;
object_id_t packetSource;
static object_id_t defaultPacketSource; static object_id_t defaultPacketSource;
object_id_t packetSource = objects::NO_OBJECT; object_id_t packetSource = objects::NO_OBJECT;
static object_id_t defaultPacketDestination; static object_id_t defaultPacketDestination;
@ -303,6 +303,7 @@ protected:
void checkAndExecuteFifo(CommandMapIter iter); void checkAndExecuteFifo(CommandMapIter iter);
private: private:
/** /**
* This method handles internal execution of a command, * This method handles internal execution of a command,
* once it has been started by @sa{startExecution()} in the request * once it has been started by @sa{startExecution()} in the request

View File

@ -9,10 +9,11 @@
object_id_t PusServiceBase::packetSource = 0; object_id_t PusServiceBase::packetSource = 0;
object_id_t PusServiceBase::packetDestination = 0; object_id_t PusServiceBase::packetDestination = 0;
PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid, uint8_t setServiceId) : PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid,
SystemObject(setObjectId), apid(setApid), serviceId(setServiceId), errorParameter1( uint8_t setServiceId) :
0), errorParameter2(0), requestQueue(NULL) { SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) {
requestQueue = QueueFactory::instance()->createMessageQueue(PUS_SERVICE_MAX_RECEPTION); requestQueue = QueueFactory::instance()->
createMessageQueue(PUS_SERVICE_MAX_RECEPTION);
} }
PusServiceBase::~PusServiceBase() { PusServiceBase::~PusServiceBase() {
@ -20,50 +21,64 @@ PusServiceBase::~PusServiceBase() {
} }
ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) {
handleRequestQueue();
ReturnValue_t result = this->performService();
if (result != RETURN_OK) {
sif::error << "PusService " << (uint16_t) this->serviceId
<< ": performService returned with " << (int16_t) result
<< std::endl;
return RETURN_FAILED;
}
return RETURN_OK;
}
void PusServiceBase::setTaskIF(PeriodicTaskIF* taskHandle) {
this->taskHandle = taskHandle;
}
void PusServiceBase::handleRequestQueue() {
TmTcMessage message; TmTcMessage message;
ReturnValue_t result = RETURN_FAILED;
for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) {
ReturnValue_t status = this->requestQueue->receiveMessage(&message); ReturnValue_t status = this->requestQueue->receiveMessage(&message);
// debug << "PusServiceBase::performOperation: Receiving from MQ ID: " << std::hex << this->requestQueue.getId() // debug << "PusServiceBase::performOperation: Receiving from MQ ID: "
// << std::dec << " returned: " << status << std::endl; // << std::hex << this->requestQueue.getId()
// << std::dec << " returned: " << status << std::endl;
if (status == RETURN_OK) { if (status == RETURN_OK) {
this->currentPacket.setStoreAddress(message.getStorageId()); this->currentPacket.setStoreAddress(message.getStorageId());
// info << "Service " << (uint16_t) this->serviceId << ": new packet!" << std::endl; //info << "Service " << (uint16_t) this->serviceId <<
// ": new packet!" << std::endl;
ReturnValue_t return_code = this->handleRequest(); result = this->handleRequest(currentPacket.getSubService());
// debug << "Service " << (uint16_t)this->serviceId << ": handleRequest returned: " << (int)return_code << std::endl;
if (return_code == RETURN_OK) { // debug << "Service " << (uint16_t)this->serviceId <<
// ": handleRequest returned: " << (int)return_code << std::endl;
if (result == RETURN_OK) {
this->verifyReporter.sendSuccessReport( this->verifyReporter.sendSuccessReport(
TC_VERIFY::COMPLETION_SUCCESS, &this->currentPacket); TC_VERIFY::COMPLETION_SUCCESS, &this->currentPacket);
} else { }
else {
this->verifyReporter.sendFailureReport( this->verifyReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE, &this->currentPacket, TC_VERIFY::COMPLETION_FAILURE, &this->currentPacket,
return_code, 0, errorParameter1, errorParameter2); result, 0, errorParameter1, errorParameter2);
} }
this->currentPacket.deletePacket(); this->currentPacket.deletePacket();
errorParameter1 = 0; errorParameter1 = 0;
errorParameter2 = 0; errorParameter2 = 0;
} else if (status == MessageQueueIF::EMPTY) { }
else if (status == MessageQueueIF::EMPTY) {
status = RETURN_OK; status = RETURN_OK;
// debug << "PusService " << (uint16_t)this->serviceId << ": no new packet." << std::endl; // debug << "PusService " << (uint16_t)this->serviceId <<
// ": no new packet." << std::endl;
break; break;
} else { }
else {
sif::error << "PusServiceBase::performOperation: Service " sif::error << "PusServiceBase::performOperation: Service "
<< (uint16_t) this->serviceId << (uint16_t) this->serviceId
<< ": Error receiving packet. Code: " << std::hex << status << ": Error receiving packet. Code: " << std::hex << status
<< std::dec << std::endl; << std::dec << std::endl;
} }
} }
ReturnValue_t return_code = this->performService();
if (return_code == RETURN_OK) {
return RETURN_OK;
} else {
sif::error << "PusService " << (uint16_t) this->serviceId
<< ": performService returned with " << (int16_t) return_code
<< std::endl;
return RETURN_FAILED;
}
} }
uint16_t PusServiceBase::getIdentifier() { uint16_t PusServiceBase::getIdentifier() {
@ -79,19 +94,28 @@ ReturnValue_t PusServiceBase::initialize() {
if (result != RETURN_OK) { if (result != RETURN_OK) {
return result; return result;
} }
AcceptsTelemetryIF* dest_service = objectManager->get<AcceptsTelemetryIF>( AcceptsTelemetryIF* destService = objectManager->get<AcceptsTelemetryIF>(
packetDestination); packetDestination);
PUSDistributorIF* distributor = objectManager->get<PUSDistributorIF>( PUSDistributorIF* distributor = objectManager->get<PUSDistributorIF>(
packetSource); packetSource);
if ((dest_service != NULL) && (distributor != NULL)) { if ((destService != nullptr) && (distributor != nullptr)) {
this->requestQueue->setDefaultDestination( this->requestQueue->setDefaultDestination(
dest_service->getReportReceptionQueue()); destService->getReportReceptionQueue());
distributor->registerService(this); distributor->registerService(this);
return RETURN_OK; return RETURN_OK;
} else { }
else {
sif::error << "PusServiceBase::PusServiceBase: Service " sif::error << "PusServiceBase::PusServiceBase: Service "
<< (uint32_t) this->serviceId << ": Configuration error." << (uint32_t) this->serviceId << ": Configuration error."
<< " Make sure packetSource and packetDestination are defined correctly" << std::endl; << " Make sure packetSource and packetDestination are defined "
"correctly" << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
} }
ReturnValue_t PusServiceBase::initializeAfterTaskCreation() {
// If task parameters, for example task frequency are required, this
// function should be overriden and the system object task IF can
// be used to get those parameters.
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,5 +1,5 @@
#ifndef PUSSERVICEBASE_H_ #ifndef FRAMEWORK_TMTCSERVICES_PUSSERVICEBASE_H_
#define PUSSERVICEBASE_H_ #define FRAMEWORK_TMTCSERVICES_PUSSERVICEBASE_H_
#include <framework/objectmanager/ObjectManagerIF.h> #include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/objectmanager/SystemObject.h> #include <framework/objectmanager/SystemObject.h>
@ -9,7 +9,6 @@
#include <framework/tmtcservices/AcceptsTelecommandsIF.h> #include <framework/tmtcservices/AcceptsTelecommandsIF.h>
#include <framework/tmtcservices/VerificationCodes.h> #include <framework/tmtcservices/VerificationCodes.h>
#include <framework/tmtcservices/VerificationReporter.h> #include <framework/tmtcservices/VerificationReporter.h>
#include <framework/internalError/InternalErrorReporterIF.h>
#include <framework/ipc/MessageQueueIF.h> #include <framework/ipc/MessageQueueIF.h>
namespace Factory{ namespace Factory{
@ -17,72 +16,100 @@ void setStaticFrameworkObjectIds();
} }
/** /**
* \defgroup pus_services PUS Service Framework * @defgroup pus_services PUS Service Framework
* These group contains all implementations of PUS Services in the OBSW. * These group contains all implementations of PUS Services in the OBSW.
* Most of the Services are directly taken from the ECSS PUS Standard. * Most of the Services are directly taken from the ECSS PUS Standard.
*/ */
/** /**
* \brief This class is the basis for all PUS Services, which can immediately process Telecommand Packets. * @brief This class is the basis for all PUS Services,
* It manages Telecommand reception and the generation of Verification Reports. Every class that inherits * which can immediately process Telecommand Packets.
* from this abstract class has to implement handleRequest and performService. Services that are created with this * @details
* It manages Telecommand reception and the generation of Verification Reports.
* Every class that inherits from this abstract class has to implement
* handleRequest and performService. Services that are created with this
* Base class have to handle any kind of request immediately on reception. * Base class have to handle any kind of request immediately on reception.
* All PUS Services are System Objects, so an Object ID needs to be specified on construction. * All PUS Services are System Objects, so an Object ID needs to be specified
* \ingroup pus_services * on construction.
* @ingroup pus_services
*/ */
class PusServiceBase : public ExecutableObjectIF, public AcceptsTelecommandsIF, public SystemObject, public HasReturnvaluesIF { class PusServiceBase : public ExecutableObjectIF,
public AcceptsTelecommandsIF,
public SystemObject,
public HasReturnvaluesIF {
friend void (Factory::setStaticFrameworkObjectIds)(); friend void (Factory::setStaticFrameworkObjectIds)();
public: public:
/** /**
* The constructor for the class. * @brief The passed values are set, but inter-object initialization is
* The passed values are set, but inter-object initialization is done in the initialize method. * done in the initialize method.
* @param setObjectId The system object identifier of this Service instance. * @param setObjectId
* @param set_apid The APID the Service is instantiated for. * The system object identifier of this Service instance.
* @param set_service_id The Service Identifier as specified in ECSS PUS. * @param setApid
* The APID the Service is instantiated for.
* @param setServiceId
* The Service Identifier as specified in ECSS PUS.
*/ */
PusServiceBase( object_id_t setObjectId, uint16_t setApid, uint8_t setServiceId); PusServiceBase( object_id_t setObjectId, uint16_t setApid,
uint8_t setServiceId);
/** /**
* The destructor is empty. * The destructor is empty.
*/ */
virtual ~PusServiceBase(); virtual ~PusServiceBase();
/** /**
* @brief The handleRequest method shall handle any kind of Telecommand Request immediately. * @brief The handleRequest method shall handle any kind of Telecommand
* Request immediately.
* @details * @details
* Implemetations can take the Telecommand in currentPacket and perform any kind of operation. * Implemetations can take the Telecommand in currentPacket and perform
* They may send additional "Start Success (1,3)" messages with the verifyReporter, but Completion * any kind of operation.
* Success or Failure Reports are generated automatically after execution of this method. * They may send additional "Start Success (1,3)" messages with the
* verifyReporter, but Completion Success or Failure Reports are generated
* automatically after execution of this method.
* *
* If a Telecommand can not be executed within one call cycle, * If a Telecommand can not be executed within one call cycle,
* this Base class is not the right parent. * this Base class is not the right parent.
* *
* The child class may add additional error information by setting #errorParameters which are * The child class may add additional error information by setting
* attached to the generated verification message. * #errorParameters which aren attached to the generated verification
* message.
* *
* Subservice checking should be implemented in this method. * Subservice checking should be implemented in this method.
* *
* @return The returned status_code is directly taken as main error code in the Verification Report. * @return The returned status_code is directly taken as main error code
* in the Verification Report.
* On success, RETURN_OK shall be returned. * On success, RETURN_OK shall be returned.
*/ */
virtual ReturnValue_t handleRequest() = 0; virtual ReturnValue_t handleRequest(uint8_t subservice) = 0;
/** /**
* In performService, implementations can handle periodic, non-TC-triggered activities. * In performService, implementations can handle periodic,
* non-TC-triggered activities.
* The performService method is always called. * The performService method is always called.
* @return A success or failure code that does not trigger any kind of verification message. * @return Currently, everything other that RETURN_OK only triggers
* diagnostic output.
*/ */
virtual ReturnValue_t performService() = 0; virtual ReturnValue_t performService() = 0;
/** /**
* This method implements the typical activity of a simple PUS Service. * This method implements the typical activity of a simple PUS Service.
* It checks for new requests, and, if found, calls handleRequest, sends completion verification messages and deletes * It checks for new requests, and, if found, calls handleRequest, sends
* completion verification messages and deletes
* the TC requests afterwards. * the TC requests afterwards.
* performService is always executed afterwards. * performService is always executed afterwards.
* @return \c RETURN_OK if the periodic performService was successful. * @return @c RETURN_OK if the periodic performService was successful.
* \c RETURN_FAILED else. * @c RETURN_FAILED else.
*/ */
ReturnValue_t performOperation(uint8_t opCode); ReturnValue_t performOperation(uint8_t opCode) override;
virtual uint16_t getIdentifier(); virtual uint16_t getIdentifier() override;
MessageQueueId_t getRequestQueue(); MessageQueueId_t getRequestQueue() override;
virtual ReturnValue_t initialize(); virtual ReturnValue_t initialize() override;
virtual void setTaskIF(PeriodicTaskIF* taskHandle) override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
protected: protected:
/**
* @brief Handle to the underlying task
* @details
* Will be set by setTaskIF(), which is called on task creation.
*/
PeriodicTaskIF* taskHandle = nullptr;
/** /**
* The APID of this instance of the Service. * The APID of this instance of the Service.
*/ */
@ -94,19 +121,19 @@ protected:
/** /**
* One of two error parameters for additional error information. * One of two error parameters for additional error information.
*/ */
uint32_t errorParameter1; uint32_t errorParameter1 = 0;
/** /**
* One of two error parameters for additional error information. * One of two error parameters for additional error information.
*/ */
uint32_t errorParameter2; uint32_t errorParameter2 = 0;
/** /**
* This is a complete instance of the Telecommand reception queue of the class. * This is a complete instance of the telecommand reception queue
* It is initialized on construction of the class. * of the class. It is initialized on construction of the class.
*/ */
MessageQueueIF* requestQueue; MessageQueueIF* requestQueue = nullptr;
/** /**
* An instance of the VerificationReporter class, that simplifies sending any kind of * An instance of the VerificationReporter class, that simplifies
* Verification Message to the TC Verification Service. * sending any kind of verification message to the TC Verification Service.
*/ */
VerificationReporter verifyReporter; VerificationReporter verifyReporter;
/** /**
@ -121,9 +148,12 @@ protected:
private: private:
/** /**
* This constant sets the maximum number of packets accepted per call. * This constant sets the maximum number of packets accepted per call.
* Remember that one packet must be completely handled in one #handleRequest call. * Remember that one packet must be completely handled in one
* #handleRequest call.
*/ */
static const uint8_t PUS_SERVICE_MAX_RECEPTION = 10; static const uint8_t PUS_SERVICE_MAX_RECEPTION = 10;
void handleRequestQueue();
}; };
#endif /* PUSSERVICEBASE_H_ */ #endif /* PUSSERVICEBASE_H_ */