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

This commit is contained in:
Robin Müller 2020-07-28 13:08:04 +02:00
commit 35fe41361b
18 changed files with 690 additions and 432 deletions

View File

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

View File

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

View File

@ -124,6 +124,9 @@ public:
*/
void setToUnknownCommand();
void setReplyRejected(ReturnValue_t reason, Command_t initialCommand = CMD_NONE);
ReturnValue_t getReplyRejectedReason(
Command_t *initialCommand = nullptr) const;
size_t getMinimumMessageSize() const;
};

View File

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

View File

@ -1,17 +1,19 @@
#include "PeriodicTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/tasks/ExecutableObjectIF.h>
#include "PeriodicTask.h"
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(
setDeadlineMissedFunc) {
BaseType_t status = xTaskCreate(taskEntryPoint, name, setStack, this, setPriority, &handle);
setDeadlineMissedFunc)
{
BaseType_t status = xTaskCreate(taskEntryPoint, name,
setStack, this, setPriority, &handle);
if(status != pdPASS){
sif::debug << "PeriodicTask Insufficient heap memory remaining. Status: "
<< status << std::endl;
sif::debug << "PeriodicTask Insufficient heap memory remaining. "
"Status: " << status << std::endl;
}
}
@ -21,16 +23,19 @@ PeriodicTask::~PeriodicTask(void) {
}
void PeriodicTask::taskEntryPoint(void* argument) {
//The argument is re-interpreted as PeriodicTask. The Task object is global, so it is found from any place.
// The argument is re-interpreted as PeriodicTask. The Task object is
// global, so it is found from any place.
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
// Task should not start until explicitly requested
// in FreeRTOS, tasks start as soon as they are created if the scheduler is running
// but not if the scheduler is not running.
// to be able to accommodate both cases we check a member which is set in #startTask()
// if it is not set and we get here, the scheduler was started before #startTask() was called and we need to suspend
// if it is set, the scheduler was not running before #startTask() was called and we can continue
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running.
* To be able to accommodate both cases we check a member which is set in
* #startTask(). If it is not set and we get here, the scheduler was started
* before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we
* can continue */
if (!originalTask->started) {
if (not originalTask->started) {
vTaskSuspend(NULL);
}
@ -59,31 +64,73 @@ void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
/* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to explicitly.
After this assignment, xLastWakeTime is updated automatically internally within
vTaskDelayUntil(). */
count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */
for (;;) {
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
for (auto const& object: objectList) {
object->performOperation();
}
//TODO deadline missed check
checkMissedDeadline(xLastWakeTime, xPeriod);
vTaskDelayUntil(&xLastWakeTime, xPeriod);
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ReturnValue_t PeriodicTask::addComponent(object_id_t object, bool setTaskIF) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == NULL) {
if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implements ExecutableObjectIF!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
if(setTaskIF) {
newObject->setTaskIF(this);
}
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000;
}
void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand
* it. */
TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval;
// 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_
#define MULTIOBJECTTASK_H_
#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/tasks/PeriodicTaskIF.h>
#include <framework/tasks/Typedef.h>
#include <FreeRTOS.h>
#include "task.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <vector>
class ExecutableObjectIF;
/**
* @brief This class represents a specialized task for periodic activities of multiple objects.
*
* @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute
* multiple objects that implement the ExecutableObjectIF interface. The objects must be
* added prior to starting the task.
*
* @brief This class represents a specialized task for
* periodic activities of multiple objects.
* @ingroup task_handling
*/
class PeriodicTask: public PeriodicTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details The class is initialized without allocated objects. These need to be added
* with #addObject.
* In the underlying TaskBase class, a new operating system task is created.
* In addition to the TaskBase parameters, the period, the pointer to the
* aforementioned initialization function and an optional "deadline-missed"
* function pointer is passed.
* @param priority Sets the priority of a task. Values range from a low 0 to a high 99.
* @param stack_size The stack size reserved by the operating system for the task.
* @param setPeriod The length of the period with which the task's functionality will be
* executed. It is expressed in clock ticks.
* @param setDeadlineMissedFunc The function pointer to the deadline missed function
* that shall be assigned.
* Keep in Mind that you need to call before this vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h".
* TODO: why does this need to be called before vTaskStartScheduler?
* @details
* The class is initialized without allocated objects.
* These need to be added with #addComponent.
* @param priority
* Sets the priority of a task. Values depend on freeRTOS configuration,
* high number means high priority.
* @param stack_size
* The stack size reserved by the operating system for the task.
* @param setPeriod
* The length of the period with which the task's
* functionality will be executed. It is expressed in clock ticks.
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall
* be assigned.
*/
PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with the task object's
* lifetime, so the destructor is empty.
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~PeriodicTask(void);
@ -53,58 +54,72 @@ public:
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object);
ReturnValue_t addComponent(object_id_t object,
bool setTaskIF = true) override;
uint32_t getPeriodMs() const;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms);
ReturnValue_t sleepFor(uint32_t ms) override;
protected:
bool started;
TaskHandle_t handle;
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.
//! Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
/**
* @brief The period of the task.
* @details The period determines the frequency of the task's execution. It is expressed in clock ticks.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed.
* So, each may react individually on a timing failure. The pointer may be NULL,
* then nothing happens on missing the deadline. The deadline is equal to the next execution
* of the periodic task.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed so each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details It converts the argument back to the thread object type and copies the class instance
* to the task context. The taskFunctionality method is called afterwards.
* @details
* It converts the argument back to the thread object type and copies the
* class instance to the task context. The taskFunctionality method is
* called afterwards.
* @param A pointer to the task object itself is passed as argument.
*/
static void taskEntryPoint(void* argument);
/**
* @brief The function containing the actual functionality of the task.
* @details The method sets and starts
* the task's period, then enters a loop that is repeated as long as the isRunning
* attribute is true. Within the loop, all performOperation methods of the added
* objects are called. Afterwards the checkAndRestartPeriod system call blocks the task
* until the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
* @details
* The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called.
* Afterwards the checkAndRestartPeriod system call blocks the task until
* the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
void checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval);
void handleMissedDeadline();
};
#endif /* MULTIOBJECTTASK_H_ */
#endif /* PERIODICTASK_H_ */

View File

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

View File

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

View File

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

View File

@ -60,7 +60,7 @@ private:
//! In this function, the characters are parsed.
void putChars(char const* begin, char const* end);
std::string getPreamble(size_t * preambleSize = nullptr);
std::string* getPreamble(size_t * preambleSize = nullptr);
};
#endif

View File

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

View File

@ -33,7 +33,7 @@ public:
* the unbuffered mode.
* @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

View File

@ -1,9 +1,11 @@
#ifndef PERIODICTASKIF_H_
#define PERIODICTASKIF_H_
#ifndef FRAMEWORK_TASK_PERIODICTASKIF_H_
#define FRAMEWORK_TASK_PERIODICTASKIF_H_
#include <framework/objectmanager/SystemObjectIF.h>
#include <framework/timemanager/Clock.h>
#include <cstddef>
class ExecutableObjectIF;
/**
* New version of TaskIF
* Follows RAII principles, i.e. there's no create or delete method.
@ -17,11 +19,27 @@ public:
*/
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 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;

View File

@ -1,5 +1,6 @@
#include <framework/timemanager/CCSDSTime.h>
#include <stdio.h>
#include <inttypes.h>
#include <math.h>
CCSDSTime::CCSDSTime() {
@ -154,15 +155,17 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
if (length < 19) {
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;
uint8_t month;
uint16_t month;
uint16_t day;
uint8_t hour;
uint8_t minute;
uint16_t hour;
uint16_t minute;
float second;
//try Code A (yyyy-mm-dd)
int count = sscanf((char *) from, "%4hi-%2hhi-%2hiT%2hhi:%2hhi:%fZ", &year,
&month, &day, &hour, &minute, &second);
int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year,
&month, &day, &hour, &minute, &second);
if (count == 6) {
to->year = year;
to->month = month;
@ -174,9 +177,52 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
return RETURN_OK;
}
//try Code B (yyyy-ddd)
count = sscanf((char *) from, "%4hi-%3hiT%2hhi:%2hhi:%fZ", &year, &day,
// try Code B (yyyy-ddd)
count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &day,
&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) {
uint8_t tempDay;
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;
return RETURN_OK;
}
#endif
return UNSUPPORTED_TIME_FORMAT;
}

View File

@ -1,22 +1,21 @@
/*
* CommandingServiceBase.cpp
*
* Created on: 28.08.2019
* Author: gaisser
*/
#include <framework/tcdistribution/PUSDistributorIF.h>
#include <framework/tmtcservices/AcceptsTelemetryIF.h>
#include <framework/objectmanager/ObjectManagerIF.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,
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) :
SystemObject(setObjectId), apid(apid), service(service), timeout_seconds(
commandTimeout_seconds), tmPacketCounter(0), IPCStore(NULL), TCStore(
NULL), commandQueue(NULL), requestQueue(NULL), commandMap(
numberOfParallelCommands), failureParameter1(0), failureParameter2(
0), packetSource(setPacketSource), packetDestination(
setPacketDestination),executingTask(NULL) {
SystemObject(setObjectId), apid(apid), service(service),
timeoutSeconds(commandTimeoutSeconds),
commandMap(numberOfParallelCommands), packetSource(setPacketSource),
packetDestination(setPacketDestination) {
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
}
@ -57,8 +56,10 @@ ReturnValue_t CommandingServiceBase::initialize() {
objectManager->get<AcceptsTelemetryIF>(packetDestination);
PUSDistributorIF* distributor = objectManager->get<PUSDistributorIF>(
packetSource);
if ((packetForwarding == NULL) && (distributor == NULL)) {
return RETURN_FAILED;
if (packetForwarding == nullptr or distributor == nullptr) {
sif::error << "CommandingServiceBase::intialize: Packet source or "
"packet destination invalid!" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
distributor->registerService(this);
@ -68,8 +69,10 @@ ReturnValue_t CommandingServiceBase::initialize() {
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
TCStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if ((IPCStore == NULL) || (TCStore == NULL)) {
return RETURN_FAILED;
if (IPCStore == nullptr or TCStore == nullptr) {
sif::error << "CommandingServiceBase::intialize: IPC store or TC store "
"not initialized yet!" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
return RETURN_OK;
@ -77,97 +80,126 @@ ReturnValue_t CommandingServiceBase::initialize() {
}
void CommandingServiceBase::handleCommandQueue() {
CommandMessage reply, nextCommand;
ReturnValue_t result, sendResult = RETURN_OK;
bool isStep = false;
CommandMessage reply;
ReturnValue_t result = RETURN_FAILED;
for (result = commandQueue->receiveMessage(&reply); result == RETURN_OK;
result = commandQueue->receiveMessage(&reply)) {
isStep = false;
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;
}
handleCommandMessage(&reply);
}
}
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() {
TmTcMessage message;
ReturnValue_t result;
@ -181,7 +213,7 @@ void CommandingServiceBase::handleRequestQueue() {
packet.setStoreAddress(address);
if ((packet.getSubService() == 0)
|| (isValidSubservice(packet.getSubService()) != RETURN_OK)) {
or (isValidSubservice(packet.getSubService()) != RETURN_OK)) {
rejectPacket(TC_VERIFY::START_FAILURE, &packet, INVALID_SUBSERVICE);
continue;
}
@ -194,8 +226,7 @@ void CommandingServiceBase::handleRequestQueue() {
}
//Is a command already active for the target object?
typename FixedMap<MessageQueueId_t,
CommandingServiceBase::CommandInfo>::Iterator iter;
CommandMapIter iter;
iter = commandMap.find(queue);
if (iter != commandMap.end()) {
@ -210,7 +241,7 @@ void CommandingServiceBase::handleRequestQueue() {
if (result != RETURN_OK) {
rejectPacket(TC_VERIFY::START_FAILURE, &packet, BUSY);
} else {
startExecution(&packet, &iter);
startExecution(&packet, iter);
}
}
@ -218,9 +249,9 @@ void CommandingServiceBase::handleRequestQueue() {
}
void CommandingServiceBase::sendTmPacket(uint8_t subservice,
const uint8_t* data, uint32_t dataLen, const uint8_t* headerData,
uint32_t headerSize) {
ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
const uint8_t* data, size_t dataLen, const uint8_t* headerData,
size_t headerSize) {
TmPacketStored tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, data, dataLen, headerData, headerSize);
ReturnValue_t result = tmPacketStored.sendPacket(
@ -228,79 +259,79 @@ void CommandingServiceBase::sendTmPacket(uint8_t subservice,
if (result == HasReturnvaluesIF::RETURN_OK) {
this->tmPacketCounter++;
}
return result;
}
void CommandingServiceBase::sendTmPacket(uint8_t subservice,
object_id_t objectId, const uint8_t *data, uint32_t dataLen) {
uint8_t buffer[sizeof(object_id_t)];
uint8_t* pBuffer = buffer;
size_t size = 0;
SerializeAdapter::serialize(&objectId, &pBuffer, &size,
sizeof(object_id_t), SerializeIF::Endianness::BIG);
TmPacketStored tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, data, dataLen, buffer, size);
ReturnValue_t result = tmPacketStored.sendPacket(
requestQueue->getDefaultDestination(), requestQueue->getId());
if (result == HasReturnvaluesIF::RETURN_OK) {
this->tmPacketCounter++;
}
ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
object_id_t objectId, const uint8_t *data, size_t dataLen) {
uint8_t buffer[sizeof(object_id_t)];
uint8_t* pBuffer = buffer;
size_t size = 0;
SerializeAdapter::serialize(&objectId, &pBuffer, &size,
sizeof(object_id_t), SerializeIF::Endianness::BIG);
TmPacketStored tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, data, dataLen, buffer, size);
ReturnValue_t result = tmPacketStored.sendPacket(
requestQueue->getDefaultDestination(), requestQueue->getId());
if (result == HasReturnvaluesIF::RETURN_OK) {
this->tmPacketCounter++;
}
return result;
}
void CommandingServiceBase::sendTmPacket(uint8_t subservice,
SerializeIF* content, SerializeIF* header) {
TmPacketStored tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, content, header);
ReturnValue_t result = tmPacketStored.sendPacket(
requestQueue->getDefaultDestination(), requestQueue->getId());
if (result == HasReturnvaluesIF::RETURN_OK) {
this->tmPacketCounter++;
}
ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
SerializeIF* content, SerializeIF* header) {
TmPacketStored tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, content, header);
ReturnValue_t result = tmPacketStored.sendPacket(
requestQueue->getDefaultDestination(), requestQueue->getId());
if (result == HasReturnvaluesIF::RETURN_OK) {
this->tmPacketCounter++;
}
return result;
}
void CommandingServiceBase::startExecution(
TcPacketStored *storedPacket,
typename FixedMap<MessageQueueId_t,
CommandingServiceBase::CommandInfo>::Iterator *iter) {
ReturnValue_t result, sendResult = RETURN_OK;
CommandMessage message;
(*iter)->subservice = storedPacket->getSubService();
result = prepareCommand(&message, (*iter)->subservice,
storedPacket->getApplicationData(),
storedPacket->getApplicationDataSize(), &(*iter)->state,
(*iter)->objectId);
void CommandingServiceBase::startExecution(TcPacketStored *storedPacket,
CommandMapIter iter) {
ReturnValue_t result = RETURN_OK;
CommandMessage command;
iter->subservice = storedPacket->getSubService();
result = prepareCommand(&command, iter->subservice,
storedPacket->getApplicationData(),
storedPacket->getApplicationDataSize(), &iter->state,
iter->objectId);
ReturnValue_t sendResult = RETURN_OK;
switch (result) {
case RETURN_OK:
if (message.getCommand() != CommandMessage::CMD_NONE) {
sendResult = commandQueue->sendMessage((*iter).value->first,
&message);
if (command.getCommand() != CommandMessage::CMD_NONE) {
sendResult = commandQueue->sendMessage(iter.value->first,
&command);
}
if (sendResult == RETURN_OK) {
Clock::getUptime(&(*iter)->uptimeOfStart);
(*iter)->step = 0;
// (*iter)->state = 0;
(*iter)->subservice = storedPacket->getSubService();
(*iter)->command = message.getCommand();
(*iter)->tcInfo.ackFlags = storedPacket->getAcknowledgeFlags();
(*iter)->tcInfo.tcPacketId = storedPacket->getPacketId();
(*iter)->tcInfo.tcSequenceControl =
Clock::getUptime(&iter->uptimeOfStart);
iter->step = 0;
iter->subservice = storedPacket->getSubService();
iter->command = command.getCommand();
iter->tcInfo.ackFlags = storedPacket->getAcknowledgeFlags();
iter->tcInfo.tcPacketId = storedPacket->getPacketId();
iter->tcInfo.tcSequenceControl =
storedPacket->getPacketSequenceControl();
acceptPacket(TC_VERIFY::START_SUCCESS, storedPacket);
} else {
message.clearCommandMessage();
command.clearCommandMessage();
rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult);
checkAndExecuteFifo(iter);
}
break;
case EXECUTION_COMPLETE:
if (message.getCommand() != CommandMessage::CMD_NONE) {
if (command.getCommand() != CommandMessage::CMD_NONE) {
//Fire-and-forget command.
sendResult = commandQueue->sendMessage((*iter).value->first,
&message);
sendResult = commandQueue->sendMessage(iter.value->first,
&command);
}
if (sendResult == RETURN_OK) {
verificationReporter.sendSuccessReport(TC_VERIFY::START_SUCCESS,
@ -308,7 +339,7 @@ void CommandingServiceBase::startExecution(
acceptPacket(TC_VERIFY::COMPLETION_SUCCESS, storedPacket);
checkAndExecuteFifo(iter);
} else {
message.clearCommandMessage();
command.clearCommandMessage();
rejectPacket(TC_VERIFY::START_FAILURE, storedPacket, sendResult);
checkAndExecuteFifo(iter);
}
@ -335,12 +366,10 @@ void CommandingServiceBase::acceptPacket(uint8_t reportId,
}
void CommandingServiceBase::checkAndExecuteFifo(
typename FixedMap<MessageQueueId_t,
CommandingServiceBase::CommandInfo>::Iterator *iter) {
void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter iter) {
store_address_t address;
if ((*iter)->fifo.retrieve(&address) != RETURN_OK) {
commandMap.erase(iter);
if (iter->fifo.retrieve(&address) != RETURN_OK) {
commandMap.erase(&iter);
} else {
TcPacketStored newPacket(address);
startExecution(&newPacket, iter);
@ -348,8 +377,7 @@ void CommandingServiceBase::checkAndExecuteFifo(
}
void CommandingServiceBase::handleUnrequestedReply(
CommandMessage* reply) {
void CommandingServiceBase::handleUnrequestedReply(CommandMessage* reply) {
reply->clearCommandMessage();
}
@ -364,18 +392,18 @@ MessageQueueId_t CommandingServiceBase::getCommandQueue() {
void CommandingServiceBase::checkTimeout() {
uint32_t uptime;
Clock::getUptime(&uptime);
typename FixedMap<MessageQueueId_t,
CommandingServiceBase::CommandInfo>::Iterator iter;
CommandMapIter iter;
for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) {
if ((iter->uptimeOfStart + (timeout_seconds * 1000)) < uptime) {
if ((iter->uptimeOfStart + (timeoutSeconds * 1000)) < uptime) {
verificationReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl,
TIMEOUT);
checkAndExecuteFifo(&iter);
checkAndExecuteFifo(iter);
}
}
}
void CommandingServiceBase::setTaskIF(PeriodicTaskIF* task_) {
executingTask = task_;
}

View File

@ -1,35 +1,33 @@
#ifndef 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/serialize/SerializeAdapter.h>
#include <framework/storagemanager/StorageManagerIF.h>
#include <framework/tasks/ExecutableObjectIF.h>
#include <framework/tcdistribution/PUSDistributorIF.h>
#include <framework/tmtcpacket/pus/TcPacketStored.h>
#include <framework/tmtcpacket/pus/TmPacketStored.h>
#include <framework/ipc/MessageQueueIF.h>
#include <framework/tmtcservices/AcceptsTelecommandsIF.h>
#include <framework/tmtcservices/AcceptsTelemetryIF.h>
#include <framework/tmtcservices/TmTcMessage.h>
#include <framework/tmtcservices/VerificationReporter.h>
#include <framework/internalError/InternalErrorReporterIF.h>
#include <framework/ipc/QueueFactory.h>
#include <framework/timemanager/Clock.h>
#include <framework/ipc/CommandMessage.h>
#include <framework/container/FixedMap.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.
* Every class that inherits from this abstract class has to implement four adaption points:
* It manages Telecommand reception and the generation of Verification Reports
* 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
* - getMessageQueueAndObject
* - prepareCommand
* - handleReply
* \ingroup pus_services
* @author gaisser
* @ingroup pus_services
*/
class CommandingServiceBase: public SystemObject,
public AcceptsTelecommandsIF,
@ -59,7 +57,7 @@ public:
*/
CommandingServiceBase(object_id_t setObjectId, 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 = 20);
virtual ~CommandingServiceBase();
@ -99,9 +97,7 @@ public:
* Used to setup the reference of the task, that executes this component
* @param task_ Pointer to the taskIF of this task
*/
virtual void setTaskIF(PeriodicTaskIF* task_){
executingTask = task_;
};
virtual void setTaskIF(PeriodicTaskIF* task_);
protected:
/**
@ -113,8 +109,9 @@ protected:
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.
* The target message queue ID can then be acquired by using the target interface.
* Once a TC Request is valid, the existence of the destination and its
* target interface is checked and retrieved. The target message queue ID
* can then be acquired by using the target interface.
* @param subservice
* @param tcData Application Data of TC Packet
* @param tcDataLen
@ -125,48 +122,69 @@ protected:
* - @c CSB or implementation specific return codes
*/
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;
/**
* After the Message Queue and Object ID are determined,
* the command is prepared by using an implementation specific CommandMessage type
* which is sent to the target object.
* It contains all necessary information for the device to execute telecommands.
* @param message[out] message to be sent to the object
* @param subservice[in] Subservice of the current communication
* @param tcData Additional data of the command
* @param tcDataLen Length of the additional data
* @param state[out] Setable state of the communication
* After the Message Queue and Object ID are determined, the command is
* prepared by using an implementation specific CommandMessage type
* which is sent to the target object. It contains all necessary information
* for the device to execute telecommands.
* @param message [out] message which can be set and is sent to the object
* @param subservice Subservice of the current communication
* @param tcData Application data of command
* @param tcDataLen Application data length
* @param state [out/in] Setable state of the communication.
* communication
* @param objectId Target object ID
* @return - @c RETURN_OK on success
* - @c EXECUTION_COMPLETE if exectuin is finished
* - any other return code will be part of (1,4) start failure
* @return
*/
virtual ReturnValue_t prepareCommand(CommandMessage *message,
uint8_t subservice, const uint8_t *tcData, uint32_t tcDataLen,
virtual ReturnValue_t prepareCommand(CommandMessage* message,
uint8_t subservice, const uint8_t *tcData, size_t tcDataLen,
uint32_t *state, object_id_t objectId) = 0;
/**
* This function is responsible for the communication between the Command Service Base
* and the respective PUS Commanding Service once the execution has started.
* The PUS Commanding Service receives replies from the target device and forwards them by calling this function.
* There are different translations of these replies to specify how the Command Service proceeds.
* @param reply Command Message which contains information about the command
* @param previousCommand Command_t of last command
* @param state state of the communication
* @param optionalNextCommand[out] An optional next command which can be set in this function
* This function is implemented by child services to specify how replies
* to a command from another software component are handled.
* @param reply
* This is the reply in form of a generic read-