FIFO is StaticFIFO now, new FIFO using vector #127

Merged
gaisser merged 21 commits from KSat/fsfw:mueller_FIFO_static_normal into master 2020-09-01 13:09:00 +02:00
18 changed files with 690 additions and 432 deletions
Showing only changes of commit 35fe41361b - Show all commits

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

@ -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,73 @@ 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;
// Tick count has overflown
if(currentTickCount < xLastWakeTime) {
// Time to wake has overflown as well. If the tick count
// is larger than the time to wake, a deadline was missed.
if(timeToWake < xLastWakeTime and
currentTickCount > timeToWake) {
handleMissedDeadline();
}
}
// No tick count overflow. If the timeToWake has not overflown
// and the current tick count is larger than the time to wake,
// a deadline was missed.
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

@ -78,9 +78,9 @@ int ServiceInterfaceBuffer::sync(void) {
} }
size_t preambleSize = 0; size_t preambleSize = 0;
auto preamble = getPreamble(&preambleSize); std::string* preamble = getPreamble(&preambleSize);
// Write logMessage and time // Write logMessage and time
this->putChars(preamble.data(), preamble.data() + preambleSize); this->putChars(preamble->data(), preamble->data() + preambleSize);
// Handle output // Handle output
this->putChars(pbase(), pptr()); this->putChars(pbase(), pptr());
// This tells that buffer is empty again // This tells that buffer is empty again
@ -92,7 +92,7 @@ bool ServiceInterfaceBuffer::isBuffered() const {
return buffered; return buffered;
} }
std::string ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) { std::string* ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) {
Clock::TimeOfDay_t loggerTime; Clock::TimeOfDay_t loggerTime;
Clock::getDateAndTime(&loggerTime); Clock::getDateAndTime(&loggerTime);
size_t currentSize = 0; size_t currentSize = 0;
@ -110,18 +110,18 @@ std::string ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) {
loggerTime.usecond /1000); loggerTime.usecond /1000);
if(charCount < 0) { if(charCount < 0) {
printf("ServiceInterfaceBuffer: Failure parsing preamble\r\n"); printf("ServiceInterfaceBuffer: Failure parsing preamble\r\n");
return ""; return &preamble;
} }
if(charCount > MAX_PREAMBLE_SIZE) { if(charCount > MAX_PREAMBLE_SIZE) {
printf("ServiceInterfaceBuffer: Char count too large for maximum " printf("ServiceInterfaceBuffer: Char count too large for maximum "
"preamble size"); "preamble size");
return ""; return &preamble;
} }
currentSize += charCount; currentSize += charCount;
if(preambleSize != nullptr) { if(preambleSize != nullptr) {
*preambleSize = currentSize; *preambleSize = currentSize;
} }
return preamble; return &preamble;
} }

View File

@ -60,7 +60,7 @@ private:
//! 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); std::string* getPreamble(size_t * preambleSize = nullptr);
}; };
#endif #endif

View File

@ -9,7 +9,7 @@ void ServiceInterfaceStream::setActive( bool myActive) {
this->streambuf.isActive = myActive; this->streambuf.isActive = myActive;
} }
std::string ServiceInterfaceStream::getPreamble() { std::string* ServiceInterfaceStream::getPreamble() {
return streambuf.getPreamble(); return streambuf.getPreamble();
} }

View File

@ -33,7 +33,7 @@ public:
* the unbuffered mode. * the unbuffered mode.
* @return Preamle consisting of log message and timestamp. * @return Preamle consisting of log message and timestamp.
*/ */
std::string getPreamble(); std::string* getPreamble();
/** /**
* This prints an error with a preamble. Useful if using the unbuffered * This prints an error with a preamble. Useful if using the unbuffered

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

@ -1,22 +1,21 @@
/* #include <framework/tcdistribution/PUSDistributorIF.h>
* CommandingServiceBase.cpp #include <framework/tmtcservices/AcceptsTelemetryIF.h>
* #include <framework/objectmanager/ObjectManagerIF.h>
* Created on: 28.08.2019
* Author: gaisser
*/
#include <framework/tmtcservices/CommandingServiceBase.h> #include <framework/tmtcservices/CommandingServiceBase.h>
#include <framework/tmtcservices/TmTcMessage.h>
#include <framework/ipc/QueueFactory.h>
#include <framework/tmtcpacket/pus/TcPacketStored.h>
#include <framework/tmtcpacket/pus/TmPacketStored.h>
CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId,
uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands,
uint16_t commandTimeout_seconds, object_id_t setPacketSource, uint16_t commandTimeoutSeconds, object_id_t setPacketSource,
object_id_t setPacketDestination, size_t queueDepth) : object_id_t setPacketDestination, size_t queueDepth) :
SystemObject(setObjectId), apid(apid), service(service), timeout_seconds( SystemObject(setObjectId), apid(apid), service(service),
commandTimeout_seconds), tmPacketCounter(0), IPCStore(NULL), TCStore( timeoutSeconds(commandTimeoutSeconds),
NULL), commandQueue(NULL), requestQueue(NULL), commandMap( commandMap(numberOfParallelCommands), packetSource(setPacketSource),
numberOfParallelCommands), failureParameter1(0), failureParameter2( packetDestination(setPacketDestination) {
0), packetSource(setPacketSource), packetDestination(
setPacketDestination),executingTask(NULL) {
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth); requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
} }
@ -57,8 +56,10 @@ ReturnValue_t CommandingServiceBase::initialize() {
objectManager->get<AcceptsTelemetryIF>(packetDestination); objectManager->get<AcceptsTelemetryIF>(packetDestination);
PUSDistributorIF* distributor = objectManager->get<PUSDistributorIF>( PUSDistributorIF* distributor = objectManager->get<PUSDistributorIF>(
packetSource); packetSource);
if ((packetForwarding == NULL) && (distributor == NULL)) { if (packetForwarding == nullptr or distributor == nullptr) {
return RETURN_FAILED; sif::error << "CommandingServiceBase::intialize: Packet source or "
"packet destination invalid!" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
distributor->registerService(this); distributor->registerService(this);
@ -68,8 +69,10 @@ ReturnValue_t CommandingServiceBase::initialize() {
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
TCStore = objectManager->get<StorageManagerIF>(objects::TC_STORE); TCStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if ((IPCStore == NULL) || (TCStore == NULL)) { if (IPCStore == nullptr or TCStore == nullptr) {
return RETURN_FAILED; sif::error << "CommandingServiceBase::intialize: IPC store or TC store "
"not initialized yet!" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
return RETURN_OK; return RETURN_OK;
@ -77,97 +80,126 @@ ReturnValue_t CommandingServiceBase::initialize() {
} }
void CommandingServiceBase::handleCommandQueue() { void CommandingServiceBase::handleCommandQueue() {
CommandMessage reply, nextCommand; CommandMessage reply;
ReturnValue_t result, sendResult = RETURN_OK; ReturnValue_t result = RETURN_FAILED;
bool isStep = false;
for (result = commandQueue->receiveMessage(&reply); result == RETURN_OK; for (result = commandQueue->receiveMessage(&reply); result == RETURN_OK;
result = commandQueue->receiveMessage(&reply)) { result = commandQueue->receiveMessage(&reply)) {
isStep = false; handleCommandMessage(&reply);
typename FixedMap<MessageQueueId_t,
CommandingServiceBase::CommandInfo>::Iterator iter;
if (reply.getSender() == MessageQueueIF::NO_QUEUE) {
handleUnrequestedReply(&reply);
continue;
}
if ((iter = commandMap.find(reply.getSender())) == commandMap.end()) {
handleUnrequestedReply(&reply);
continue;
}
nextCommand.setCommand(CommandMessage::CMD_NONE);
result = handleReply(&reply, iter->command, &iter->state, &nextCommand,
iter->objectId, &isStep);
switch (result) {
case EXECUTION_COMPLETE:
case RETURN_OK:
case NO_STEP_MESSAGE:
iter->command = nextCommand.getCommand();
if (nextCommand.getCommand() != CommandMessage::CMD_NONE) {
sendResult = commandQueue->sendMessage(reply.getSender(),
&nextCommand);
}
if (sendResult == RETURN_OK) {
if (isStep) {
if (result != NO_STEP_MESSAGE) {
verificationReporter.sendSuccessReport(
TC_VERIFY::PROGRESS_SUCCESS,
iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, ++iter->step);
}
} else {
verificationReporter.sendSuccessReport(
TC_VERIFY::COMPLETION_SUCCESS,
iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, 0);
checkAndExecuteFifo(&iter);
}
} else {
if (isStep) {
nextCommand.clearCommandMessage();
verificationReporter.sendFailureReport(
TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags,
iter->tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, sendResult,
++iter->step, failureParameter1, failureParameter2);
} else {
nextCommand.clearCommandMessage();
verificationReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE,
iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, sendResult, 0,
failureParameter1, failureParameter2);
}
failureParameter1 = 0;
failureParameter2 = 0;
checkAndExecuteFifo(&iter);
}
break;
case INVALID_REPLY:
//might be just an unrequested reply at a bad moment
handleUnrequestedReply(&reply);
break;
default:
if (isStep) {
verificationReporter.sendFailureReport(
TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl,
result, ++iter->step, failureParameter1,
failureParameter2);
} else {
verificationReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl,
result, 0, failureParameter1, failureParameter2);
}
failureParameter1 = 0;
failureParameter2 = 0;
checkAndExecuteFifo(&iter);
break;
}
} }
} }
void CommandingServiceBase::handleCommandMessage(CommandMessage* reply) {
bool isStep = false;
CommandMessage nextCommand;
CommandMapIter iter = commandMap.find(reply->getSender());
// handle unrequested reply first
if (reply->getSender() == MessageQueueIF::NO_QUEUE or
iter == commandMap.end()) {
handleUnrequestedReply(reply);
return;
}
nextCommand.setCommand(CommandMessage::CMD_NONE);
// Implemented by child class, specifies what to do with reply.
ReturnValue_t result = handleReply(reply, iter->command, &iter->state,
&nextCommand, iter->objectId, &isStep);
/* If the child implementation does not implement special handling for
* rejected replies (RETURN_FAILED is returned), a failure verification
* will be generated with the reason as the return code and the initial
* command as failure parameter 1 */
if(reply->getCommand() == CommandMessage::REPLY_REJECTED and
result == RETURN_FAILED) {
result = reply->getReplyRejectedReason();
failureParameter1 = iter->command;
}
switch (result) {
case EXECUTION_COMPLETE:
case RETURN_OK:
case NO_STEP_MESSAGE:
// handle result of reply handler implemented by developer.
handleReplyHandlerResult(result, iter, &nextCommand, reply, isStep);
break;
case INVALID_REPLY:
//might be just an unrequested reply at a bad moment
handleUnrequestedReply(reply);
break;
default:
if (isStep) {
verificationReporter.sendFailureReport(
TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl,
result, ++iter->step, failureParameter1,
failureParameter2);
} else {
verificationReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl,
result, 0, failureParameter1, failureParameter2);
}
failureParameter1 = 0;
failureParameter2 = 0;
checkAndExecuteFifo(iter);
break;
}
}
void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result,
CommandMapIter iter, CommandMessage* nextCommand,
CommandMessage* reply, bool& isStep) {
iter->command = nextCommand->getCommand();
// In case a new command is to be sent immediately, this is performed here.
// If no new command is sent, only analyse reply result by initializing
// sendResult as RETURN_OK
ReturnValue_t sendResult = RETURN_OK;
if (nextCommand->getCommand() != CommandMessage::CMD_NONE) {
sendResult = commandQueue->sendMessage(reply->getSender(),
nextCommand);
}
if (sendResult == RETURN_OK) {
if (isStep and result != NO_STEP_MESSAGE) {
verificationReporter.sendSuccessReport(
TC_VERIFY::PROGRESS_SUCCESS,
iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, ++iter->step);
}
else {
verificationReporter.sendSuccessReport(
TC_VERIFY::COMPLETION_SUCCESS,
iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, 0);
checkAndExecuteFifo(iter);
}
}
else {
if (isStep) {
nextCommand->clearCommandMessage();
verificationReporter.sendFailureReport(
TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags,
iter->tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, sendResult,
++iter->step, failureParameter1, failureParameter2);
} else {
nextCommand->clearCommandMessage();
verificationReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE,
iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, sendResult, 0,
failureParameter1, failureParameter2);
}
failureParameter1 = 0;
failureParameter2 = 0;
checkAndExecuteFifo(iter);
}
}
void CommandingServiceBase::handleRequestQueue() { void CommandingServiceBase::handleRequestQueue() {
TmTcMessage message; TmTcMessage message;
ReturnValue_t result; ReturnValue_t result;
@ -181,7 +213,7 @@ void CommandingServiceBase::handleRequestQueue() {
packet.setStoreAddress(address); packet.setStoreAddress(address);
if ((packet.getSubService() == 0) if ((packet.getSubService() == 0)
|| (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;
} }
@ -194,8 +226,7 @@ void CommandingServiceBase::handleRequestQueue() {
} }
//Is a command already active for the target object? //Is a command already active for the target object?
typename FixedMap<MessageQueueId_t, CommandMapIter iter;
CommandingServiceBase::CommandInfo>::Iterator iter;
iter = commandMap.find(queue); iter = commandMap.find(queue);
if (iter != commandMap.end()) { if (iter != commandMap.end()) {
@ -210,7 +241,7 @@ void CommandingServiceBase::handleRequestQueue() {
if (result != RETURN_OK) { if (result != RETURN_OK) {
rejectPacket(TC_VERIFY::START_FAILURE, &packet, BUSY); rejectPacket(TC_VERIFY::START_FAILURE, &packet, BUSY);
} else { } else {
startExecution(&packet, &iter); startExecution(&packet, iter);
} }
} }
@ -218,9 +249,9 @@ void CommandingServiceBase::handleRequestQueue() {
} }
void CommandingServiceBase::sendTmPacket(uint8_t subservice, ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
const uint8_t* data, uint32_t dataLen, const uint8_t* headerData, const uint8_t* data, size_t dataLen, const uint8_t* headerData,
uint32_t headerSize) { size_t headerSize) {
TmPacketStored tmPacketStored(this->apid, this->service, subservice, TmPacketStored tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, data, dataLen, headerData, headerSize); this->tmPacketCounter, data, dataLen, headerData, headerSize);
ReturnValue_t result = tmPacketStored.sendPacket( ReturnValue_t result = tmPacketStored.sendPacket(
@ -228,79 +259,79 @@ void CommandingServiceBase::sendTmPacket(uint8_t subservice,
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
this->tmPacketCounter++; this->tmPacketCounter++;
} }
return result;
} }
void CommandingServiceBase::sendTmPacket(uint8_t subservice, ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
object_id_t objectId, const uint8_t *data, uint32_t dataLen) { object_id_t objectId, const uint8_t *data, size_t dataLen) {
uint8_t buffer[sizeof(object_id_t)]; uint8_t buffer[sizeof(object_id_t)];
uint8_t* pBuffer = buffer; uint8_t* pBuffer = buffer;
size_t size = 0; size_t size = 0;
SerializeAdapter::serialize(&objectId, &pBuffer, &size, SerializeAdapter::serialize(&objectId, &pBuffer, &size,
sizeof(object_id_t), SerializeIF::Endianness::BIG); sizeof(object_id_t), SerializeIF::Endianness::BIG);
TmPacketStored tmPacketStored(this->apid, this->service, subservice, TmPacketStored tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, data, dataLen, buffer, size); this->tmPacketCounter, data, dataLen, buffer, size);
ReturnValue_t result = tmPacketStored.sendPacket( ReturnValue_t result = tmPacketStored.sendPacket(
requestQueue->getDefaultDestination(), requestQueue->getId()); requestQueue->getDefaultDestination(), requestQueue->getId());
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
this->tmPacketCounter++; this->tmPacketCounter++;
} }
return result;
} }
void CommandingServiceBase::sendTmPacket(uint8_t subservice, ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
SerializeIF* content, SerializeIF* header) { SerializeIF* content, SerializeIF* header) {
TmPacketStored tmPacketStored(this->apid, this->service, subservice, TmPacketStored tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, content, header); this->tmPacketCounter, content, header);
ReturnValue_t result = tmPacketStored.sendPacket( ReturnValue_t result = tmPacketStored.sendPacket(
requestQueue->getDefaultDestination(), requestQueue->getId()); requestQueue->getDefaultDestination(), requestQueue->getId());
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
this->tmPacketCounter++; this->tmPacketCounter++;
} }
return result;
} }
void CommandingServiceBase::startExecution( void CommandingServiceBase::startExecution(TcPacketStored *storedPacket,
TcPacketStored *storedPacket, CommandMapIter iter) {
typename FixedMap<MessageQueueId_t, ReturnValue_t result = RETURN_OK;
CommandingServiceBase::CommandInfo>::Iterator *iter) { CommandMessage command;
ReturnValue_t result, sendResult = RETURN_OK; iter->subservice = storedPacket->getSubService();
CommandMessage message; result = prepareCommand(&command, iter->subservice,
(*iter)->subservice = storedPacket->getSubService(); storedPacket->getApplicationData(),
result = prepareCommand(&message, (*iter)->subservice, storedPacket->getApplicationDataSize(), &iter->state,
storedPacket->getApplicationData(), iter->objectId);
storedPacket->getApplicationDataSize(), &(*iter)->state,
(*iter)->objectId);
ReturnValue_t sendResult = RETURN_OK;
switch (result) { switch (result) {
case RETURN_OK: case RETURN_OK:
if (message.getCommand() != CommandMessage::CMD_NONE) { if (command.getCommand() != CommandMessage::CMD_NONE) {
sendResult = commandQueue->sendMessage((*iter).value->first, sendResult = commandQueue->sendMessage(iter.value->first,
&message); &command);
} }
if (sendResult == RETURN_OK) { if (sendResult == RETURN_OK) {
Clock::getUptime(&(*iter)->uptimeOfStart); Clock::getUptime(&iter->uptimeOfStart);
(*iter)->step = 0; iter->step = 0;
// (*iter)->state = 0; iter->subservice = storedPacket->getSubService();
(*iter)->subservice = storedPacket->getSubService(); iter->command = command.getCommand();
(*iter)->command = message.getCommand(); iter->tcInfo.ackFlags = storedPacket->getAcknowledgeFlags();
(*iter)->tcInfo.ackFlags = storedPacket->getAcknowledgeFlags(); iter->tcInfo.tcPacketId = storedPacket->getPacketId();
(*iter)->tcInfo.tcPacketId = storedPacket->getPacketId(); iter->tcInfo.tcSequenceControl =
(*iter)->tcInfo.tcSequenceControl =
storedPacket->getPacketSequenceControl(); storedPacket->getPacketSequenceControl();
acceptPacket(TC_VERIFY::START_SUCCESS, storedPacket); acceptPacket(TC_VERIFY::START_SUCCESS, storedPacket);
} else { } else {
message.clearCommandMessage(); command.clearCommandMessage();
rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult); rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult);
checkAndExecuteFifo(iter); checkAndExecuteFifo(iter);
} }
break; break;
case EXECUTION_COMPLETE: case EXECUTION_COMPLETE:
if (message.getCommand() != CommandMessage::CMD_NONE) { if (command.getCommand() != CommandMessage::CMD_NONE) {
//Fire-and-forget command. //Fire-and-forget command.
sendResult = commandQueue->sendMessage((*iter).value->first, sendResult = commandQueue->sendMessage(iter.value->first,
&message); &command);
} }
if (sendResult == RETURN_OK) { if (sendResult == RETURN_OK) {
verificationReporter.sendSuccessReport(TC_VERIFY::START_SUCCESS, verificationReporter.sendSuccessReport(TC_VERIFY::START_SUCCESS,
@ -308,7 +339,7 @@ void CommandingServiceBase::startExecution(
acceptPacket(TC_VERIFY::COMPLETION_SUCCESS, storedPacket); acceptPacket(TC_VERIFY::COMPLETION_SUCCESS, storedPacket);
checkAndExecuteFifo(iter); checkAndExecuteFifo(iter);
} else { } else {
message.clearCommandMessage(); command.clearCommandMessage();
rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult); rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult);
checkAndExecuteFifo(iter); checkAndExecuteFifo(iter);
} }
@ -335,12 +366,10 @@ void CommandingServiceBase::acceptPacket(uint8_t reportId,
} }
void CommandingServiceBase::checkAndExecuteFifo( void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter iter) {
typename FixedMap<MessageQueueId_t,
CommandingServiceBase::CommandInfo>::Iterator *iter) {
store_address_t address; store_address_t address;
if ((*iter)->fifo.retrieve(&address) != RETURN_OK) { if (iter->fifo.retrieve(&address) != RETURN_OK) {
commandMap.erase(iter); commandMap.erase(&iter);
} else { } else {
TcPacketStored newPacket(address); TcPacketStored newPacket(address);
startExecution(&newPacket, iter); startExecution(&newPacket, iter);
@ -348,8 +377,7 @@ void CommandingServiceBase::checkAndExecuteFifo(
} }
void CommandingServiceBase::handleUnrequestedReply( void CommandingServiceBase::handleUnrequestedReply(CommandMessage* reply) {
CommandMessage* reply) {
reply->clearCommandMessage(); reply->clearCommandMessage();
} }
@ -364,18 +392,18 @@ MessageQueueId_t CommandingServiceBase::getCommandQueue() {
void CommandingServiceBase::checkTimeout() { void CommandingServiceBase::checkTimeout() {
uint32_t uptime; uint32_t uptime;
Clock::getUptime(&uptime); Clock::getUptime(&uptime);
typename FixedMap<MessageQueueId_t, CommandMapIter iter;
CommandingServiceBase::CommandInfo>::Iterator iter;
for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) {
if ((iter->uptimeOfStart + (timeout_seconds * 1000)) < uptime) { if ((iter->uptimeOfStart + (timeoutSeconds * 1000)) < uptime) {
verificationReporter.sendFailureReport( verificationReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl,
TIMEOUT); TIMEOUT);
checkAndExecuteFifo(&iter); checkAndExecuteFifo(iter);
} }
} }
} }
void CommandingServiceBase::setTaskIF(PeriodicTaskIF* task_) {
executingTask = task_;
}

View File

@ -1,35 +1,33 @@
#ifndef FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ #ifndef FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_
#define FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ #define FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_
#include <framework/container/FixedMap.h>
#include <framework/container/FIFO.h>
#include <framework/ipc/CommandMessage.h>
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/objectmanager/SystemObject.h> #include <framework/objectmanager/SystemObject.h>
#include <framework/serialize/SerializeAdapter.h>
#include <framework/storagemanager/StorageManagerIF.h> #include <framework/storagemanager/StorageManagerIF.h>
#include <framework/tasks/ExecutableObjectIF.h> #include <framework/tasks/ExecutableObjectIF.h>
#include <framework/tcdistribution/PUSDistributorIF.h> #include <framework/ipc/MessageQueueIF.h>
#include <framework/tmtcpacket/pus/TcPacketStored.h>
#include <framework/tmtcpacket/pus/TmPacketStored.h>
#include <framework/tmtcservices/AcceptsTelecommandsIF.h> #include <framework/tmtcservices/AcceptsTelecommandsIF.h>
#include <framework/tmtcservices/AcceptsTelemetryIF.h>
#include <framework/tmtcservices/TmTcMessage.h>
#include <framework/tmtcservices/VerificationReporter.h> #include <framework/tmtcservices/VerificationReporter.h>
#include <framework/internalError/InternalErrorReporterIF.h> #include <framework/ipc/CommandMessage.h>
#include <framework/ipc/QueueFactory.h> #include <framework/container/FixedMap.h>
#include <framework/timemanager/Clock.h> #include <framework/container/FIFO.h>
#include <framework/serialize/SerializeIF.h>
class TcPacketStored;
/** /**
* \brief This class is the basis for all PUS Services, which have to relay Telecommands to software bus. * @brief This class is the basis for all PUS Services, which have to
* relay Telecommands to software bus.
* *
* It manages Telecommand reception and the generation of Verification Reports like PUSServiceBase. * It manages Telecommand reception and the generation of Verification Reports
* Every class that inherits from this abstract class has to implement four adaption points: * similar to PusServiceBase. This class is used if a telecommand can't be
* handled immediately and must be relayed to the internal software bus.
* - isValidSubservice * - isValidSubservice
* - getMessageQueueAndObject * - getMessageQueueAndObject
* - prepareCommand * - prepareCommand
* - handleReply * - handleReply
* \ingroup pus_services * @author gaisser
* @ingroup pus_services
*/ */
class CommandingServiceBase: public SystemObject, class CommandingServiceBase: public SystemObject,
public AcceptsTelecommandsIF, public AcceptsTelecommandsIF,
@ -59,7 +57,7 @@ public:
*/ */
CommandingServiceBase(object_id_t setObjectId, uint16_t apid, CommandingServiceBase(object_id_t setObjectId, uint16_t apid,
uint8_t service, uint8_t numberOfParallelCommands, uint8_t service, uint8_t numberOfParallelCommands,
uint16_t commandTimeout_seconds, object_id_t setPacketSource, uint16_t commandTimeoutSeconds, object_id_t setPacketSource,
object_id_t setPacketDestination, size_t queueDepth = 20); object_id_t setPacketDestination, size_t queueDepth = 20);
virtual ~CommandingServiceBase(); virtual ~CommandingServiceBase();
@ -99,9 +97,7 @@ public:
* Used to setup the reference of the task, that executes this component * Used to setup the reference of the task, that executes this component
* @param task_ Pointer to the taskIF of this task * @param task_ Pointer to the taskIF of this task
*/ */
virtual void setTaskIF(PeriodicTaskIF* task_){ virtual void setTaskIF(PeriodicTaskIF* task_);
executingTask = task_;
};
protected: protected:
/** /**
@ -113,8 +109,9 @@ protected:
virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0;
/** /**
* Once a TC Request is valid, the existence of the destination and its target interface is checked and retrieved. * Once a TC Request is valid, the existence of the destination and its
* The target message queue ID can then be acquired by using the target interface. * target interface is checked and retrieved. The target message queue ID
* can then be acquired by using the target interface.
* @param subservice * @param subservice
* @param tcData Application Data of TC Packet * @param tcData Application Data of TC Packet
* @param tcDataLen * @param tcDataLen
@ -125,48 +122,69 @@ protected:
* - @c CSB or implementation specific return codes * - @c CSB or implementation specific return codes
*/ */
virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice,
const uint8_t *tcData, uint32_t tcDataLen, MessageQueueId_t *id, const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id,
object_id_t *objectId) = 0; object_id_t *objectId) = 0;
/** /**
* After the Message Queue and Object ID are determined, * After the Message Queue and Object ID are determined, the command is
* the command is prepared by using an implementation specific CommandMessage type * prepared by using an implementation specific CommandMessage type
* which is sent to the target object. * which is sent to the target object. It contains all necessary information
* It contains all necessary information for the device to execute telecommands. * for the device to execute telecommands.
* @param message[out] message to be sent to the object * @param message [out] message which can be set and is sent to the object
* @param subservice[in] Subservice of the current communication * @param subservice Subservice of the current communication
* @param tcData Additional data of the command * @param tcData Application data of command
* @param tcDataLen Length of the additional data * @param tcDataLen Application data length
* @param state[out] Setable state of the communication * @param state [out/in] Setable state of the communication.
* communication
* @param objectId Target object ID * @param objectId Target object ID
* @return - @c RETURN_OK on success * @return
* - @c EXECUTION_COMPLETE if exectuin is finished
* - any other return code will be part of (1,4) start failure
*/ */
virtual ReturnValue_t prepareCommand(CommandMessage *message, virtual ReturnValue_t prepareCommand(CommandMessage* message,
uint8_t subservice, const uint8_t *tcData, uint32_t tcDataLen, uint8_t subservice, const uint8_t *tcData, size_t tcDataLen,
uint32_t *state, object_id_t objectId) = 0; uint32_t *state, object_id_t objectId) = 0;
/** /**
* This function is responsible for the communication between the Command Service Base * This function is implemented by child services to specify how replies
* and the respective PUS Commanding Service once the execution has started. * to a command from another software component are handled.
* The PUS Commanding Service receives replies from the target device and forwards them by calling this function. * @param reply
* There are different translations of these replies to specify how the Command Service proceeds. * This is the reply in form of a generic read-only command message.
* @param reply Command Message which contains information about the command * @param previousCommand
* @param previousCommand Command_t of last command * Command_t of related command
* @param state state of the communication * @param state [out/in]
* @param optionalNextCommand[out] An optional next command which can be set in this function * Additional parameter which can be used to pass state information.
* State of the communication
* @param optionalNextCommand [out]
* An optional next command which can be set in this function
* @param objectId Source object ID * @param objectId Source object ID
* @param isStep Flag value to mark steps of command execution * @param isStep Flag value to mark steps of command execution
* @return - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to generate TC verification success * @return
* - @c INVALID_REPLY can handle unrequested replies * - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to
* - Anything else triggers a TC verification failure * generate TC verification success
* - @c INVALID_REPLY calls handleUnrequestedReply
* - Anything else triggers a TC verification failure. If RETURN_FAILED
* is returned and the command ID is CommandMessage::REPLY_REJECTED,
* a failure verification message with the reason as the error parameter
* and the initial command as failure parameter 1.
*/ */
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,
CommandMessage *optionalNextCommand, object_id_t objectId, CommandMessage* optionalNextCommand, object_id_t objectId,
bool *isStep) = 0; bool *isStep) = 0;
/**
* This function can be overidden to handle unrequested reply,
* when the reply sender ID is unknown or is not found is the command map.
* The default implementation will clear the command message and all
* its contents.
* @param reply
* Reply which is non-const so the default implementation can clear the
* message.
*/
virtual void handleUnrequestedReply(CommandMessage* reply);
virtual void doPeriodicOperation();
struct CommandInfo { struct CommandInfo {
struct tcInfo { struct tcInfo {
uint8_t ackFlags; uint8_t ackFlags;
@ -182,84 +200,92 @@ protected:
FIFO<store_address_t, 3> fifo; FIFO<store_address_t, 3> fifo;
}; };
using CommandMapIter = FixedMap<MessageQueueId_t,
CommandingServiceBase::CommandInfo>::Iterator;
const uint16_t apid; const uint16_t apid;
const uint8_t service; const uint8_t service;
const uint16_t timeout_seconds; const uint16_t timeoutSeconds;
uint8_t tmPacketCounter; uint8_t tmPacketCounter = 0;
StorageManagerIF *IPCStore; StorageManagerIF *IPCStore = nullptr;
StorageManagerIF *TCStore; StorageManagerIF *TCStore = nullptr;
MessageQueueIF* commandQueue; MessageQueueIF* commandQueue = nullptr;
MessageQueueIF* requestQueue; MessageQueueIF* requestQueue = nullptr;
VerificationReporter verificationReporter; VerificationReporter verificationReporter;
FixedMap<MessageQueueId_t, CommandInfo> commandMap; FixedMap<MessageQueueId_t, CommandInfo> commandMap;
uint32_t failureParameter1; //!< May be set be children to return a more precise failure condition. /* May be set be children to return a more precise failure condition. */
uint32_t failureParameter2; //!< May be set be children to return a more precise failure condition. uint32_t failureParameter1 = 0;
uint32_t failureParameter2 = 0;
object_id_t packetSource; object_id_t packetSource;
object_id_t packetDestination; object_id_t packetDestination;
/** /**
* Pointer to the task which executes this component, is invalid before setTaskIF was called. * Pointer to the task which executes this component,
* is invalid before setTaskIF was called.
*/ */
PeriodicTaskIF* executingTask; PeriodicTaskIF* executingTask = nullptr;
/** /**
* Send TM data from pointer to data. If a header is supplied it is added before data * @brief Send TM data from pointer to data.
* If a header is supplied it is added before data
* @param subservice Number of subservice * @param subservice Number of subservice
* @param data Pointer to the data in the Packet * @param data Pointer to the data in the Packet
* @param dataLen Lenght of data in the Packet * @param dataLen Lenght of data in the Packet
* @param headerData HeaderData will be placed before data * @param headerData HeaderData will be placed before data
* @param headerSize Size of HeaderData * @param headerSize Size of HeaderData
*/ */
void sendTmPacket(uint8_t subservice, const uint8_t *data, uint32_t dataLen, ReturnValue_t sendTmPacket(uint8_t subservice, const uint8_t *data,
const uint8_t* headerData = NULL, uint32_t headerSize = 0); size_t dataLen, const uint8_t* headerData = nullptr,
size_t headerSize = 0);
/** /**
* To send TM packets of objects that still need to be serialized and consist of an object ID with appended data * @brief To send TM packets of objects that still need to be serialized
* and consist of an object ID with appended data.
* @param subservice Number of subservice * @param subservice Number of subservice
* @param objectId ObjectId is placed before data * @param objectId ObjectId is placed before data
* @param data Data to append to the packet * @param data Data to append to the packet
* @param dataLen Length of Data * @param dataLen Length of Data
*/ */
void sendTmPacket(uint8_t subservice, object_id_t objectId, ReturnValue_t sendTmPacket(uint8_t subservice, object_id_t objectId,
const uint8_t *data, uint32_t dataLen); const uint8_t *data, size_t dataLen);
/** /**
* To send packets has data which is in form of a SerializeIF or Adapters implementing it * @brief To send packets which are contained inside a class implementing
* SerializeIF.
* @param subservice Number of subservice * @param subservice Number of subservice
* @param content This is a pointer to the serialized packet * @param content This is a pointer to the serialized packet
* @param header Serialize IF header which will be placed before content * @param header Serialize IF header which will be placed before content
*/ */
void sendTmPacket(uint8_t subservice, SerializeIF* content, ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content,
SerializeIF* header = NULL); SerializeIF* header = nullptr);
virtual void handleUnrequestedReply(CommandMessage *reply); void checkAndExecuteFifo(CommandMapIter iter);
virtual void doPeriodicOperation();
void checkAndExecuteFifo(
typename FixedMap<MessageQueueId_t, CommandInfo>::Iterator *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 Queue handler. * once it has been started by @sa{startExecution()} in the request
* It handles replies generated by the devices and relayed by the specific service implementation. * queue handler.
* This means that it determines further course of action depending on the return values specified * It handles replies generated by the devices and relayed by the specific
* in the service implementation. * service implementation. This means that it determines further course of
* action depending on the return values specified in the service
* implementation.
* This includes the generation of TC verification messages. Note that * This includes the generation of TC verification messages. Note that
* the static framework object ID @c VerificationReporter::messageReceiver needs to be set. * the static framework object ID @c VerificationReporter::messageReceiver
* needs to be set.
* - TM[1,5] Step Successs * - TM[1,5] Step Successs
* - TM[1,6] Step Failure * - TM[1,6] Step Failure
* - TM[1,7] Completion Success * - TM[1,7] Completion Success
@ -280,8 +306,11 @@ private:
void acceptPacket(uint8_t reportId, TcPacketStored* packet); void acceptPacket(uint8_t reportId, TcPacketStored* packet);
void startExecution(TcPacketStored *storedPacket, void startExecution(TcPacketStored *storedPacket, CommandMapIter iter);
typename FixedMap<MessageQueueId_t, CommandInfo>::Iterator *iter);
void handleCommandMessage(CommandMessage* reply);
void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter,
CommandMessage* nextCommand, CommandMessage* reply, bool& isStep);
void checkTimeout(); void checkTimeout();
}; };

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_ */