Merge remote-tracking branch 'upstream/master' into mueller/feature/DHBupdate

This commit is contained in:
Robin Müller 2020-08-02 15:49:11 +02:00
commit f36da8a79c
20 changed files with 917 additions and 527 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,48 +1,49 @@
#ifndef MULTIOBJECTTASK_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_
#define MULTIOBJECTTASK_H_ #define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_
#include <framework/objectmanager/ObjectManagerIF.h> #include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/tasks/PeriodicTaskIF.h> #include <framework/tasks/PeriodicTaskIF.h>
#include <framework/tasks/Typedef.h> #include <framework/tasks/Typedef.h>
#include <FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include "task.h" #include <freertos/task.h>
#include <vector> #include <vector>
class ExecutableObjectIF; class ExecutableObjectIF;
/** /**
* @brief This class represents a specialized task for periodic activities of multiple objects. * @brief This class represents a specialized task for
* * periodic activities of multiple objects.
* @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute
* multiple objects that implement the ExecutableObjectIF interface. The objects must be
* added prior to starting the task.
*
* @ingroup task_handling * @ingroup task_handling
*/ */
class PeriodicTask: public PeriodicTaskIF { class PeriodicTask: public PeriodicTaskIF {
public: public:
/** /**
* @brief Standard constructor of the class. * Keep in Mind that you need to call before this vTaskStartScheduler()!
* @details The class is initialized without allocated objects. These need to be added * A lot of task parameters are set in "FreeRTOSConfig.h".
* with #addObject. * TODO: why does this need to be called before vTaskStartScheduler?
* In the underlying TaskBase class, a new operating system task is created. * @details
* In addition to the TaskBase parameters, the period, the pointer to the * The class is initialized without allocated objects.
* aforementioned initialization function and an optional "deadline-missed" * These need to be added with #addComponent.
* function pointer is passed. * @param priority
* @param priority Sets the priority of a task. Values range from a low 0 to a high 99. * Sets the priority of a task. Values depend on freeRTOS configuration,
* @param stack_size The stack size reserved by the operating system for the task. * high number means high priority.
* @param setPeriod The length of the period with which the task's functionality will be * @param stack_size
* executed. It is expressed in clock ticks. * The stack size reserved by the operating system for the task.
* @param setDeadlineMissedFunc The function pointer to the deadline missed function * @param setPeriod
* that shall be assigned. * The length of the period with which the task's
* functionality will be executed. It is expressed in clock ticks.
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall
* be assigned.
*/ */
PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, TaskPeriod setPeriod, PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()); 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
* the next period.
* On missing the deadline, the deadlineMissedFunction is executed. * On missing the deadline, the deadlineMissedFunction is executed.
*/ */
void taskFunctionality(void); void taskFunctionality(void);
void checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval);
void handleMissedDeadline();
}; };
#endif /* MULTIOBJECTTASK_H_ */ #endif /* PERIODICTASK_H_ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
#include <framework/timemanager/CCSDSTime.h> #include <framework/timemanager/CCSDSTime.h>
#include <stdio.h> #include <stdio.h>
#include <inttypes.h>
#include <math.h> #include <math.h>
CCSDSTime::CCSDSTime() { CCSDSTime::CCSDSTime() {
@ -154,14 +155,16 @@ 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;
@ -175,8 +178,51 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
} }
// 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,73 +80,53 @@ 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;
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); nextCommand.setCommand(CommandMessage::CMD_NONE);
result = handleReply(&reply, iter->command, &iter->state, &nextCommand,
iter->objectId, &isStep);
// 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) { switch (result) {
case EXECUTION_COMPLETE: case EXECUTION_COMPLETE:
case RETURN_OK: case RETURN_OK:
case NO_STEP_MESSAGE: case NO_STEP_MESSAGE:
iter->command = nextCommand.getCommand(); // handle result of reply handler implemented by developer.
if (nextCommand.getCommand() != CommandMessage::CMD_NONE) { handleReplyHandlerResult(result, iter, &nextCommand, reply, isStep);
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; break;
case INVALID_REPLY: case INVALID_REPLY:
//might be just an unrequested reply at a bad moment //might be just an unrequested reply at a bad moment
handleUnrequestedReply(&reply); handleUnrequestedReply(reply);
break; break;
default: default:
if (isStep) { if (isStep) {
@ -160,13 +143,62 @@ void CommandingServiceBase::handleCommandQueue() {
} }
failureParameter1 = 0; failureParameter1 = 0;
failureParameter2 = 0; failureParameter2 = 0;
checkAndExecuteFifo(&iter); checkAndExecuteFifo(iter);
break; 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;
@ -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,11 +259,12 @@ 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;
@ -245,11 +277,11 @@ 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,
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);
@ -258,49 +290,48 @@ void CommandingServiceBase::sendTmPacket(uint8_t subservice,
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();
result = prepareCommand(&message, (*iter)->subservice,
storedPacket->getApplicationData(), storedPacket->getApplicationData(),
storedPacket->getApplicationDataSize(), &(*iter)->state, storedPacket->getApplicationDataSize(), &iter->state,
(*iter)->objectId); 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 COMMANDINGSERVICEBASE_H_ #ifndef FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_
#define 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::hex << this->requestQueue.getId()
// << std::dec << " returned: " << status << std::endl; // << 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_ */