Update to new FSFW release. Minor changes to include path

This commit is contained in:
petriVM18 2021-03-09 10:24:28 +01:00
commit f094558f11
171 changed files with 7367 additions and 1306 deletions

0
.gitmodules vendored Normal file
View File

12
FSFWVersion.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef FSFW_DEFAULTCFG_VERSION_H_
#define FSFW_DEFAULTCFG_VERSION_H_
const char* const FSFW_VERSION_NAME = "ASTP";
#define FSFW_VERSION 0
#define FSFW_SUBVERSION 0
#define FSFW_REVISION 1
#endif /* FSFW_DEFAULTCFG_VERSION_H_ */

2
NOTICE
View File

@ -4,6 +4,8 @@ The initial version of the Flight Software Framework was developed during
the Flying Laptop Project by the Universität Stuttgart in coorporation the Flying Laptop Project by the Universität Stuttgart in coorporation
with Airbus Defence and Space GmbH. with Airbus Defence and Space GmbH.
The supreme FSFW Logo was designed by Markus Koller and Luise Trilsbach.
Copyrights in the Flight Software Framework are retained by their contributors. Copyrights in the Flight Software Framework are retained by their contributors.
No copyright assignment is required to contribute to the Flight Software Framework. No copyright assignment is required to contribute to the Flight Software Framework.

159
README.md Normal file
View File

@ -0,0 +1,159 @@
![FSFW Logo](logo/FSFW_Logo_V3_bw.png)
# Flight Software Framework (FSFW)
The Flight Software Framework is a C++ Object Oriented Framework for unmanned,
automated systems like Satellites.
The initial version of the Flight Software Framework was developed during
the Flying Laptop Project by the University of Stuttgart in cooperation
with Airbus Defence and Space GmbH.
## Intended Use
The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability.
Therefore, a mode and health system provides control over the states of the software and the controlled devices.
In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
The recommended hardware is a microprocessor with more than 2 MB of RAM and 1 MB of non-volatile Memory.
For reference, current Applications use a Cobham Gaisler UT699 (LEON3FT), a ISISPACE IOBC or a Zynq-7020 SoC.
## Structure
The general structure is driven by the usage of interfaces provided by objects. The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be widely available, even with older compilers.
The FSFW uses dynamic allocation during the initialization but provides static containers during runtime.
This simplifies the instantiation of objects and allows the usage of some standard containers.
Dynamic Allocation after initialization is discouraged and different solutions are provided in the FSFW to achieve that.
The fsfw uses Run-time type information.
Exceptions are not allowed.
### Failure Handling
Functions should return a defined ReturnValue_t to signal to the caller that something is gone wrong.
Returnvalues must be unique. For this the function HasReturnvaluesIF::makeReturnCode or the Macro MAKE_RETURN can be used.
The CLASS_ID is a unique id for that type of object. See returnvalues/FwClassIds.
### OSAL
The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. A independent OSAL called "host" is currently not finished. This aims to be running on windows as well.
The OSAL provides periodic tasks, message queues, clocks and Semaphores as well as Mutexes.
### Core Components
Clock:
* This is a class of static functions that can be used at anytime
* Leap Seconds must be set if any time conversions from UTC to other times is used
ObjectManager (must be created):
* The component which handles all references. All SystemObjects register at this component.
* Any SystemObject needs to have a unique ObjectId. Those can be managed like objects::framework_objects.
* A reference to an object can be get by calling the following function. T must be the specific Interface you want to call.
A nullptr check of the returning Pointer must be done. This function is based on Run-time type information.
``` c++
template <typename T> T* ObjectManagerIF::get( object_id_t id )
```
* A typical way to create all objects on startup is a handing a static produce function to the ObjectManager on creation.
By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards.
Event Manager:
* Component which allows routing of events
* Other objects can subscribe to specific events, ranges of events or all events of an object.
* Subscriptions can be done during runtime but should be done during initialization
* Amounts of allowed subscriptions must be configured by setting this parameters:
``` c++
namespace fsfwconfig {
//! Configure the allocated pool sizes for the event manager.
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
}
```
Health Table:
* A component which holds every health state
* Provides a thread safe way to access all health states without the need of message exchanges
Stores
* The message based communication can only exchange a few bytes of information inside the message itself. Therefore, additional information can be exchanged with Stores. With this, only the store address must be exchanged in the message.
* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC Store is used. For outgoing TM a TM store is used.
* All of them should use the Thread Safe Class storagemanager/PoolManager
Tasks
There are two different types of tasks:
* The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the insertion to the Tasks.
* FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for DeviceHandlers, where polling should be in a defined order. An example can be found in defaultcfg/fsfwconfig/pollingSequence
### Static Ids in the framework
Some parts of the framework use a static routing address for communication.
An example setup of ids can be found in the example config in "defaultcft/fsfwconfig/objects/Factory::setStaticFrameworkObjectIds()".
### Events
Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT. This works analog to the returnvalues.
Every object that needs own EventIds has to get a unique SUBSYSTEM_ID.
Every SystemObject can call triggerEvent from the parent class.
Therefore, event messages contain the specific EventId and the objectId of the object that has triggered.
### Internal Communication
Components communicate mostly over Message through Queues.
Those queues are created by calling the singleton QueueFactory::instance()->create().
### External Communication
The external communication with the mission control system is mostly up to the user implementation.
The FSFW provides PUS Services which can be used to but don't need to be used.
The services can be seen as a conversion from a TC to a message based communication and back.
#### CCSDS Frames, CCSDS Space Packets and PUS
If the communication is based on CCSDS Frames and Space Packets, several classes can be used to distributed the packets to the corresponding services. Those can be found in tcdistribution.
If Space Packets are used, a timestamper must be created.
An example can be found in the timemanager folder, this uses CCSDSTime::CDS_short.
#### DeviceHandling
DeviceHandlers are a core component of the FSFW.
The idea is, to have a software counterpart of every physical device to provide a simple mode, health and commanding interface.
By separating the underlying Communication Interface with DeviceCommunicationIF, a DH can be tested on different hardware.
The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction.
A standard FDIR component for the DH will be created automatically but can be overwritten by the user.
#### Modes, Health
The two interfaces HasModesIF and HasHealthIF provide access for commanding and monitoring of components.
On-board Mode Management is implement in hierarchy system.
DeviceHandlers and Controllers are the lowest part of the hierarchy.
The next layer are Assemblies. Those assemblies act as a component which handle redundancies of handlers.
Assemblies share a common core with the next level which are the Subsystems.
Those Assemblies are intended to act as auto-generated components from a database which describes the subsystem modes.
The definitions contain transition and target tables which contain the DH, Assembly and Controller Modes to be commanded.
Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a switch into any higher AOCS mode might first turn on the sensors, than the actuators and the controller as last component.
The target table is used to describe the state that is checked continuously by the subsystem.
All of this allows System Modes to be generated as Subsystem object as well from the same database.
This System contains list of subsystem modes in the transition and target tables.
Therefore, it allows a modular system to create system modes and easy commanding of those, because only the highest components must be commanded.
The health state represents if the component is able to perform its tasks.
This can be used to signal the system to avoid using this component instead of a redundant one.
The on-board FDIR uses the health state for isolation and recovery.
## Example config
A example config can be found in defaultcfg/fsfwconfig.
## Unit Tests
Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include catch2 itself.
See README.md in the unittest Folder.

View File

@ -1,10 +1,12 @@
#include "ActionHelper.h" #include "ActionHelper.h"
#include "HasActionsIF.h" #include "HasActionsIF.h"
#include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueSenderIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : ActionHelper::ActionHelper(HasActionsIF* setOwner,
owner(setOwner), queueToUse(useThisQueue), ipcStore(nullptr) { MessageQueueIF* useThisQueue) :
owner(setOwner), queueToUse(useThisQueue) {
} }
ActionHelper::~ActionHelper() { ActionHelper::~ActionHelper() {
@ -33,13 +35,15 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) { void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo,
ActionId_t commandId, ReturnValue_t result) {
CommandMessage reply; CommandMessage reply;
ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result); ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result);
queueToUse->sendMessage(reportTo, &reply); queueToUse->sendMessage(reportTo, &reply);
} }
void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) { void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId,
ReturnValue_t result) {
CommandMessage reply; CommandMessage reply;
ActionMessage::setCompletionReply(&reply, commandId, result); ActionMessage::setCompletionReply(&reply, commandId, result);
queueToUse->sendMessage(reportTo, &reply); queueToUse->sendMessage(reportTo, &reply);
@ -49,8 +53,8 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) {
queueToUse = queue; queueToUse = queue;
} }
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, void ActionHelper::prepareExecution(MessageQueueId_t commandedBy,
store_address_t dataAddress) { ActionId_t actionId, store_address_t dataAddress) {
const uint8_t* dataPtr = NULL; const uint8_t* dataPtr = NULL;
size_t size = 0; size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
@ -62,6 +66,11 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t act
} }
result = owner->executeAction(actionId, commandedBy, dataPtr, size); result = owner->executeAction(actionId, commandedBy, dataPtr, size);
ipcStore->deleteData(dataAddress); ipcStore->deleteData(dataAddress);
if(result == HasActionsIF::EXECUTION_FINISHED) {
CommandMessage reply;
ActionMessage::setCompletionReply(&reply, actionId, result);
queueToUse->sendMessage(commandedBy, &reply);
}
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
CommandMessage reply; CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result); ActionMessage::setStepReply(&reply, actionId, 0, result);
@ -86,21 +95,27 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
result = data->serialize(&dataPtr, &size, maxSize, SerializeIF::Endianness::BIG); result = data->serialize(&dataPtr, &size, maxSize,
SerializeIF::Endianness::BIG);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeAddress); ipcStore->deleteData(storeAddress);
return result; return result;
} }
//We don't need to report the objectId, as we receive REQUESTED data before the completion success message. // We don't need to report the objectId, as we receive REQUESTED data
//True aperiodic replies need to be reported with another dedicated message. // before the completion success message.
// True aperiodic replies need to be reported with
// another dedicated message.
ActionMessage::setDataReply(&reply, replyId, storeAddress); ActionMessage::setDataReply(&reply, replyId, storeAddress);
//TODO Service Implementation sucks at the moment // If the sender needs to be hidden, for example to handle packet
// as unrequested reply, this will be done here.
if (hideSender) { if (hideSender) {
result = MessageQueueSenderIF::sendMessage(reportTo, &reply); result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
} else { }
else {
result = queueToUse->sendMessage(reportTo, &reply); result = queueToUse->sendMessage(reportTo, &reply);
} }
if (result != HasReturnvaluesIF::RETURN_OK){ if (result != HasReturnvaluesIF::RETURN_OK){
ipcStore->deleteData(storeAddress); ipcStore->deleteData(storeAddress);
} }
@ -109,3 +124,39 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
void ActionHelper::resetHelper() { void ActionHelper::resetHelper() {
} }
ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
ActionId_t replyId, const uint8_t *data, size_t dataSize,
bool hideSender) {
CommandMessage reply;
store_address_t storeAddress;
ReturnValue_t result = ipcStore->addData(&storeAddress, data, dataSize);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeAddress);
return result;
}
// We don't need to report the objectId, as we receive REQUESTED data
// before the completion success message.
// True aperiodic replies need to be reported with
// another dedicated message.
ActionMessage::setDataReply(&reply, replyId, storeAddress);
// If the sender needs to be hidden, for example to handle packet
// as unrequested reply, this will be done here.
if (hideSender) {
result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
}
else {
result = queueToUse->sendMessage(reportTo, &reply);
}
if (result != HasReturnvaluesIF::RETURN_OK){
ipcStore->deleteData(storeAddress);
}
return result;
}

View File

@ -1,15 +1,18 @@
#ifndef ACTIONHELPER_H_ #ifndef FSFW_ACTION_ACTIONHELPER_H_
#define ACTIONHELPER_H_ #define FSFW_ACTION_ACTIONHELPER_H_
#include "ActionMessage.h" #include "ActionMessage.h"
#include "../serialize/SerializeIF.h" #include "../serialize/SerializeIF.h"
#include "../ipc/MessageQueueIF.h" #include "../ipc/MessageQueueIF.h"
/** /**
* \brief Action Helper is a helper class which handles action messages * @brief Action Helper is a helper class which handles action messages
* *
* Components which use the HasActionIF this helper can be used to handle the action messages. * Components which use the HasActionIF this helper can be used to handle
* It does handle step messages as well as other answers to action calls. It uses the executeAction function * the action messages.
* of its owner as callback. The call of the initialize function is mandatory and it needs a valid messageQueueIF pointer! * It does handle step messages as well as other answers to action calls.
* It uses the executeAction function of its owner as callback.
* The call of the initialize function is mandatory and needs a
* valid MessageQueueIF pointer!
*/ */
class HasActionsIF; class HasActionsIF;
@ -18,7 +21,8 @@ public:
/** /**
* Constructor of the action helper * Constructor of the action helper
* @param setOwner Pointer to the owner of the interface * @param setOwner Pointer to the owner of the interface
* @param useThisQueue messageQueue to be used, can be set during initialize function as well. * @param useThisQueue messageQueue to be used, can be set during
* initialize function as well.
*/ */
ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
@ -26,28 +30,36 @@ public:
/** /**
* Function to be called from the owner with a new command message * Function to be called from the owner with a new command message
* *
* If the message is a valid action message the helper will use the executeAction function from HasActionsIF. * If the message is a valid action message the helper will use the
* If the message is invalid or the callback fails a message reply will be send to the sender of the message automatically. * executeAction function from HasActionsIF.
* If the message is invalid or the callback fails a message reply will be
* send to the sender of the message automatically.
* *
* @param command Pointer to a command message received by the owner * @param command Pointer to a command message received by the owner
* @return HasReturnvaluesIF::RETURN_OK if the message is a action message, CommandMessage::UNKNOW_COMMAND if this message ID is unkown * @return HasReturnvaluesIF::RETURN_OK if the message is a action message,
* CommandMessage::UNKNOW_COMMAND if this message ID is unkown
*/ */
ReturnValue_t handleActionMessage(CommandMessage* command); ReturnValue_t handleActionMessage(CommandMessage* command);
/** /**
* Helper initialize function. Must be called before use of any other helper function * Helper initialize function. Must be called before use of any other
* @param queueToUse_ Pointer to the messageQueue to be used, optional if queue was set in constructor * helper function
* @param queueToUse_ Pointer to the messageQueue to be used, optional
* if queue was set in constructor
* @return Returns RETURN_OK if successful * @return Returns RETURN_OK if successful
*/ */
ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr); ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr);
/** /**
* Function to be called from the owner to send a step message. Success or failure will be determined by the result value. * Function to be called from the owner to send a step message.
* Success or failure will be determined by the result value.
* *
* @param step Number of steps already done * @param step Number of steps already done
* @param reportTo The messageQueueId to report the step message to * @param reportTo The messageQueueId to report the step message to
* @param commandId ID of the executed command * @param commandId ID of the executed command
* @param result Result of the execution * @param result Result of the execution
*/ */
void step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); void step(uint8_t step, MessageQueueId_t reportTo,
ActionId_t commandId,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
/** /**
* Function to be called by the owner to send a action completion message * Function to be called by the owner to send a action completion message
* *
@ -55,39 +67,59 @@ public:
* @param commandId ID of the executed command * @param commandId ID of the executed command
* @param result Result of the execution * @param result Result of the execution
*/ */
void finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); void finish(MessageQueueId_t reportTo, ActionId_t commandId,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
/** /**
* Function to be called by the owner if an action does report data * Function to be called by the owner if an action does report data.
* * Takes a SerializeIF* pointer and serializes it into the IPC store.
* @param reportTo MessageQueueId_t to report the action completion message to * @param reportTo MessageQueueId_t to report the action completion
* message to
* @param replyId ID of the executed command * @param replyId ID of the executed command
* @param data Pointer to the data * @param data Pointer to the data
* @return Returns RETURN_OK if successful, otherwise failure code * @return Returns RETURN_OK if successful, otherwise failure code
*/ */
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data, bool hideSender = false); ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId,
SerializeIF* data, bool hideSender = false);
/** /**
* Function to setup the MessageQueueIF* of the helper. Can be used to set the messageQueueIF* if * Function to be called by the owner if an action does report data.
* message queue is unavailable at construction and initialize but must be setup before first call of other functions. * Takes the raw data and writes it into the IPC store.
* @param reportTo MessageQueueId_t to report the action completion
* message to
* @param replyId ID of the executed command
* @param data Pointer to the data
* @return Returns RETURN_OK if successful, otherwise failure code
*/
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId,
const uint8_t* data, size_t dataSize, bool hideSender = false);
/**
* Function to setup the MessageQueueIF* of the helper. Can be used to
* set the MessageQueueIF* if message queue is unavailable at construction
* and initialize but must be setup before first call of other functions.
* @param queue Queue to be used by the helper * @param queue Queue to be used by the helper
*/ */
void setQueueToUse(MessageQueueIF *queue); void setQueueToUse(MessageQueueIF *queue);
protected: protected:
static const uint8_t STEP_OFFSET = 1;//!< Increase of value of this per step //!< Increase of value of this per step
static const uint8_t STEP_OFFSET = 1;
HasActionsIF* owner;//!< Pointer to the owner HasActionsIF* owner;//!< Pointer to the owner
MessageQueueIF* queueToUse;//!< Queue to be used as response sender, has to be set with //! Queue to be used as response sender, has to be set in ctor or with
StorageManagerIF* ipcStore;//!< Pointer to an IPC Store, initialized during construction or initialize(MessageQueueIF* queueToUse_) or with setQueueToUse(MessageQueueIF *queue) //! setQueueToUse
MessageQueueIF* queueToUse;
//! Pointer to an IPC Store, initialized during construction or
StorageManagerIF* ipcStore = nullptr;
/** /**
*Internal function called by handleActionMessage(CommandMessage* command) * Internal function called by handleActionMessage
*
* @param commandedBy MessageQueueID of Commander * @param commandedBy MessageQueueID of Commander
* @param actionId ID of action to be done * @param actionId ID of action to be done
* @param dataAddress Address of additional data in IPC Store * @param dataAddress Address of additional data in IPC Store
*/ */
virtual void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress); virtual void prepareExecution(MessageQueueId_t commandedBy,
ActionId_t actionId, store_address_t dataAddress);
/** /**
* * @brief Default implementation is empty.
*/ */
virtual void resetHelper(); virtual void resetHelper();
}; };
#endif /* ACTIONHELPER_H_ */ #endif /* FSFW_ACTION_ACTIONHELPER_H_ */

View File

@ -1,5 +1,5 @@
#ifndef ACTIONMESSAGE_H_ #ifndef FSFW_ACTION_ACTIONMESSAGE_H_
#define ACTIONMESSAGE_H_ #define FSFW_ACTION_ACTIONMESSAGE_H_
#include "../ipc/CommandMessage.h" #include "../ipc/CommandMessage.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
@ -18,15 +18,19 @@ public:
static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5); static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5);
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6); static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
virtual ~ActionMessage(); virtual ~ActionMessage();
static void setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters); static void setCommand(CommandMessage* message, ActionId_t fid,
store_address_t parameters);
static ActionId_t getActionId(const CommandMessage* message ); static ActionId_t getActionId(const CommandMessage* message );
static store_address_t getStoreId(const CommandMessage* message ); static store_address_t getStoreId(const CommandMessage* message );
static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); static void setStepReply(CommandMessage* message, ActionId_t fid,
uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static uint8_t getStep(const CommandMessage* message ); static uint8_t getStep(const CommandMessage* message );
static ReturnValue_t getReturnCode(const CommandMessage* message ); static ReturnValue_t getReturnCode(const CommandMessage* message );
static void setDataReply(CommandMessage* message, ActionId_t actionId, store_address_t data); static void setDataReply(CommandMessage* message, ActionId_t actionId,
static void setCompletionReply(CommandMessage* message, ActionId_t fid, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); store_address_t data);
static void setCompletionReply(CommandMessage* message, ActionId_t fid,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void clear(CommandMessage* message); static void clear(CommandMessage* message);
}; };
#endif /* ACTIONMESSAGE_H_ */ #endif /* FSFW_ACTION_ACTIONMESSAGE_H_ */

View File

@ -1,5 +1,5 @@
#ifndef COMMANDSACTIONSIF_H_ #ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_
#define COMMANDSACTIONSIF_H_ #define FSFW_ACTION_COMMANDSACTIONSIF_H_
#include "CommandActionHelper.h" #include "CommandActionHelper.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
@ -24,11 +24,14 @@ public:
virtual MessageQueueIF* getCommandQueuePtr() = 0; virtual MessageQueueIF* getCommandQueuePtr() = 0;
protected: protected:
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0; virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0;
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) = 0; virtual void stepFailedReceived(ActionId_t actionId, uint8_t step,
virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) = 0; ReturnValue_t returnCode) = 0;
virtual void dataReceived(ActionId_t actionId, const uint8_t* data,
uint32_t size) = 0;
virtual void completionSuccessfulReceived(ActionId_t actionId) = 0; virtual void completionSuccessfulReceived(ActionId_t actionId) = 0;
virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) = 0; virtual void completionFailedReceived(ActionId_t actionId,
ReturnValue_t returnCode) = 0;
}; };
#endif /* COMMANDSACTIONSIF_H_ */ #endif /* FSFW_ACTION_COMMANDSACTIONSIF_H_ */

View File

@ -1,11 +1,12 @@
#ifndef FRAMEWORK_ACTION_HASACTIONSIF_H_ #ifndef FSFW_ACTION_HASACTIONSIF_H_
#define FRAMEWORK_ACTION_HASACTIONSIF_H_ #define FSFW_ACTION_HASACTIONSIF_H_
#include "ActionHelper.h" #include "ActionHelper.h"
#include "ActionMessage.h" #include "ActionMessage.h"
#include "SimpleActionHelper.h" #include "SimpleActionHelper.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "../ipc/MessageQueueIF.h" #include "../ipc/MessageQueueIF.h"
/** /**
* @brief * @brief
* Interface for component which uses actions * Interface for component which uses actions
@ -47,14 +48,16 @@ public:
virtual MessageQueueId_t getCommandQueue() const = 0; virtual MessageQueueId_t getCommandQueue() const = 0;
/** /**
* Execute or initialize the execution of a certain function. * Execute or initialize the execution of a certain function.
* Returning #EXECUTION_FINISHED or a failure code, nothing else needs to * The ActionHelpers will execute this function and behave differently
* be done. When needing more steps, return RETURN_OK and issue steps and * depending on the returnvalue.
* completion manually. *
* One "step failed" or completion report must be issued! * @return
* -@c EXECUTION_FINISHED Finish reply will be generated
* -@c Not RETURN_OK Step failure reply will be generated
*/ */
virtual ReturnValue_t executeAction(ActionId_t actionId, virtual ReturnValue_t executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0; MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0;
}; };
#endif /* FRAMEWORK_ACTION_HASACTIONSIF_H_ */ #endif /* FSFW_ACTION_HASACTIONSIF_H_ */

View File

@ -1,16 +1,17 @@
#include "HasActionsIF.h" #include "HasActionsIF.h"
#include "SimpleActionHelper.h" #include "SimpleActionHelper.h"
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner,
MessageQueueIF* useThisQueue) : MessageQueueIF* useThisQueue) :
ActionHelper(setOwner, useThisQueue), isExecuting(false), lastCommander( ActionHelper(setOwner, useThisQueue), isExecuting(false) {
0), lastAction(0), stepCount(0) {
} }
SimpleActionHelper::~SimpleActionHelper() { SimpleActionHelper::~SimpleActionHelper() {
} }
void SimpleActionHelper::step(ReturnValue_t result) { void SimpleActionHelper::step(ReturnValue_t result) {
//STEP_OFFESET is subtracted to compensate for adding offset in base method, which is not necessary here. // STEP_OFFESET is subtracted to compensate for adding offset in base
// method, which is not necessary here.
ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction, ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction,
result); result);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -1,8 +1,13 @@
#ifndef SIMPLEACTIONHELPER_H_ #ifndef FSFW_ACTION_SIMPLEACTIONHELPER_H_
#define SIMPLEACTIONHELPER_H_ #define FSFW_ACTION_SIMPLEACTIONHELPER_H_
#include "ActionHelper.h" #include "ActionHelper.h"
/**
* @brief This is an action helper which is only able to service one action
* at a time but remembers last commander and last action which
* simplifies usage
*/
class SimpleActionHelper: public ActionHelper { class SimpleActionHelper: public ActionHelper {
public: public:
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
@ -12,13 +17,14 @@ public:
ReturnValue_t reportData(SerializeIF* data); ReturnValue_t reportData(SerializeIF* data);
protected: protected:
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress); void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress);
virtual void resetHelper(); virtual void resetHelper();
private: private:
bool isExecuting; bool isExecuting;
MessageQueueId_t lastCommander; MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE;
ActionId_t lastAction; ActionId_t lastAction = 0;
uint8_t stepCount; uint8_t stepCount = 0;
}; };
#endif /* SIMPLEACTIONHELPER_H_ */ #endif /* SIMPLEACTIONHELPER_H_ */

View File

@ -9,6 +9,7 @@ SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size,
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
} }
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer, SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
const size_t size, bool overwriteOld, size_t maxExcessBytes): const size_t size, bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld, SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld,
@ -16,6 +17,11 @@ SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
} }
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
this->fifoDepth = fifoDepth;
}
ReturnValue_t SharedRingBuffer::lockRingBufferMutex( ReturnValue_t SharedRingBuffer::lockRingBufferMutex(
MutexIF::TimeoutType timeoutType, dur_millis_t timeout) { MutexIF::TimeoutType timeoutType, dur_millis_t timeout) {
return mutex->lockMutex(timeoutType, timeout); return mutex->lockMutex(timeoutType, timeout);
@ -25,6 +31,25 @@ ReturnValue_t SharedRingBuffer::unlockRingBufferMutex() {
return mutex->unlockMutex(); return mutex->unlockMutex();
} }
MutexIF* SharedRingBuffer::getMutexHandle() const { MutexIF* SharedRingBuffer::getMutexHandle() const {
return mutex; return mutex;
} }
ReturnValue_t SharedRingBuffer::initialize() {
if(fifoDepth > 0) {
receiveSizesFIFO = new DynamicFIFO<size_t>(fifoDepth);
}
return SystemObject::initialize();
}
DynamicFIFO<size_t>* SharedRingBuffer::getReceiveSizesFIFO() {
if(receiveSizesFIFO == nullptr) {
// Configuration error.
sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer"
<< " was not configured to have sizes FIFO, returning nullptr!"
<< std::endl;
}
return receiveSizesFIFO;
}

View File

@ -2,6 +2,7 @@
#define FSFW_CONTAINER_SHAREDRINGBUFFER_H_ #define FSFW_CONTAINER_SHAREDRINGBUFFER_H_
#include "SimpleRingBuffer.h" #include "SimpleRingBuffer.h"
#include "DynamicFIFO.h"
#include "../ipc/MutexIF.h" #include "../ipc/MutexIF.h"
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "../timemanager/Clock.h" #include "../timemanager/Clock.h"
@ -26,6 +27,16 @@ public:
SharedRingBuffer(object_id_t objectId, const size_t size, SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes); bool overwriteOld, size_t maxExcessBytes);
/**
* @brief This function can be used to add an optional FIFO to the class
* @details
* This FIFO will be allocated in the initialize function (and will
* have a fixed maximum size after that). It can be used to store
* values like packet sizes, for example for a shared ring buffer
* used by producer/consumer tasks.
*/
void setToUseReceiveSizeFIFO(size_t fifoDepth);
/** /**
* This constructor takes an external buffer with the specified size. * This constructor takes an external buffer with the specified size.
* @param buffer * @param buffer
@ -59,8 +70,21 @@ public:
* @return * @return
*/ */
MutexIF* getMutexHandle() const; MutexIF* getMutexHandle() const;
ReturnValue_t initialize() override;
/**
* If the shared ring buffer was configured to have a sizes FIFO, a handle
* to that FIFO can be retrieved with this function.
* Do not forget to protect access with a lock if required!
* @return
*/
DynamicFIFO<size_t>* getReceiveSizesFIFO();
private: private:
MutexIF* mutex = nullptr; MutexIF* mutex = nullptr;
size_t fifoDepth = 0;
DynamicFIFO<size_t>* receiveSizesFIFO = nullptr;
}; };

6
defaultcfg/README.md Normal file
View File

@ -0,0 +1,6 @@
# How to setup configuration folder for FSFW
It is recommended to copy the content of the defaultcfg folder
into a config folder which is in the same directory as the Flight
Software Framework submodule. After that, the config.mk folder should be
included by the primary Makefile with CURRENTPATH set correctly.

View File

@ -0,0 +1,55 @@
#ifndef CONFIG_FSFWCONFIG_H_
#define CONFIG_FSFWCONFIG_H_
#include <FSFWVersion.h>
#include <cstddef>
#include <cstdint>
//! Used to determine whether C++ ostreams are used
//! Those can lead to code bloat.
#define FSFW_CPP_OSTREAM_ENABLED 1
//! Reduced printout to further decrese code size
//! Be careful, this also turns off most diagnostic prinouts!
#define FSFW_REDUCED_PRINTOUT 0
//! Can be used to enable debugging printouts for developing the FSFW
#define FSFW_DEBUGGING 0
//! Defines the FIFO depth of each commanding service base which
//! also determines how many commands a CSB service can handle in one cycle
//! simulataneously. This will increase the required RAM for
//! each CSB service !
#define FSFW_CSB_FIFO_DEPTH 6
//! If FSFW_OBJ_EVENT_TRANSLATION is set to one,
//! additional output which requires the translation files translateObjects
//! and translateEvents (and their compiled source files)
#define FSFW_OBJ_EVENT_TRANSLATION 0
#if FSFW_OBJ_EVENT_TRANSLATION == 1
#define FSFW_DEBUG_OUTPUT 1
//! Specify whether info events are printed too.
#define FSFW_DEBUG_INFO 1
#include <translateObjects.h>
#include <translateEvents.h>
#else
#define FSFW_DEBUG_OUTPUT 0
#endif
//! When using the newlib nano library, C99 support for stdio facilities
//! will not be provided. This define should be set to 1 if this is the case.
#define FSFW_NO_C99_IO 1
namespace fsfwconfig {
//! Default timestamp size. The default timestamp will be an eight byte CDC
//! short timestamp.
static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8;
//! Configure the allocated pool sizes for the event manager.
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
}
#endif /* CONFIG_FSFWCONFIG_H_ */

View File

@ -0,0 +1,16 @@
#ifndef CONFIG_OBSWCONFIG_H_
#define CONFIG_OBSWCONFIG_H_
#include "OBSWVersion.h"
#ifdef __cplusplus
namespace config {
#endif
/* Add mission configuration flags here */
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_OBSWCONFIG_H_ */

View File

@ -0,0 +1,9 @@
#ifndef CONFIG_VERSION_H_
#define CONFIG_VERSION_H_
/* OBSW versioning can be specified in this file */
#define OBSW_VERSION 0
#define OBSW_SUBVERSION 0
#endif /* CONFIG_VERSION_H_ */

View File

@ -0,0 +1,5 @@
#include "logicalAddresses.h"

View File

@ -0,0 +1,18 @@
#ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_
#define CONFIG_DEVICES_LOGICALADDRESSES_H_
#include <fsfw/devicehandlers/CookieIF.h>
#include "../objects/systemObjectList.h"
#include <cstdint>
/**
* Can be used for addresses for physical devices like I2C adresses.
*/
namespace addresses {
/* Logical addresses have uint32_t datatype */
enum logicalAddresses: address_t {
};
}
#endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */

View File

@ -0,0 +1,4 @@
#include "powerSwitcherList.h"

View File

@ -0,0 +1,12 @@
#ifndef CONFIG_DEVICES_POWERSWITCHERLIST_H_
#define CONFIG_DEVICES_POWERSWITCHERLIST_H_
namespace switches {
/* Switches are uint8_t datatype and go from 0 to 255 */
enum switcherList {
};
}
#endif /* CONFIG_DEVICES_POWERSWITCHERLIST_H_ */

View File

@ -0,0 +1,18 @@
#ifndef CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
#define CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
#include <cstdint>
#include <fsfw/events/fwSubsystemIdRanges.h>
/**
* @brief Custom subsystem IDs can be added here
* @details
* Subsystem IDs are used to create unique events.
*/
namespace SUBSYSTEM_ID {
enum: uint8_t {
SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE,
};
}
#endif /* CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ */

View File

@ -0,0 +1,15 @@
CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/tmtc/*.cpp)
CXXSRC += $(wildcard $(CURRENTPATH)/devices/*.cpp)
INCLUDES += $(CURRENTPATH)
INCLUDES += $(CURRENTPATH)/objects
INCLUDES += $(CURRENTPATH)/returnvalues
INCLUDES += $(CURRENTPATH)/tmtc
INCLUDES += $(CURRENTPATH)/events
INCLUDES += $(CURRENTPATH)/devices
INCLUDES += $(CURRENTPATH)/pollingsequence
INCLUDES += $(CURRENTPATH)/ipc

View File

@ -0,0 +1,12 @@
#include "missionMessageTypes.h"
#include <fsfw/ipc/CommandMessageIF.h>
void messagetypes::clearMissionMessage(CommandMessage* message) {
switch(message->getMessageType()) {
default:
break;
}
}

View File

@ -0,0 +1,21 @@
#ifndef CONFIG_IPC_MISSIONMESSAGETYPES_H_
#define CONFIG_IPC_MISSIONMESSAGETYPES_H_
#include <fsfw/ipc/CommandMessage.h>
#include <fsfw/ipc/FwMessageTypes.h>
/**
* Custom command messages are specified here.
* Most messages needed to use FSFW are already located in
* <fsfw/ipc/FwMessageTypes.h>
* @param message Generic Command Message
*/
namespace messagetypes {
enum CustomMessageTypes {
MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT
};
void clearMissionMessage(CommandMessage* message);
}
#endif /* CONFIG_IPC_MISSIONMESSAGETYPES_H_ */

View File

@ -0,0 +1,54 @@
#include "Factory.h"
#include "../tmtc/apid.h"
#include "../tmtc/pusIds.h"
#include "../objects/systemObjectList.h"
#include "../devices/logicalAddresses.h"
#include "../devices/powerSwitcherList.h"
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include <fsfw/events/EventManager.h>
#include <fsfw/health/HealthTable.h>
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
#include <fsfw/tmtcservices/CommandingServiceBase.h>
#include <fsfw/tmtcservices/PusServiceBase.h>
#include <internalError/InternalErrorReporter.h>
#include <cstdint>
/**
* This class should be used to create all system objects required for
* the on-board software, using the object ID list from the configuration
* folder.
*
* The objects are registered in the internal object manager automatically.
* This is used later to add objects to tasks.
*
* This file also sets static framework IDs.
*
* Framework objects are created first.
* @ingroup init
*/
void Factory::produce(void) {
setStaticFrameworkObjectIds();
new EventManager(objects::EVENT_MANAGER);
new HealthTable(objects::HEALTH_TABLE);
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER);
}
void Factory::setStaticFrameworkObjectIds() {
PusServiceBase::packetSource = objects::NO_OBJECT;
PusServiceBase::packetDestination = objects::NO_OBJECT;
CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT;
CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT;
VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION;
DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
DeviceHandlerBase::rawDataReceiverId = objects::PUS_SERVICE_2_DEVICE_ACCESS;
DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
TmPacketStored::timeStamperId = objects::NO_OBJECT;
}

View File

@ -0,0 +1,17 @@
#ifndef FACTORY_H_
#define FACTORY_H_
#include <fsfw/objectmanager/SystemObjectIF.h>
#include <cstddef>
namespace Factory {
/**
* @brief Creates all SystemObject elements which are persistent
* during execution.
*/
void produce();
void setStaticFrameworkObjectIds();
}
#endif /* FACTORY_H_ */

View File

@ -0,0 +1,16 @@
#ifndef CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
#define CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
#include <cstdint>
#include <fsfw/objectmanager/frameworkObjects.h>
// The objects will be instantiated in the ID order
namespace objects {
enum sourceObjects: uint32_t {
/* All addresses between start and end are reserved for the FSFW */
FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION,
FSFW_CONFIG_RESERVED_END = TM_STORE
};
}
#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */

View File

@ -0,0 +1,23 @@
#include "PollingSequenceFactory.h"
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
ReturnValue_t pst::pollingSequenceInitDefault(
FixedTimeslotTaskIF *thisSequence) {
/* Length of a communication cycle */
uint32_t length = thisSequence->getPeriodMs();
/* Add polling sequence table here */
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!"
<< std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
}

View File

@ -0,0 +1,32 @@
#ifndef POLLINGSEQUENCEFACTORY_H_
#define POLLINGSEQUENCEFACTORY_H_
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
class FixedTimeslotTaskIF;
/**
* All device handlers are scheduled by adding them into Polling Sequence Tables (PST)
* to satisfy stricter timing requirements of device communication,
* A device handler has four different communication steps:
* 1. DeviceHandlerIF::SEND_WRITE -> Send write via interface
* 2. DeviceHandlerIF::GET_WRITE -> Get confirmation for write
* 3. DeviceHandlerIF::SEND_READ -> Send read request
* 4. DeviceHandlerIF::GET_READ -> Read from interface
* The PST specifies precisely when the respective ComIF functions are called
* during the communication cycle time.
* The task is created using the FixedTimeslotTaskIF,
* which utilises the underlying Operating System Abstraction Layer (OSAL)
*
* @param thisSequence FixedTimeslotTaskIF * object is passed inside the Factory class when creating the PST
* @return
*/
namespace pst {
/* Default PST */
ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence);
}
#endif /* POLLINGSEQUENCEINIT_H_ */

View File

@ -0,0 +1,16 @@
#ifndef CONFIG_RETURNVALUES_CLASSIDS_H_
#define CONFIG_RETURNVALUES_CLASSIDS_H_
#include <fsfw/returnvalues/FwClassIds.h>
/**
* @brief CLASS_ID defintions which are required for custom returnvalues.
*/
namespace CLASS_ID {
enum {
MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT,
};
}
#endif /* CONFIG_RETURNVALUES_CLASSIDS_H_ */

View File

@ -0,0 +1,18 @@
#ifndef CONFIG_TMTC_APID_H_
#define CONFIG_TMTC_APID_H_
#include <cstdint>
/**
* Application Process Definition: entity, uniquely identified by an
* application process ID (APID), capable of generating telemetry source
* packets and receiving telecommand packets.
*
* Chose APID(s) for mission and define it here.
*/
namespace apid {
static const uint16_t DEFAULT_APID = 0x00;
}
#endif /* CONFIG_TMTC_APID_H_ */

View File

@ -0,0 +1,23 @@
#ifndef CONFIG_TMTC_PUSIDS_HPP_
#define CONFIG_TMTC_PUSIDS_HPP_
namespace pus {
enum Ids: uint8_t {
PUS_SERVICE_1 = 1,
PUS_SERVICE_2 = 2,
PUS_SERVICE_3 = 3,
PUS_SERVICE_5 = 5,
PUS_SERVICE_6 = 6,
PUS_SERVICE_8 = 8,
PUS_SERVICE_9 = 9,
PUS_SERVICE_11 = 11,
PUS_SERVICE_17 = 17,
PUS_SERVICE_19 = 19,
PUS_SERVICE_20 = 20,
PUS_SERVICE_23 = 23,
PUS_SERVICE_200 = 200,
PUS_SERVICE_201 = 201,
};
};
#endif /* CONFIG_TMTC_PUSIDS_HPP_ */

View File

@ -1235,7 +1235,7 @@ void DeviceHandlerBase::buildInternalCommand(void) {
if (result == BUSY) { if (result == BUSY) {
//so we can track misconfigurations //so we can track misconfigurations
sif::debug << std::hex << getObjectId() sif::debug << std::hex << getObjectId()
<< ": DHB::buildInternalCommand: Busy" << std::endl; << ": DHB::buildInternalCommand: Busy" << std::dec << std::endl;
result = NOTHING_TO_SEND; //no need to report this result = NOTHING_TO_SEND; //no need to report this
} }
} }

View File

@ -1,5 +1,7 @@
#include "EventManager.h" #include "EventManager.h"
#include "EventMessage.h" #include "EventMessage.h"
#include <FSFWConfig.h>
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
@ -12,8 +14,10 @@ const uint16_t EventManager::POOL_SIZES[N_POOLS] = {
// objects registering for certain events. // objects registering for certain events.
// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. // Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher.
// So a good guess is 75 to a max of 100 pools required for each, which fits well. // So a good guess is 75 to a max of 100 pools required for each, which fits well.
// SHOULDDO: Shouldn't this be in the config folder and passed via ctor? const uint16_t EventManager::N_ELEMENTS[N_POOLS] = {
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 }; fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES ,
fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS,
fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS };
EventManager::EventManager(object_id_t setObjectId) : EventManager::EventManager(object_id_t setObjectId) :
SystemObject(setObjectId), SystemObject(setObjectId),

13
fsfw.mk
View File

@ -28,12 +28,25 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/*.cpp)
# select the OS # select the OS
ifeq ($(OS_FSFW),rtems) ifeq ($(OS_FSFW),rtems)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/rtems/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/rtems/*.cpp)
else ifeq ($(OS_FSFW),linux) else ifeq ($(OS_FSFW),linux)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/linux/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/linux/*.cpp)
else ifeq ($(OS_FSFW),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) else ifeq ($(OS_FSFW),host)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/host/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/host/*.cpp)
ifeq ($(OS),Windows_NT)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/windows/*.cpp)
else
# For now, the linux UDP bridge sources needs to be included manually by upper makefile
# for host OS because we can't be sure the OS is linux.
# Following lines can be used to do this:
# CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TcUnixUdpPollingTask.cpp
# CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TmTcUnixUdpBridge.cpp
endif
else else
$(error invalid OS_FSFW specified, valid OS_FSFW are rtems, linux, freeRTOS, host) $(error invalid OS_FSFW specified, valid OS_FSFW are rtems, linux, freeRTOS, host)
endif endif

View File

@ -1,5 +1,5 @@
#ifndef HASHEALTHIF_H_ #ifndef FSFW_HEALTH_HASHEALTHIF_H_
#define HASHEALTHIF_H_ #define FSFW_HEALTH_HASHEALTHIF_H_
#include "../events/Event.h" #include "../events/Event.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
@ -8,9 +8,13 @@
class HasHealthIF { class HasHealthIF {
public: public:
typedef enum { enum HealthState: uint8_t {
HEALTHY = 1, FAULTY = 0, EXTERNAL_CONTROL = 2, NEEDS_RECOVERY = 3, PERMANENT_FAULTY = 4 HEALTHY = 1,
} HealthState; FAULTY = 0,
EXTERNAL_CONTROL = 2,
NEEDS_RECOVERY = 3,
PERMANENT_FAULTY = 4
};
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF; static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1); static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
@ -31,20 +35,17 @@ public:
virtual MessageQueueId_t getCommandQueue() const = 0; virtual MessageQueueId_t getCommandQueue() const = 0;
/** /**
* set the Health State * @brief Set the Health State
*
* The parent will be informed, if the Health changes * The parent will be informed, if the Health changes
*
* @param health * @param health
*/ */
virtual ReturnValue_t setHealth(HealthState health) = 0; virtual ReturnValue_t setHealth(HealthState health) = 0;
/** /**
* get Health State * @brief Get Health State
*
* @return Health State of the object * @return Health State of the object
*/ */
virtual HasHealthIF::HealthState getHealth() = 0; virtual HasHealthIF::HealthState getHealth() = 0;
}; };
#endif /* HASHEALTHIF_H_ */ #endif /* FSFW_HEALTH_HASHEALTHIF_H_ */

View File

@ -12,13 +12,15 @@
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
/** /**
* Helper class for Objects that implement HasHealthIF * @brief Helper class for Objects that implement HasHealthIF
* @details
* It takes care of registering with the Health Table as well as handling
* health commands (including replying to the sender) and updating
* the Health Table.
* *
* It takes care of registering with the Health Table as well as handling health commands * If a parent is set in the ctor, the parent will be informed with a
* (including replying to the sender) and updating the Health Table. * @c HEALTH_INFO message about changes in the health state.
* * Note that a @c HEALTH_INFO is only generated if the Health
* If a parent is set in the ctor, the parent will be informed with a @c HEALTH_INFO message
* about changes in the health state. Note that a @c HEALTH_INFO is only generated if the Health
* changes, not for all @c HEALTH_SET commands received. * changes, not for all @c HEALTH_SET commands received.
* *
* It does NOT handle @c HEALTH_INFO messages * It does NOT handle @c HEALTH_INFO messages
@ -27,10 +29,9 @@ class HealthHelper {
public: public:
/** /**
* ctor
*
* @param owner * @param owner
* @param objectId the object Id to use when communication with the HealthTable * @param objectId The object Id to use when communication with
* the HealthTable
*/ */
HealthHelper(HasHealthIF* owner, object_id_t objectId); HealthHelper(HasHealthIF* owner, object_id_t objectId);
@ -57,7 +58,8 @@ public:
* @param message * @param message
* @return * @return
* -@c RETURN_OK if the message was handled * -@c RETURN_OK if the message was handled
* -@c RETURN_FAILED if the message could not be handled (ie it was not a @c HEALTH_SET or @c HEALTH_READ message) * -@c RETURN_FAILED if the message could not be handled
* (ie it was not a @c HEALTH_SET or @c HEALTH_READ message)
*/ */
ReturnValue_t handleHealthCommand(CommandMessage *message); ReturnValue_t handleHealthCommand(CommandMessage *message);
@ -78,15 +80,18 @@ public:
HasHealthIF::HealthState getHealth(); HasHealthIF::HealthState getHealth();
/** /**
* @param parentQueue the Queue id of the parent object. Set to 0 if no parent present * @param parentQueue The queue ID of the parent object.
* Set to 0 if no parent present
*/ */
void setParentQueue(MessageQueueId_t parentQueue); void setParentQueue(MessageQueueId_t parentQueue);
/** /**
* *
* @param parentQueue the Queue id of the parent object. Set to 0 if no parent present * @param parentQueue The queue ID of the parent object.
* Set to 0 if no parent present
* @return * @return
* -@c RETURN_OK if the Health Table was found and the object could be registered * -@c RETURN_OK if the Health Table was found and the object
* could be registered
* -@c RETURN_FAILED else * -@c RETURN_FAILED else
*/ */
ReturnValue_t initialize(MessageQueueId_t parentQueue ); ReturnValue_t initialize(MessageQueueId_t parentQueue );
@ -110,11 +115,15 @@ private:
HasHealthIF* owner; HasHealthIF* owner;
/** /**
* if the #parentQueue is not NULL, a @c HEALTH_INFO message will be sent to this queue * if the #parentQueue is not NULL, a @c HEALTH_INFO message
* @param health the health is passed as parameter so that the number of calls to the health table can be minimized * will be sent to this queue
* @param health
* The health is passed as parameter so that the number of
* calls to the health table can be minimized
* @param oldHealth information of the previous health state. * @param oldHealth information of the previous health state.
*/ */
void informParent(HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth); void informParent(HasHealthIF::HealthState health,
HasHealthIF::HealthState oldHealth);
void handleSetHealthCommand(CommandMessage *message); void handleSetHealthCommand(CommandMessage *message);
}; };

View File

@ -7,11 +7,13 @@ void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command,
message->setParameter2(oldHealth); message->setParameter2(oldHealth);
} }
void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command) { void HealthMessage::setHealthMessage(CommandMessage* message,
Command_t command) {
message->setCommand(command); message->setCommand(command);
} }
HasHealthIF::HealthState HealthMessage::getHealth(const CommandMessage* message) { HasHealthIF::HealthState HealthMessage::getHealth(
const CommandMessage* message) {
return (HasHealthIF::HealthState) message->getParameter(); return (HasHealthIF::HealthState) message->getParameter();
} }

View File

@ -1,5 +1,5 @@
#ifndef HEALTHMESSAGE_H_ #ifndef FSFW_HEALTH_HEALTHMESSAGE_H_
#define HEALTHMESSAGE_H_ #define FSFW_HEALTH_HEALTHMESSAGE_H_
#include "HasHealthIF.h" #include "HasHealthIF.h"
#include "../ipc/CommandMessage.h" #include "../ipc/CommandMessage.h"
@ -7,14 +7,20 @@
class HealthMessage { class HealthMessage {
public: public:
static const uint8_t MESSAGE_ID = messagetypes::HEALTH_COMMAND; static const uint8_t MESSAGE_ID = messagetypes::HEALTH_COMMAND;
static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);//REPLY_COMMAND_OK/REPLY_REJECTED
static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(3); //NO REPLY! static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);
// No reply expected, health will be announced as event!
static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(2);
// Same as before, but all objects in health table will
// announce their health as events.
static const Command_t HEALTH_ANNOUNCE_ALL = MAKE_COMMAND_ID(3);
static const Command_t HEALTH_INFO = MAKE_COMMAND_ID(5); static const Command_t HEALTH_INFO = MAKE_COMMAND_ID(5);
static const Command_t REPLY_HEALTH_SET = MAKE_COMMAND_ID(6); static const Command_t REPLY_HEALTH_SET = MAKE_COMMAND_ID(6);
static void setHealthMessage(CommandMessage *message, Command_t command, static void setHealthMessage(CommandMessage *message, Command_t command,
HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth = HasHealthIF::FAULTY); HasHealthIF::HealthState health,
HasHealthIF::HealthState oldHealth = HasHealthIF::FAULTY);
static void setHealthMessage(CommandMessage *message, Command_t command); static void setHealthMessage(CommandMessage *message, Command_t command);
static HasHealthIF::HealthState getHealth(const CommandMessage *message); static HasHealthIF::HealthState getHealth(const CommandMessage *message);
@ -27,4 +33,4 @@ private:
HealthMessage(); HealthMessage();
}; };
#endif /* HEALTHMESSAGE_H_ */ #endif /* FSFW_HEALTH_HEALTHMESSAGE_H_ */

View File

@ -1,6 +1,7 @@
#include "HealthTable.h" #include "HealthTable.h"
#include "../serialize/SerializeAdapter.h" #include "../ipc/MutexHelper.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
#include "../serialize/SerializeAdapter.h"
HealthTable::HealthTable(object_id_t objectid) : HealthTable::HealthTable(object_id_t objectid) :
SystemObject(objectid) { SystemObject(objectid) {
@ -9,6 +10,12 @@ HealthTable::HealthTable(object_id_t objectid) :
mapIterator = healthMap.begin(); mapIterator = healthMap.begin();
} }
void HealthTable::setMutexTimeout(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) {
this->timeoutType = timeoutType;
this->mutexTimeoutMs = timeoutMs;
}
HealthTable::~HealthTable() { HealthTable::~HealthTable() {
MutexFactory::instance()->deleteMutex(mutex); MutexFactory::instance()->deleteMutex(mutex);
} }
@ -18,74 +25,63 @@ ReturnValue_t HealthTable::registerObject(object_id_t object,
if (healthMap.count(object) != 0) { if (healthMap.count(object) != 0) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
healthMap.insert( healthMap.emplace(object, initilialState);
std::pair<object_id_t, HasHealthIF::HealthState>(object,
initilialState));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void HealthTable::setHealth(object_id_t object, void HealthTable::setHealth(object_id_t object,
HasHealthIF::HealthState newState) { HasHealthIF::HealthState newState) {
mutex->lockMutex(MutexIF::BLOCKING); MutexHelper(mutex, timeoutType, mutexTimeoutMs);
HealthMap::iterator iter = healthMap.find(object); HealthMap::iterator iter = healthMap.find(object);
if (iter != healthMap.end()) { if (iter != healthMap.end()) {
iter->second = newState; iter->second = newState;
} }
mutex->unlockMutex();
} }
HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) { HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) {
HasHealthIF::HealthState state = HasHealthIF::HEALTHY; HasHealthIF::HealthState state = HasHealthIF::HEALTHY;
mutex->lockMutex(MutexIF::BLOCKING); MutexHelper(mutex, timeoutType, mutexTimeoutMs);
HealthMap::iterator iter = healthMap.find(object); HealthMap::iterator iter = healthMap.find(object);
if (iter != healthMap.end()) { if (iter != healthMap.end()) {
state = iter->second; state = iter->second;
} }
mutex->unlockMutex();
return state; return state;
} }
uint32_t HealthTable::getPrintSize() { bool HealthTable::hasHealth(object_id_t object) {
mutex->lockMutex(MutexIF::BLOCKING); MutexHelper(mutex, timeoutType, mutexTimeoutMs);
uint32_t size = healthMap.size() * 5 + 2; HealthMap::iterator iter = healthMap.find(object);
mutex->unlockMutex(); if (iter != healthMap.end()) {
return true;
}
return false;
}
size_t HealthTable::getPrintSize() {
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
uint32_t size = healthMap.size() * sizeof(object_id_t) +
sizeof(HasHealthIF::HealthState) + sizeof(uint16_t);
return size; return size;
} }
bool HealthTable::hasHealth(object_id_t object) {
bool exits = false;
mutex->lockMutex(MutexIF::BLOCKING);
HealthMap::iterator iter = healthMap.find(object);
if (iter != healthMap.end()) {
exits = true;
}
mutex->unlockMutex();
return exits;
}
void HealthTable::printAll(uint8_t* pointer, size_t maxSize) { void HealthTable::printAll(uint8_t* pointer, size_t maxSize) {
mutex->lockMutex(MutexIF::BLOCKING); MutexHelper(mutex, timeoutType, mutexTimeoutMs);
size_t size = 0; size_t size = 0;
uint16_t count = healthMap.size(); uint16_t count = healthMap.size();
ReturnValue_t result = SerializeAdapter::serialize(&count, SerializeAdapter::serialize(&count,
&pointer, &size, maxSize, SerializeIF::Endianness::BIG); &pointer, &size, maxSize, SerializeIF::Endianness::BIG);
HealthMap::iterator iter; for (const auto& health: healthMap) {
for (iter = healthMap.begin(); SerializeAdapter::serialize(&health.first,
iter != healthMap.end() && result == HasReturnvaluesIF::RETURN_OK;
++iter) {
result = SerializeAdapter::serialize(&iter->first,
&pointer, &size, maxSize, SerializeIF::Endianness::BIG); &pointer, &size, maxSize, SerializeIF::Endianness::BIG);
uint8_t health = iter->second; uint8_t healthValue = health.second;
result = SerializeAdapter::serialize(&health, &pointer, &size, SerializeAdapter::serialize(&healthValue, &pointer, &size,
maxSize, SerializeIF::Endianness::BIG); maxSize, SerializeIF::Endianness::BIG);
} }
mutex->unlockMutex();
} }
ReturnValue_t HealthTable::iterate( ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) {
std::pair<object_id_t, HasHealthIF::HealthState> *value, bool reset) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
mutex->lockMutex(MutexIF::BLOCKING); MutexHelper(mutex, timeoutType, mutexTimeoutMs);
if (reset) { if (reset) {
mapIterator = healthMap.begin(); mapIterator = healthMap.begin();
} }
@ -94,7 +90,5 @@ ReturnValue_t HealthTable::iterate(
} }
*value = *mapIterator; *value = *mapIterator;
mapIterator++; mapIterator++;
mutex->unlockMutex();
return result; return result;
} }

View File

@ -1,35 +1,47 @@
#ifndef HEALTHTABLE_H_ #ifndef FSFW_HEALTH_HEALTHTABLE_H_
#define HEALTHTABLE_H_ #define FSFW_HEALTH_HEALTHTABLE_H_
#include "HealthTableIF.h" #include "HealthTableIF.h"
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "../ipc/MutexIF.h" #include "../ipc/MutexIF.h"
#include <map> #include <map>
typedef std::map<object_id_t, HasHealthIF::HealthState> HealthMap;
class HealthTable: public HealthTableIF, public SystemObject { class HealthTable: public HealthTableIF, public SystemObject {
public: public:
HealthTable(object_id_t objectid); HealthTable(object_id_t objectid);
virtual ~HealthTable(); virtual ~HealthTable();
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
/** HealthTableIF overrides */
virtual ReturnValue_t registerObject(object_id_t object, virtual ReturnValue_t registerObject(object_id_t object,
HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY); HasHealthIF::HealthState initilialState =
HasHealthIF::HEALTHY) override;
virtual size_t getPrintSize() override;
virtual void printAll(uint8_t *pointer, size_t maxSize) override;
virtual bool hasHealth(object_id_t object); /** ManagesHealthIF overrides */
virtual void setHealth(object_id_t object, HasHealthIF::HealthState newState); virtual bool hasHealth(object_id_t object) override;
virtual HasHealthIF::HealthState getHealth(object_id_t); virtual void setHealth(object_id_t object,
HasHealthIF::HealthState newState) override;
virtual uint32_t getPrintSize(); virtual HasHealthIF::HealthState getHealth(object_id_t) override;
virtual void printAll(uint8_t *pointer, size_t maxSize);
protected: protected:
using HealthMap = std::map<object_id_t, HasHealthIF::HealthState>;
using HealthEntry = std::pair<object_id_t, HasHealthIF::HealthState>;
MutexIF* mutex; MutexIF* mutex;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeoutMs = 20;
HealthMap healthMap; HealthMap healthMap;
HealthMap::iterator mapIterator; HealthMap::iterator mapIterator;
virtual ReturnValue_t iterate(std::pair<object_id_t,HasHealthIF::HealthState> *value, bool reset = false); virtual ReturnValue_t iterate(
HealthEntry* value,
bool reset = false) override;
}; };
#endif /* HEALTHTABLE_H_ */ #endif /* FSFW_HEALTH_HEALTHTABLE_H_ */

View File

@ -1,26 +1,24 @@
#ifndef HEALTHTABLEIF_H_ #ifndef FSFW_HEALTH_HEALTHTABLEIF_H_
#define HEALTHTABLEIF_H_ #define FSFW_HEALTH_HEALTHTABLEIF_H_
#include "ManagesHealthIF.h" #include "ManagesHealthIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <map>
class HealthTableIF: public ManagesHealthIF { class HealthTableIF: public ManagesHealthIF {
friend class HealthCommandingService;
public: public:
virtual ~HealthTableIF() { virtual ~HealthTableIF() {}
}
virtual ReturnValue_t registerObject(object_id_t object, virtual ReturnValue_t registerObject(object_id_t object,
HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0; HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0;
virtual uint32_t getPrintSize() = 0; virtual size_t getPrintSize() = 0;
virtual void printAll(uint8_t *pointer, size_t maxSize) = 0; virtual void printAll(uint8_t *pointer, size_t maxSize) = 0;
protected: protected:
virtual ReturnValue_t iterate(std::pair<object_id_t,HasHealthIF::HealthState> *value, bool reset = false) = 0; virtual ReturnValue_t iterate(
std::pair<object_id_t,HasHealthIF::HealthState> *value,
bool reset = false) = 0;
}; };
#endif /* HEALTHTABLEIF_H_ */ #endif /* FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ */

View File

@ -1,8 +1,9 @@
#ifndef FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ #ifndef FSFW_HEALTH_MANAGESHEALTHIF_H_
#define FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ #define FSFW_HEALTH_MANAGESHEALTHIF_H_
#include "HasHealthIF.h" #include "HasHealthIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
class ManagesHealthIF { class ManagesHealthIF {
public: public:
virtual ~ManagesHealthIF() { virtual ~ManagesHealthIF() {
@ -49,4 +50,4 @@ public:
} }
}; };
#endif /* FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ */ #endif /* FSFW_HEALTH_MANAGESHEALTHIF_H_ */

View File

@ -1,61 +1,77 @@
#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_ #ifndef FSFW_IPC_MESSAGEQUEUEIF_H_
#define FSFW_IPC_MESSAGEQUEUEIF_H_ #define FSFW_IPC_MESSAGEQUEUEIF_H_
// COULDDO: We could support blocking calls
#include "messageQueueDefinitions.h" #include "messageQueueDefinitions.h"
#include "MessageQueueMessage.h" #include "MessageQueueMessageIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <cstdint>
// COULDDO: We could support blocking calls
// semaphores are being implemented, which makes this idea even more iteresting.
/**
* @defgroup message_queue Message Queue
* @brief Message Queue related software components
*/
class MessageQueueIF { class MessageQueueIF {
public: public:
static const MessageQueueId_t NO_QUEUE = 0; static const MessageQueueId_t NO_QUEUE = 0;
static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF;
/** //! No new messages on the queue
* No new messages on the queue
*/
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1); static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1);
/** //! No space left for more messages
* No space left for more messages
*/
static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); static const ReturnValue_t FULL = MAKE_RETURN_CODE(2);
/** //! Returned if a reply method was called without partner
* Returned if a reply method was called without partner
*/
static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3); static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3);
//! Returned if the target destination is invalid.
static constexpr ReturnValue_t DESTINVATION_INVALID = MAKE_RETURN_CODE(4);
virtual ~MessageQueueIF() {} virtual ~MessageQueueIF() {}
/** /**
* @brief This operation sends a message to the last communication partner. * @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using the stored * @details
* lastParnter information as destination. If there was no message received yet * This operation simplifies answering an incoming message by using the
* (i.e. lastPartner is zero), an error code is returned. * stored lastParnter information as destination. If there was no message
* @param message A pointer to a previously created message, which is sent. * received yet (i.e. lastPartner is zero), an error code is returned.
* \return RETURN_OK if ok * @param message
* \return NO_REPLY_PARTNER Should return NO_REPLY_PARTNER if partner was found * A pointer to a previously created message, which is sent.
* @return
* -@c RETURN_OK if ok
* -@c NO_REPLY_PARTNER Should return NO_REPLY_PARTNER if partner was found.
*/ */
virtual ReturnValue_t reply( MessageQueueMessage* message ) = 0; virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0;
/** /**
* @brief This function reads available messages from the message queue and returns the sender. * @brief This function reads available messages from the message queue
* @details It works identically to the other receiveMessage call, but in addition returns the * and returns the sender.
* sender's queue id. * @details
* @param message A pointer to a message in which the received data is stored. * It works identically to the other receiveMessage call, but in addition
* @param receivedFrom A pointer to a queue id in which the sender's id is stored. * returns the sender's queue id.
* @param message
* A pointer to a message in which the received data is stored.
* @param receivedFrom
* A pointer to a queue id in which the sender's id is stored.
*/ */
virtual ReturnValue_t receiveMessage(MessageQueueMessage* message, virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t *receivedFrom) = 0; MessageQueueId_t *receivedFrom) = 0;
/** /**
* @brief This function reads available messages from the message queue. * @brief This function reads available messages from the message queue.
* @details If data is available it is stored in the passed message pointer. The message's * @details
* original content is overwritten and the sendFrom information is stored in the * If data is available it is stored in the passed message pointer.
* lastPartner attribute. Else, the lastPartner information remains untouched, the * The message's original content is overwritten and the sendFrom
* message's content is cleared and the function returns immediately. * information is stored in theblastPartner attribute. Else, the lastPartner
* @param message A pointer to a message in which the received data is stored. * information remains untouched, the message's content is cleared and the
* function returns immediately.
* @param message
* A pointer to a message in which the received data is stored.
* @return -@c RETURN_OK on success
* -@c MessageQueueIF::EMPTY if queue is empty
*/ */
virtual ReturnValue_t receiveMessage(MessageQueueMessage* message) = 0; virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0;
/** /**
* Deletes all pending messages in the queue. * Deletes all pending messages in the queue.
* @param count The number of flushed messages. * @param count The number of flushed messages.
@ -63,57 +79,89 @@ public:
*/ */
virtual ReturnValue_t flush(uint32_t* count) = 0; virtual ReturnValue_t flush(uint32_t* count) = 0;
/** /**
* @brief This method returns the message queue id of the last communication partner. * @brief This method returns the message queue
* id of the last communication partner.
*/ */
virtual MessageQueueId_t getLastPartner() const = 0; virtual MessageQueueId_t getLastPartner() const = 0;
/** /**
* @brief This method returns the message queue id of this class's message queue. * @brief This method returns the message queue
* id of this class's message queue.
*/ */
virtual MessageQueueId_t getId() const = 0; virtual MessageQueueId_t getId() const = 0;
/** /**
* \brief With the sendMessage call, a queue message is sent to a receiving queue. * @brief With the sendMessage call, a queue message
* \details This method takes the message provided, adds the sentFrom information and passes * is sent to a receiving queue.
* it on to the destination provided with an operating system call. The OS's return * @details
* value is returned. * This method takes the message provided, adds the sentFrom information
* \param sendTo This parameter specifies the message queue id to send the message to. * and passes it on to the destination provided with an operating system
* \param message This is a pointer to a previously created message, which is sent. * call. The OS's returnvalue is returned.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * @param sendTo
* This variable is set to zero by default. * This parameter specifies the message queue id to send the message to.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full (if implemented). * @param message
* This is a pointer to a previously created message, which is sent.
* @param sentFrom
* The sentFrom information can be set to inject the sender's queue id
* into the message. This variable is set to zero by default.
* @param ignoreFault
* If set to true, the internal software fault counter is not incremented
* if queue is full (if implemented).
* @return -@c RETURN_OK on success
* -@c MessageQueueIF::FULL if queue is full
*/ */
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
/** MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
* @brief This operation sends a message to the given destination. bool ignoreFault = false ) = 0;
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its
* queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault = false ) = 0;
/** /**
* \brief The sendToDefaultFrom method sends a queue message to the default destination. * @brief This operation sends a message to the given destination.
* \details In all other aspects, it works identical to the sendMessage method. * @details
* \param message This is a pointer to a previously created message, which is sent. * It directly uses the sendMessage call of the MessageQueueSender parent,
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * but passes its queue id as "sentFrom" parameter.
* This variable is set to zero by default. * @param sendTo
* This parameter specifies the message queue id of the destination
* message queue.
* @param message
* A pointer to a previously created message, which is sent.
* @param ignoreFault
* If set to true, the internal software fault counter is not incremented
* if queue is full.
*/ */
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault = false ) = 0;
/**
* @brief The sendToDefaultFrom method sends a queue message
* to the default destination.
* @details
* In all other aspects, it works identical to the sendMessage method.
* @param message
* This is a pointer to a previously created message, which is sent.
* @param sentFrom
* The sentFrom information can be set to inject the sender's queue id
* into the message. This variable is set to zero by default.
* @return -@c RETURN_OK on success
* -@c MessageQueueIF::FULL if queue is full
*/
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0;
/** /**
* @brief This operation sends a message to the default destination. * @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the sendToDefault call of the * @details
* Implementation class and adds its queue id as "sentFrom" information. * As in the sendMessage method, this function uses the sendToDefault
* call of the Implementation class and adds its queue id as
* "sentFrom" information.
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
* @return -@c RETURN_OK on success
* -@c MessageQueueIF::FULL if queue is full
*/ */
virtual ReturnValue_t sendToDefault( MessageQueueMessage* message ) = 0; virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ) = 0;
/** /**
* \brief This method is a simple setter for the default destination. * @brief This method is a simple setter for the default destination.
*/ */
virtual void setDefaultDestination(MessageQueueId_t defaultDestination) = 0; virtual void setDefaultDestination(MessageQueueId_t defaultDestination) = 0;
/** /**
* \brief This method is a simple getter for the default destination. * @brief This method is a simple getter for the default destination.
*/ */
virtual MessageQueueId_t getDefaultDestination() const = 0; virtual MessageQueueId_t getDefaultDestination() const = 0;
@ -122,4 +170,4 @@ public:
#endif /* FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ */ #endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */

View File

@ -1,8 +1,8 @@
#ifndef FSFW_IPC_MESSAGEQUEUESENDERIF_H_ #ifndef FSFW_IPC_MESSAGEQUEUESENDERIF_H_
#define FSFW_IPC_MESSAGEQUEUESENDERIF_H_ #define FSFW_IPC_MESSAGEQUEUESENDERIF_H_
#include "../ipc/MessageQueueIF.h" #include "MessageQueueIF.h"
#include "../ipc/MessageQueueMessageIF.h" #include "MessageQueueMessageIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
class MessageQueueSenderIF { class MessageQueueSenderIF {
@ -15,7 +15,7 @@ public:
* Not sure whether this is actually a good idea. * Not sure whether this is actually a good idea.
*/ */
static ReturnValue_t sendMessage(MessageQueueId_t sendTo, static ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = MessageQueueIF::NO_QUEUE, MessageQueueId_t sentFrom = MessageQueueIF::NO_QUEUE,
bool ignoreFault = false); bool ignoreFault = false);
private: private:

View File

@ -1,8 +1,10 @@
#ifndef FRAMEWORK_IPC_QUEUEFACTORY_H_ #ifndef FSFW_IPC_QUEUEFACTORY_H_
#define FRAMEWORK_IPC_QUEUEFACTORY_H_ #define FSFW_IPC_QUEUEFACTORY_H_
#include "MessageQueueIF.h" #include "MessageQueueIF.h"
#include <stdint.h> #include "MessageQueueMessage.h"
#include <cstdint>
/** /**
* Creates message queues. * Creates message queues.
* This class is a "singleton" interface, i.e. it provides an * This class is a "singleton" interface, i.e. it provides an
@ -30,4 +32,4 @@ private:
static QueueFactory* factoryInstance; static QueueFactory* factoryInstance;
}; };
#endif /* FRAMEWORK_IPC_QUEUEFACTORY_H_ */ #endif /* FSFW_IPC_QUEUEFACTORY_H_ */

BIN
logo/FSFW_Logo_V3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

711
logo/FSFW_Logo_V3.svg Normal file
View File

@ -0,0 +1,711 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="59.111mm"
height="67.383003mm"
viewBox="0 0 59.111 67.383003"
version="1.1"
id="svg22814"
inkscape:version="0.92.0 r15299"
sodipodi:docname="FSFW_Logo_V3.svg"
style="enable-background:new">
<defs
id="defs22808">
<inkscape:path-effect
effect="bspline"
id="path-effect23502"
is_visible="true"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter23683">
<feBlend
inkscape:collect="always"
mode="darken"
in2="BackgroundImage"
id="feBlend23685" />
</filter>
<meshgradient
inkscape:collect="always"
id="meshgradient23819"
gradientUnits="userSpaceOnUse"
x="-9.447978"
y="-28.967659"
gradientTransform="matrix(1.6672918,0,0,1.5637161,15.752536,45.300004)">
<meshrow
id="meshrow23821">
<meshpatch
id="meshpatch23823">
<stop
path="c 11.8178,0 23.6355,0 35.4533,0"
style="stop-color:#0087ce;stop-opacity:1"
id="stop23825" />
<stop
path="c 0,3.49232 0,6.98464 0,10.477"
style="stop-color:#00beff;stop-opacity:1"
id="stop23827" />
<stop
path="c -11.8178,0 -23.6355,0 -35.4533,0"
style="stop-color:#0087ce;stop-opacity:1"
id="stop23829" />
<stop
path="c 0,-3.49232 0,-6.98464 0,-10.477"
style="stop-color:#00519e;stop-opacity:1"
id="stop23831" />
</meshpatch>
</meshrow>
</meshgradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath24955">
<g
style="display:inline;fill:url(#meshgradient24977);fill-opacity:1;enable-background:new"
id="g24975"
transform="translate(-42.742183,-140.61702)"
clip-path="none">
<path
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98699999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 48.300305,143.44076 c -0.811661,0 -1.109125,0.75874 -1.480469,1.48047 l -4.00014,7.77454 c -0.371344,0.72173 0.668807,1.48047 1.480468,1.48047 h 9.625183 c 0.811661,0 1.109108,-0.75875 1.480469,-1.48047 l 4.00036,-7.77454 c 0.371361,-0.72172 -0.668808,-1.48047 -1.480469,-1.48047 z m 0,0.98828 h 9.625402 c 0.281935,0 0.621179,0.2415 0.492187,0.49219 l -4.00036,7.77454 c -0.128993,0.25069 -0.210251,0.49218 -0.492187,0.49218 h -9.625181 c -0.281935,0 -0.621175,-0.24149 -0.492189,-0.49218 l 4.000141,-7.77454 c 0.128986,-0.25069 0.210253,-0.49219 0.492187,-0.49219 z"
id="path24957"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssssssssssssssssss" />
<path
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
sodipodi:nodetypes="ssssssssssssssssss"
inkscape:connector-curvature="0"
id="path24959"
d="m 90.668816,143.44076 c -0.811661,0 -1.109125,0.75874 -1.480469,1.48047 l -4.00014,7.77454 c -0.371344,0.72173 0.668808,1.48047 1.480469,1.48047 h 9.625909 c 0.81166,0 1.109109,-0.75875 1.48047,-1.48047 l 4.000355,-7.77454 c 0.37136,-0.72172 -0.66881,-1.48047 -1.48046,-1.48047 z m 0,0.98828 h 9.626134 c 0.28193,0 0.62117,0.24151 0.49218,0.49219 l -4.000365,7.77454 c -0.128993,0.25069 -0.21025,0.49218 -0.49218,0.49218 h -9.625909 c -0.281935,0 -0.621174,-0.24149 -0.492188,-0.49218 l 4.00014,-7.77454 c 0.128986,-0.25069 0.210254,-0.49219 0.492188,-0.49219 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98699999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<text
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="69.980721"
y="150.38542"
id="text24965"><tspan
dy="-2"
dx="0"
sodipodi:role="line"
id="tspan24961"
x="69.980721"
y="150.38542"
style="text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill-opacity:1;stroke-width:0.26458332">fs</tspan><tspan
dx="0 0 -0.27000001"
id="tspan24963"
sodipodi:role="line"
x="69.980721"
y="157"
style="text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill-opacity:1;stroke-width:0.26458332"> fw</tspan></text>
<g
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
transform="translate(-1.937002)"
id="g24969"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.36171436px;line-height:5.85107136px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.23404284"
aria-label="{">
<path
sodipodi:nodetypes="ccssccsssccccssccccssscc"
inkscape:connector-curvature="0"
id="path24967"
style="font-size:18.72342873px;fill:#000000;fill-opacity:1;stroke-width:0.23404284"
d="m 67.678074,141.482 c -0.798867,0.0624 -1.915603,0.38946 -2.290072,0.80139 -0.361986,0.41191 -0.543,1.06141 -0.543,1.94766 v 1.29191 c 0,1.04851 -0.199567,1.82824 -0.599,2.34001 -0.386951,0.51177 -1.010722,0.82383 -1.872,0.93617 0.848795,0.11234 1.472567,0.41816 1.872,0.91745 0.399433,0.49929 0.599,1.22951 0.599,2.19064 v 1.38554 c 0,0.88624 0.193496,1.5478 0.543,1.98468 0.349504,0.44936 1.453759,0.79514 2.290072,0.85755 v 0.86501 c -1.260711,-0.0749 -2.215606,-0.38696 -2.864685,-0.93618 -0.636597,-0.53673 -0.954895,-1.55404 -0.954895,-3.05192 v -1.23574 c 0,-0.84879 -0.205958,-1.44794 -0.617873,-1.79745 -0.399433,-0.36199 -1.017306,-0.59291 -1.853619,-0.69277 v -0.95489 c 0.761419,-0.0624 1.360569,-0.28084 1.797449,-0.65532 0.449362,-0.38695 0.674043,-0.91745 0.674043,-1.59149 v -1.66639 c 0,-1.26071 0.293334,-2.19064 0.880001,-2.78979 0.586667,-0.59915 1.566527,-0.93617 2.939579,-1.01107 z" />
</g>
<g
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
aria-label="{"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.36171436px;line-height:5.85107136px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.23404284"
id="g24973"
transform="rotate(180,73.264036,148.80851)">
<path
d="m 67.678074,141.482 c -0.798867,0.0624 -1.915603,0.38946 -2.290072,0.80139 -0.361986,0.41191 -0.543,1.06141 -0.543,1.94766 v 1.29191 c 0,1.04851 -0.199567,1.82824 -0.599,2.34001 -0.386951,0.51177 -1.010722,0.82383 -1.872,0.93617 0.848795,0.11234 1.472567,0.41816 1.872,0.91745 0.399433,0.49929 0.599,1.22951 0.599,2.19064 v 1.38554 c 0,0.88624 0.193496,1.5478 0.543,1.98468 0.349504,0.44936 1.453759,0.79514 2.290072,0.85755 v 0.86501 c -1.260711,-0.0749 -2.215606,-0.38696 -2.864685,-0.93618 -0.636597,-0.53673 -0.954895,-1.55404 -0.954895,-3.05192 v -1.23574 c 0,-0.84879 -0.205958,-1.44794 -0.617873,-1.79745 -0.399433,-0.36199 -1.017306,-0.59291 -1.853619,-0.69277 v -0.95489 c 0.761419,-0.0624 1.360569,-0.28084 1.797449,-0.65532 0.449362,-0.38695 0.674043,-0.91745 0.674043,-1.59149 v -1.66639 c 0,-1.26071 0.293334,-2.19064 0.880001,-2.78979 0.586667,-0.59915 1.566527,-0.93617 2.939579,-1.01107 z"
style="font-size:18.72342873px;fill:#000000;fill-opacity:1;stroke-width:0.23404284"
id="path24971"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccssccsssccccssccccssscc" />
</g>
</g>
</clipPath>
<meshgradient
inkscape:collect="always"
id="meshgradient24977"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.6672918,0,0,1.5637161,15.752536,45.300004)"
x="42.742184"
y="140.617">
<meshrow
id="meshrow24989">
<meshpatch
id="meshpatch24987">
<stop
path="c 19.7036,0 39.4071,0 59.1107,0"
style="stop-color:#00519e;stop-opacity:1"
id="stop24979" />
<stop
path="c 0,5.46099 0,10.922 0,16.383"
style="stop-color:#00beff;stop-opacity:1"
id="stop24981" />
<stop
path="c -19.7036,0 -39.4071,0 -59.1107,0"
style="stop-color:#00beff;stop-opacity:1"
id="stop24983" />
<stop
path="c 0,-5.46099 0,-10.922 0,-16.383"
style="stop-color:#00519e;stop-opacity:1"
id="stop24985" />
</meshpatch>
</meshrow>
</meshgradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2"
inkscape:cx="110.06798"
inkscape:cy="138.03068"
inkscape:document-units="mm"
inkscape:current-layer="layer16"
showgrid="false"
inkscape:window-width="1536"
inkscape:window-height="801"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true"
inkscape:pagecheckerboard="true" />
<metadata
id="metadata22811">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer13"
inkscape:label="Corporate_Uni_Stuttgart"
transform="translate(0,16.383002)"
style="display:none;filter:url(#filter23683)">
<rect
style="opacity:1;fill:#3e444c;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23621"
width="8.499999"
height="8.499999"
x="-8.499999"
y="42.5" />
<rect
y="34"
x="-8.499999"
height="8.499999"
width="8.499999"
id="rect23623"
style="opacity:1;fill:#00519e;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:#00beff;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23625"
width="8.499999"
height="8.499999"
x="-8.499999"
y="25.5" />
<rect
style="opacity:1;fill:#009e51;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23629"
width="8.499999"
height="8.499999"
x="-50.999996"
y="34" />
<rect
y="25.5"
x="-50.999996"
height="8.499999"
width="8.499999"
id="rect23631"
style="opacity:1;fill:#00ffbe;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
y="34"
x="-16.999998"
height="8.499999"
width="8.499999"
id="rect23635"
style="opacity:1;fill:#51009e;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:#be00ff;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23637"
width="8.499999"
height="8.499999"
x="-16.999998"
y="25.5" />
<rect
y="42.5"
x="-50.999996"
height="8.499999"
width="8.499999"
id="rect23639"
style="opacity:1;fill:#3e4c44;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:#443e4c;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23641"
width="8.499999"
height="8.499999"
x="-16.999998"
y="42.5" />
<rect
y="42.5"
x="-33.999996"
height="8.499999"
width="8.499999"
id="rect23655"
style="opacity:1;fill:#4c443e;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:#9e5100;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23657"
width="8.499999"
height="8.499999"
x="-33.999996"
y="34" />
<rect
y="25.5"
x="-33.999996"
height="8.499999"
width="8.499999"
id="rect23659"
style="opacity:1;fill:#ffbe00;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:#4c3e44;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23661"
width="8.499999"
height="8.499999"
x="-25.499998"
y="42.5" />
<rect
y="34"
x="-25.499998"
height="8.499999"
width="8.499999"
id="rect23663"
style="opacity:1;fill:#9e0051;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:#ff00be;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23665"
width="8.499999"
height="8.499999"
x="-25.499998"
y="25.5" />
<rect
y="42.5"
x="-42.499996"
height="8.499999"
width="8.499999"
id="rect23667"
style="opacity:1;fill:#444c3e;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:#519e00;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23669"
width="8.499999"
height="8.499999"
x="-42.499996"
y="34" />
<rect
y="25.5"
x="-42.499996"
height="8.499999"
width="8.499999"
id="rect23671"
style="opacity:1;fill:#beff00;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:#006cb6;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23673"
width="8.499999"
height="8.499999"
x="-8.499999"
y="17" />
<rect
y="8.500001"
x="-8.499999"
height="8.499999"
width="8.499999"
id="rect23713"
style="opacity:1;fill:#0087ce;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" />
<rect
style="opacity:1;fill:#00a3e7;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
id="rect23715"
width="8.499999"
height="8.499999"
x="-8.499999"
y="1.9073486e-006" />
</g>
<g
inkscape:groupmode="layer"
id="layer10"
inkscape:label="Logo_mono_black"
transform="translate(0,-229.617)"
style="display:inline">
<g
style="display:inline"
id="g23526"
transform="translate(-42.742184,139.99998)">
<path
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98699999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 48.300305,143.44076 c -0.811661,0 -1.109125,0.75874 -1.480469,1.48047 l -4.00014,7.77454 c -0.371344,0.72173 0.668807,1.48047 1.480468,1.48047 h 9.625183 c 0.811661,0 1.109108,-0.75875 1.480469,-1.48047 l 4.00036,-7.77454 c 0.371361,-0.72172 -0.668808,-1.48047 -1.480469,-1.48047 z m 0,0.98828 h 9.625402 c 0.281935,0 0.621179,0.2415 0.492187,0.49219 l -4.00036,7.77454 c -0.128993,0.25069 -0.210251,0.49218 -0.492187,0.49218 h -9.625181 c -0.281935,0 -0.621175,-0.24149 -0.492189,-0.49218 l 4.000141,-7.77454 c 0.128986,-0.25069 0.210253,-0.49219 0.492187,-0.49219 z"
id="path23506"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssssssssssssssssss" />
<path
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
sodipodi:nodetypes="ssssssssssssssssss"
inkscape:connector-curvature="0"
id="path23508"
d="m 90.668816,143.44076 c -0.811661,0 -1.109125,0.75874 -1.480469,1.48047 l -4.00014,7.77454 c -0.371344,0.72173 0.668808,1.48047 1.480469,1.48047 h 9.625909 c 0.81166,0 1.109109,-0.75875 1.48047,-1.48047 l 4.000355,-7.77454 c 0.37136,-0.72172 -0.66881,-1.48047 -1.48046,-1.48047 z m 0,0.98828 h 9.626134 c 0.28193,0 0.62117,0.24151 0.49218,0.49219 l -4.000365,7.77454 c -0.128993,0.25069 -0.21025,0.49218 -0.49218,0.49218 h -9.625909 c -0.281935,0 -0.621174,-0.24149 -0.492188,-0.49218 l 4.00014,-7.77454 c 0.128986,-0.25069 0.210254,-0.49219 0.492188,-0.49219 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98699999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<text
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="69.980721"
y="150.38542"
id="text23365-1"><tspan
dy="-2"
dx="0"
sodipodi:role="line"
id="tspan23363-7"
x="69.980721"
y="150.38542"
style="text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.26458332">fs</tspan><tspan
dx="0 0 -0.27000001"
id="tspan23367-0"
sodipodi:role="line"
x="69.980721"
y="157"
style="text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.26458332"> fw</tspan></text>
<g
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
transform="translate(-1.937002)"
id="text23461"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.36171436px;line-height:5.85107136px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.23404284"
aria-label="{">
<path
sodipodi:nodetypes="ccssccsssccccssccccssscc"
inkscape:connector-curvature="0"
id="path23467"
style="font-size:18.72342873px;fill:#000000;fill-opacity:1;stroke-width:0.23404284"
d="m 67.678074,141.482 c -0.798867,0.0624 -1.915603,0.38946 -2.290072,0.80139 -0.361986,0.41191 -0.543,1.06141 -0.543,1.94766 v 1.29191 c 0,1.04851 -0.199567,1.82824 -0.599,2.34001 -0.386951,0.51177 -1.010722,0.82383 -1.872,0.93617 0.848795,0.11234 1.472567,0.41816 1.872,0.91745 0.399433,0.49929 0.599,1.22951 0.599,2.19064 v 1.38554 c 0,0.88624 0.193496,1.5478 0.543,1.98468 0.349504,0.44936 1.453759,0.79514 2.290072,0.85755 v 0.86501 c -1.260711,-0.0749 -2.215606,-0.38696 -2.864685,-0.93618 -0.636597,-0.53673 -0.954895,-1.55404 -0.954895,-3.05192 v -1.23574 c 0,-0.84879 -0.205958,-1.44794 -0.617873,-1.79745 -0.399433,-0.36199 -1.017306,-0.59291 -1.853619,-0.69277 v -0.95489 c 0.761419,-0.0624 1.360569,-0.28084 1.797449,-0.65532 0.449362,-0.38695 0.674043,-0.91745 0.674043,-1.59149 v -1.66639 c 0,-1.26071 0.293334,-2.19064 0.880001,-2.78979 0.586667,-0.59915 1.566527,-0.93617 2.939579,-1.01107 z" />
</g>
<g
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
aria-label="{"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.36171436px;line-height:5.85107136px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.23404284"
id="g23472"
transform="rotate(180,73.264036,148.80851)">
<path
d="m 67.678074,141.482 c -0.798867,0.0624 -1.915603,0.38946 -2.290072,0.80139 -0.361986,0.41191 -0.543,1.06141 -0.543,1.94766 v 1.29191 c 0,1.04851 -0.199567,1.82824 -0.599,2.34001 -0.386951,0.51177 -1.010722,0.82383 -1.872,0.93617 0.848795,0.11234 1.472567,0.41816 1.872,0.91745 0.399433,0.49929 0.599,1.22951 0.599,2.19064 v 1.38554 c 0,0.88624 0.193496,1.5478 0.543,1.98468 0.349504,0.44936 1.453759,0.79514 2.290072,0.85755 v 0.86501 c -1.260711,-0.0749 -2.215606,-0.38696 -2.864685,-0.93618 -0.636597,-0.53673 -0.954895,-1.55404 -0.954895,-3.05192 v -1.23574 c 0,-0.84879 -0.205958,-1.44794 -0.617873,-1.79745 -0.399433,-0.36199 -1.017306,-0.59291 -1.853619,-0.69277 v -0.95489 c 0.761419,-0.0624 1.360569,-0.28084 1.797449,-0.65532 0.449362,-0.38695 0.674043,-0.91745 0.674043,-1.59149 v -1.66639 c 0,-1.26071 0.293334,-2.19064 0.880001,-2.78979 0.586667,-0.59915 1.566527,-0.93617 2.939579,-1.01107 z"
style="font-size:18.72342873px;fill:#000000;fill-opacity:1;stroke-width:0.23404284"
id="path23470"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccssccsssccccssccccssscc" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer12"
inkscape:label="Logo_mono_white"
style="display:inline"
transform="translate(0,16.383002)">
<g
id="g23618">
<path
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98699999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 5.558122,20.44074 c -0.811661,0 -1.109125,0.75874 -1.480469,1.48047 l -4.00014,7.77454 c -0.371344,0.72173 0.668807,1.48047 1.480468,1.48047 h 9.625183 c 0.811661,0 1.109108,-0.75875 1.480469,-1.48047 l 4.00036,-7.77454 c 0.371361,-0.72172 -0.668808,-1.48047 -1.480469,-1.48047 z m 0,0.98828 h 9.625402 c 0.281935,0 0.621179,0.2415 0.492187,0.49219 l -4.00036,7.77454 c -0.128993,0.25069 -0.210251,0.49218 -0.492187,0.49218 H 1.557983 c -0.281935,0 -0.621175,-0.24149 -0.492189,-0.49218 l 4.000141,-7.77454 c 0.128986,-0.25069 0.210253,-0.49219 0.492187,-0.49219 z"
id="path23560"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssssssssssssssssss" />
<path
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
sodipodi:nodetypes="ssssssssssssssssss"
inkscape:connector-curvature="0"
id="path23562"
d="m 47.926633,20.44074 c -0.811661,0 -1.109125,0.75874 -1.480469,1.48047 l -4.00014,7.77454 c -0.371344,0.72173 0.668808,1.48047 1.480469,1.48047 h 9.625909 c 0.81166,0 1.109109,-0.75875 1.48047,-1.48047 l 4.000355,-7.77454 c 0.37136,-0.72172 -0.66881,-1.48047 -1.48046,-1.48047 z m 0,0.98828 h 9.626134 c 0.28193,0 0.62117,0.24151 0.49218,0.49219 l -4.000365,7.77454 c -0.128993,0.25069 -0.21025,0.49218 -0.49218,0.49218 h -9.625909 c -0.281935,0 -0.621174,-0.24149 -0.492188,-0.49218 l 4.00014,-7.77454 c 0.128986,-0.25069 0.210254,-0.49219 0.492188,-0.49219 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98699999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<text
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="27.238537"
y="27.385403"
id="text23568"><tspan
dy="-2"
dx="0"
sodipodi:role="line"
id="tspan23564"
x="27.238537"
y="27.385403"
style="text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332">fs</tspan><tspan
dx="0 0 -0.27000001"
id="tspan23566"
sodipodi:role="line"
x="27.238537"
y="33.999985"
style="text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;stroke-width:0.26458332"> fw</tspan></text>
<g
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
transform="translate(-44.679185,-123.00002)"
id="g23572"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.36171436px;line-height:5.85107136px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.23404284"
aria-label="{">
<path
sodipodi:nodetypes="ccssccsssccccssccccssscc"
inkscape:connector-curvature="0"
id="path23570"
style="font-size:18.72342873px;fill:#ffffff;fill-opacity:1;stroke-width:0.23404284"
d="m 67.678074,141.482 c -0.798867,0.0624 -1.915603,0.38946 -2.290072,0.80139 -0.361986,0.41191 -0.543,1.06141 -0.543,1.94766 v 1.29191 c 0,1.04851 -0.199567,1.82824 -0.599,2.34001 -0.386951,0.51177 -1.010722,0.82383 -1.872,0.93617 0.848795,0.11234 1.472567,0.41816 1.872,0.91745 0.399433,0.49929 0.599,1.22951 0.599,2.19064 v 1.38554 c 0,0.88624 0.193496,1.5478 0.543,1.98468 0.349504,0.44936 1.453759,0.79514 2.290072,0.85755 v 0.86501 c -1.260711,-0.0749 -2.215606,-0.38696 -2.864685,-0.93618 -0.636597,-0.53673 -0.954895,-1.55404 -0.954895,-3.05192 v -1.23574 c 0,-0.84879 -0.205958,-1.44794 -0.617873,-1.79745 -0.399433,-0.36199 -1.017306,-0.59291 -1.853619,-0.69277 v -0.95489 c 0.761419,-0.0624 1.360569,-0.28084 1.797449,-0.65532 0.449362,-0.38695 0.674043,-0.91745 0.674043,-1.59149 v -1.66639 c 0,-1.26071 0.293334,-2.19064 0.880001,-2.78979 0.586667,-0.59915 1.566527,-0.93617 2.939579,-1.01107 z" />
</g>
<g
inkscape:export-ydpi="499.60001"
inkscape:export-xdpi="499.60001"
aria-label="{"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.36171436px;line-height:5.85107136px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.23404284"
id="g23576"
transform="rotate(180,51.892944,87.3085)">
<path
d="m 67.678074,141.482 c -0.798867,0.0624 -1.915603,0.38946 -2.290072,0.80139 -0.361986,0.41191 -0.543,1.06141 -0.543,1.94766 v 1.29191 c 0,1.04851 -0.199567,1.82824 -0.599,2.34001 -0.386951,0.51177 -1.010722,0.82383 -1.872,0.93617 0.848795,0.11234 1.472567,0.41816 1.872,0.91745 0.399433,0.49929 0.599,1.22951 0.599,2.19064 v 1.38554 c 0,0.88624 0.193496,1.5478 0.543,1.98468 0.349504,0.44936 1.453759,0.79514 2.290072,0.85755 v 0.86501 c -1.260711,-0.0749 -2.215606,-0.38696 -2.864685,-0.93618 -0.636597,-0.53673 -0.954895,-1.55404 -0.954895,-3.05192 v -1.23574 c 0,-0.84879 -0.205958,-1.44794 -0.617873,-1.79745 -0.399433,-0.36199 -1.017306,-0.59291 -1.853619,-0.69277 v -0.95489 c 0.761419,-0.0624 1.360569,-0.28084 1.797449,-0.65532 0.449362,-0.38695 0.674043,-0.91745 0.674043,-1.59149 v -1.66639 c 0,-1.26071 0.293334,-2.19064 0.880001,-2.78979 0.586667,-0.59915 1.566527,-0.93617 2.939579,-1.01107 z"
style="font-size:18.72342873px;fill:#ffffff;fill-opacity:1;stroke-width:0.23404284"
id="path23574"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccssccsssccccssccccssscc" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer14"
inkscape:label="Logo_colored"
style="display:inline"
transform="translate(0,17.000002)">
<g
id="g24826">
<path
sodipodi:nodetypes="ssssssssssssssssss"
inkscape:connector-curvature="0"
id="path23538"
d="m 5.558122,19.823743 c -0.811661,0 -1.109125,0.75874 -1.480469,1.48047 l -4.00014,7.77454 c -0.371344,0.72173 0.668807,1.48047 1.480468,1.48047 h 9.625183 c 0.811661,0 1.109108,-0.75875 1.480469,-1.48047 l 4.00036,-7.77454 c 0.371361,-0.72172 -0.668808,-1.48047 -1.480469,-1.48047 z m 0,0.98828 h 9.625402 c 0.281935,0 0.621179,0.2415 0.492187,0.49219 l -4.00036,7.77454 c -0.128993,0.25069 -0.210251,0.49218 -0.492187,0.49218 H 1.557983 c -0.281935,0 -0.621175,-0.24149 -0.492189,-0.49218 l 4.000141,-7.77454 c 0.128986,-0.25069 0.210253,-0.49219 0.492187,-0.49219 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#00beff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98699999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:export-xdpi="499.60001"
inkscape:export-ydpi="499.60001"
transform="translate(0,-17.000002)" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#00beff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98699999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 47.926633,19.823743 c -0.811661,0 -1.109125,0.75874 -1.480469,1.48047 l -4.00014,7.77454 c -0.371344,0.72173 0.668808,1.48047 1.480469,1.48047 h 9.625909 c 0.81166,0 1.109109,-0.75875 1.48047,-1.48047 l 4.000355,-7.77454 c 0.37136,-0.72172 -0.66881,-1.48047 -1.48046,-1.48047 z m 0,0.98828 h 9.626134 c 0.28193,0 0.62117,0.24151 0.49218,0.49219 l -4.000365,7.77454 c -0.128993,0.25069 -0.21025,0.49218 -0.49218,0.49218 h -9.625909 c -0.281935,0 -0.621174,-0.24149 -0.492188,-0.49218 l 4.00014,-7.77454 c 0.128986,-0.25069 0.210254,-0.49219 0.492188,-0.49219 z"
id="path23540"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssssssssssssssssss"
inkscape:export-xdpi="499.60001"
inkscape:export-ydpi="499.60001"
transform="translate(0,-17.000002)" />
<g
aria-label="{"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.36171436px;line-height:5.85107136px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;display:inline;opacity:0.98999999;fill:#00519e;fill-opacity:1;stroke:none;stroke-width:0.23404284;enable-background:new"
id="g23550"
transform="translate(-44.679185,-140.61702)"
inkscape:export-xdpi="499.60001"
inkscape:export-ydpi="499.60001">
<path
d="m 67.678074,141.482 c -0.798867,0.0624 -1.915603,0.38946 -2.290072,0.80139 -0.361986,0.41191 -0.543,1.06141 -0.543,1.94766 v 1.29191 c 0,1.04851 -0.199567,1.82824 -0.599,2.34001 -0.386951,0.51177 -1.010722,0.82383 -1.872,0.93617 0.848795,0.11234 1.472567,0.41816 1.872,0.91745 0.399433,0.49929 0.599,1.22951 0.599,2.19064 v 1.38554 c 0,0.88624 0.193496,1.5478 0.543,1.98468 0.349504,0.44936 1.453759,0.79514 2.290072,0.85755 v 0.86501 c -1.260711,-0.0749 -2.215606,-0.38696 -2.864685,-0.93618 -0.636597,-0.53673 -0.954895,-1.55404 -0.954895,-3.05192 v -1.23574 c 0,-0.84879 -0.205958,-1.44794 -0.617873,-1.79745 -0.399433,-0.36199 -1.017306,-0.59291 -1.853619,-0.69277 v -0.95489 c 0.761419,-0.0624 1.360569,-0.28084 1.797449,-0.65532 0.449362,-0.38695 0.674043,-0.91745 0.674043,-1.59149 v -1.66639 c 0,-1.26071 0.293334,-2.19064 0.880001,-2.78979 0.586667,-0.59915 1.566527,-0.93617 2.939579,-1.01107 z"
style="font-size:18.72342873px;fill:#00519e;fill-opacity:1;stroke-width:0.23404284"
id="path23548"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccssccsssccccssccccssscc" />
</g>
<g
transform="rotate(180,51.892943,78.500001)"
id="g23554"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.36171436px;line-height:5.85107136px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';letter-spacing:0px;word-spacing:0px;display:inline;opacity:0.98999999;fill:#00519e;fill-opacity:1;stroke:none;stroke-width:0.23404284;enable-background:new"
aria-label="{"
inkscape:export-xdpi="499.60001"
inkscape:export-ydpi="499.60001">
<path
sodipodi:nodetypes="ccssccsssccccssccccssscc"
inkscape:connector-curvature="0"
id="path23552"
style="font-size:18.72342873px;fill:#00519e;fill-opacity:1;stroke-width:0.23404284"
d="m 67.678074,141.482 c -0.798867,0.0624 -1.915603,0.38946 -2.290072,0.80139 -0.361986,0.41191 -0.543,1.06141 -0.543,1.94766 v 1.29191 c 0,1.04851 -0.199567,1.82824 -0.599,2.34001 -0.386951,0.51177 -1.010722,0.82383 -1.872,0.93617 0.848795,0.11234 1.472567,0.41816 1.872,0.91745 0.399433,0.49929 0.599,1.22951 0.599,2.19064 v 1.38554 c 0,0.88624 0.193496,1.5478 0.543,1.98468 0.349504,0.44936 1.453759,0.79514 2.290072,0.85755 v 0.86501 c -1.260711,-0.0749 -2.215606,-0.38696 -2.864685,-0.93618 -0.636597,-0.53673 -0.954895,-1.55404 -0.954895,-3.05192 v -1.23574 c 0,-0.84879 -0.205958,-1.44794 -0.617873,-1.79745 -0.399433,-0.36199 -1.017306,-0.59291 -1.853619,-0.69277 v -0.95489 c 0.761419,-0.0624 1.360569,-0.28084 1.797449,-0.65532 0.449362,-0.38695 0.674043,-0.91745 0.674043,-1.59149 v -1.66639 c 0,-1.26071 0.293334,-2.19064 0.880001,-2.78979 0.586667,-0.59915 1.566527,-0.93617 2.939579,-1.01107 z" />
</g>
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path23705"
d="m 24.042453,7.7684013 h 0.98425 V 6.1909995 h -0.98425 z"
style="display:inline;fill:#00519e;fill-opacity:1;stroke:none;stroke-width:0.15297562px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path23707"
d="m 26.264953,3.0725683 -2.2225,3e-7 v 0.7196666 l 2.2225,-3e-7 z"
style="display:inline;fill:#0087ce;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
transform="translate(0,-0.617)" />
<path
inkscape:connector-curvature="0"
id="path23709"
d="m 22.994703,3.0725686 v 0.7196666 h 1.04775 V 3.0725686 Z"
style="display:inline;fill:none;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
transform="translate(0,-0.617)" />
<path
id="path23719"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#00beff;fill-opacity:1;stroke:none;stroke-width:0.26458332"
d="m 26.41312,1.4850686 c -0.1905,-0.014111 -0.373945,-0.021167 -0.550334,-0.021167 -0.282222,0 -0.493889,0.045861 -0.635,0.1375834 -0.772583,-0.62441639 0,0 -0.772583,-0.62441639 0.282222,-0.23988888 0.663222,-0.35983332 1.143,-0.35983332 0.141111,0 0.278695,0.007056 0.41275,0.0211667 0.141111,0.0141111 0.275167,0.03175 0.402167,0.0529167 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csccsccc"
transform="translate(0,-0.617)" />
<path
sodipodi:nodetypes="csccscc"
inkscape:connector-curvature="0"
d="m 25.227786,1.601485 c -0.134055,0.091722 -0.201083,0.2751666 -0.201083,0.5503333 v 0.92075 l -0.98425,3e-7 v -0.85725 c 0,-0.5926667 0.137583,-1.0054167 0.41275,-1.23824999 0.772583,0.62441639 0,0 0.772583,0.62441639 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#00a3e7;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="path23717"
transform="translate(0,-0.617)" />
<path
inkscape:connector-curvature="0"
id="path23727"
d="m 22.994703,2.4555686 v 0.7196666 h 1.04775 V 2.4555686 h -1.04775"
style="fill:#00beff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path23729"
d="m 24.042453,6.1909994 h 0.98425 V 3.1752349 l -0.98425,3e-7 v 3.0157642"
style="fill:#006cb6;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path23731"
d="m 24.02759,11.070149 v 0.719667 h 2.032 v -0.719667 z"
style="fill:#00beff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path23733"
d="m 27.29784,11.070149 v 0.719667 h -1.23825 v -0.719667"
style="fill:#00a3e7;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path23735"
d="m 25.07534,13.366982 h 0.98425 v 3.016 h -0.98425 z"
style="fill:#00beff;fill-opacity:1;stroke:none;stroke-width:0.21439861px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path23737"
d="m 25.07534,11.789816 h 0.98425 v 1.577166 h -0.98425 v -1.577166"
style="fill:#00a3e7;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cscsccscsccc"
d="m 27.446007,10.099652 c -0.1905,-0.01411 -0.373945,-0.02117 -0.550334,-0.02117 -0.282222,0 -0.493889,0.04586 -0.635,0.137584 -0.134055,0.09172 -0.201083,0.275166 -0.201083,0.550333 v 0.92075 h -0.98425 v -0.85725 c 0,-0.592667 0.137583,-1.0054166 0.41275,-1.2382499 0.282222,-0.2398889 0.663222,-0.3598333 1.143,-0.3598333 0.141111,0 0.278695,0.00706 0.41275,0.021167 0.141111,0.014111 0.275167,0.03175 0.402167,0.052917 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#006cb6;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="path23739"
inkscape:connector-curvature="0"
transform="translate(0,-0.617)" />
<path
d="m 28.921204,8.5335684 c -0.677333,0 -1.199444,-0.1481667 -1.566333,-0.4445 -0.359833,-0.3033889 -0.53975,-0.7307356 -0.53975,-1.2810689 l 1.04775,4.856e-4 c 0,0.3033889 0.09878,0.53975 0.296333,0.7090833 0.204611,0.1693333 0.497417,0.254 0.878417,0.254 0,0 0,0 -0.116417,0.762 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#00beff;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="path23748"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc"
transform="translate(0,-0.617)" />
<path
d="m 29.799621,5.3903185 c 0.465667,0.1128889 0.811389,0.28575 1.037166,0.5185833 0.232833,0.2257778 0.34925,0.5326945 0.34925,0.92075 0,0.5221111 -0.197555,0.9383888 -0.592666,1.2488333 -0.395111,0.3033889 -0.9525,0.4550833 -1.672167,0.4550833 0.116417,-0.762 0,0 0.116417,-0.762 0.359833,0 0.631472,-0.077611 0.814917,-0.2328333 0.183444,-0.1552222 0.275166,-0.3563055 0.275166,-0.60325 0,-0.3175 -0.165805,-0.5221111 -0.497416,-0.6138333 0.169333,-0.9313333 0,0 0.169333,-0.9313333 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#0087ce;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="path23752"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccccscc"
transform="translate(0,-0.617)" />
<path
d="m 27.926371,4.4378185 c 0,0.3245555 0.215194,0.53975 0.645583,0.6455833 l 1.227667,0.3069167 c -0.169333,0.9313333 0,0 -0.169333,0.9313333 C 29.298677,6.222874 28.910621,6.1240962 28.466121,6.0253185 28.014566,5.9265407 27.644149,5.7677907 27.354871,5.5490685 27.065593,5.3303463 26.920954,4.9987352 26.920954,4.5542352 c 1.005417,-0.1164167 0,0 1.005417,-0.1164167 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#00a3e7;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="path23755"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccscc"
transform="translate(0,-0.617)" />
<path
d="m 31.048454,4.5436518 h -1.016 v -0.0635 c 0,-0.5362222 -0.342194,-0.8043333 -1.026583,-0.8043333 -0.338667,0 -0.60325,0.067028 -0.79375,0.2010834 -0.1905,0.127 -0.28575,0.3139722 -0.28575,0.5609166 -1.005417,0.1164167 0,0 -1.005417,0.1164167 0,-0.4797778 0.1905,-0.8678334 0.5715,-1.1641667 0.388056,-0.2963333 0.889001,-0.4444999 1.502834,-0.4444999 0.578555,0 1.065388,0.1199444 1.460499,0.3598333 0.395111,0.2328333 0.592667,0.5961944 0.592667,1.0900833 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#006cb6;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="path23758"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccssccccscsc"
transform="translate(0,-0.617)" />
<path
sodipodi:nodetypes="cccccc"
transform="translate(0,-0.617)"
inkscape:connector-curvature="0"
id="path23764"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#00beff;fill-opacity:1;stroke:none;stroke-width:0.26458332"
d="m 33.742924,15.878152 1.3335,-4.191 h 1.026583 l -1.87325,5.312833 h -1.142999 c 0.656166,-1.121833 0,0 0.656166,-1.121833 z" />
<path
sodipodi:nodetypes="ccccc"
d="m 32.536424,11.070152 1.2065,4.191 c -0.656166,1.121833 0,0 -0.656166,1.121833 l -1.248834,-4.370916 c 0.6985,-0.941917 0,0 0.6985,-0.941917 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#00a3e7;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="path23766"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccccc"
transform="translate(0,-0.617)"
inkscape:connector-curvature="0"
id="path23768"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#0087ce;fill-opacity:1;stroke:none;stroke-width:0.26458332"
d="m 29.890591,15.920485 1.344083,-4.233333 h 1.30175 c -0.6985,0.941917 0,0 -0.6985,0.941917 l -1.386416,4.370916 h -1.17475 c 0.613833,-1.0795 0,0 0.613833,-1.0795 z" />
<path
sodipodi:nodetypes="ccccc"
d="m 28.610008,11.687152 1.280583,4.233333 c -0.613833,1.0795 0,0 -0.613833,1.0795 l -1.756834,-5.312833 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:6.61458349px;font-family:'Univers for UniS 55 Roman';-inkscape-font-specification:'Univers for UniS 55 Roman, ';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;opacity:0.98999999;fill:#00519e;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="path23770"
inkscape:connector-curvature="0"
transform="translate(0,-0.617)" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer16"
inkscape:label="Logo_gradient"
style="display:inline">
<rect
style="display:inline;opacity:1;fill:url(#meshgradient23819);fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;enable-background:new"
id="rect23817"
width="59.111"
height="16.382999"
x="-1.110223e-016"
y="3.8147118e-006"
clip-path="url(#clipPath24955)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 58 KiB

BIN
logo/FSFW_Logo_V3_bw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,42 +1,76 @@
#include "MessageQueue.h" #include "MessageQueue.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManagerIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
// TODO I guess we should have a way of checking if we are in an ISR and then use the "fromISR" versions of all calls // TODO I guess we should have a way of checking if we are in an ISR and then
// use the "fromISR" versions of all calls
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : // As a first step towards this, introduces system context variable which needs
defaultDestination(0),lastPartner(0) { // to be switched manually
handle = xQueueCreate(message_depth, max_message_size); // Haven't found function to find system context.
if (handle == NULL) { MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
sif::error << "MessageQueue creation failed" << std::endl; maxMessageSize(maxMessageSize) {
handle = xQueueCreate(messageDepth, maxMessageSize);
if (handle == nullptr) {
sif::error << "MessageQueue::MessageQueue Creation failed" << std::endl;
} }
} }
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {
if (handle != NULL) { if (handle != nullptr) {
vQueueDelete(handle); vQueueDelete(handle);
} }
} }
void MessageQueue::switchSystemContext(CallContext callContext) {
this->callContext = callContext;
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault) { MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
} }
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId()); return sendToDefaultFrom(message, this->getId());
} }
ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
if (this->lastPartner != 0) { MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault);
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != MessageQueueIF::NO_QUEUE) {
return sendMessageFrom(this->lastPartner, message, this->getId()); return sendMessageFrom(this->lastPartner, message, this->getId());
} else { } else {
return NO_REPLY_PARTNER; return NO_REPLY_PARTNER;
} }
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault,
callContext);
}
ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) {
if (result != pdPASS) {
if (not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter = objectManager->
get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent();
}
}
return MessageQueueIF::FULL;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) { MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message); ReturnValue_t status = this->receiveMessage(message);
if(status == HasReturnvaluesIF::RETURN_OK) { if(status == HasReturnvaluesIF::RETURN_OK) {
@ -45,8 +79,9 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message,
return status; return status;
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
BaseType_t result = xQueueReceive(handle,reinterpret_cast<void*>(message->getBuffer()), 0); BaseType_t result = xQueueReceive(handle,reinterpret_cast<void*>(
message->getBuffer()), 0);
if (result == pdPASS){ if (result == pdPASS){
this->lastPartner = message->getSender(); this->lastPartner = message->getSender();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
@ -67,51 +102,55 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
} }
MessageQueueId_t MessageQueue::getId() const { MessageQueueId_t MessageQueue::getId() const {
return (MessageQueueId_t) handle; return reinterpret_cast<MessageQueueId_t>(handle);
} }
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true;
this->defaultDestination = defaultDestination; this->defaultDestination = defaultDestination;
} }
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault);
}
MessageQueueId_t MessageQueue::getDefaultDestination() const { MessageQueueId_t MessageQueue::getDefaultDestination() const {
return defaultDestination; return defaultDestination;
} }
bool MessageQueue::isDefaultDestinationSet() const { bool MessageQueue::isDefaultDestinationSet() const {
return 0; return defaultDestinationSet;
} }
// static core function to send messages.
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessage *message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault, CallContext callContext) {
BaseType_t result = pdFALSE;
QueueHandle_t destination = nullptr;
if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) {
return MessageQueueIF::DESTINVATION_INVALID;
}
else {
destination = reinterpret_cast<QueueHandle_t>(sendTo);
}
message->setSender(sentFrom); message->setSender(sentFrom);
BaseType_t result = xQueueSendToBack(reinterpret_cast<QueueHandle_t>(sendTo),
reinterpret_cast<const void*>(message->getBuffer()), 0);
if (result != pdPASS) {
if (!ignoreFault) {
InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != NULL) {
internalErrorReporter->queueMessageNotSent();
}
}
return MessageQueueIF::FULL;
}
return HasReturnvaluesIF::RETURN_OK;
if(callContext == CallContext::TASK) {
result = xQueueSendToBack(destination,
static_cast<const void*>(message->getBuffer()), 0);
}
else {
/* If the call context is from an interrupt,
* request a context switch if a higher priority task
* was blocked by the interrupt. */
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
result = xQueueSendFromISR(reinterpret_cast<QueueHandle_t>(sendTo),
static_cast<const void*>(message->getBuffer()),
&xHigherPriorityTaskWoken);
if(xHigherPriorityTaskWoken == pdTRUE) {
TaskManagement::requestContextSwitch(callContext);
}
}
return handleSendResult(result, ignoreFault);
} }

View File

@ -1,159 +1,150 @@
#ifndef MESSAGEQUEUE_H_ #ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
#define MESSAGEQUEUE_H_ #define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h" #include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h" #include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessage.h" #include "../../ipc/MessageQueueMessageIF.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include <FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <queue.h> #include <freertos/queue.h>
#include <fsfw/ipc/MessageQueueMessage.h>
//TODO this class assumes that MessageQueueId_t is the same size as void* (the FreeRTOS handle type), compiler will catch this but it might be nice to have something checking or even an always working solution // TODO: this class assumes that MessageQueueId_t is the same size as void*
// (the FreeRTOS handle type), compiler will catch this but it might be nice
// to have something checking or even an always working solution
// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ // https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/
/** /**
* @brief This class manages sending and receiving of message queue messages. * @brief This class manages sending and receiving of
* * message queue messages.
* @details Message queues are used to pass asynchronous messages between processes. * @details
* Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO * They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch * order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also provides * received messages. Being a child of MessageQueueSender, this class also
* methods to send a message to a user-defined or a default destination. In addition * provides methods to send a message to a user-defined or a default destination.
* it also provides a reply method to answer to the queue it received its last message * In addition it also provides a reply method to answer to the queue it
* from. * received its last message from.
* The MessageQueue should be used as "post box" for a single owning object. So all *
* message queue communication is "n-to-one". * The MessageQueue should be used as "post box" for a single owning object.
* For creating the queue, as well as sending and receiving messages, the class makes * So all message queue communication is "n-to-one".
* use of the operating system calls provided. * For creating the queue, as well as sending and receiving messages, the class
* \ingroup message_queue * makes use of the operating system calls provided.
*
* Please keep in mind that FreeRTOS offers different calls for message queue
* operations if called from an ISR.
* For now, the system context needs to be switched manually.
* @ingroup osal
* @ingroup message_queue
*/ */
class MessageQueue : public MessageQueueIF { class MessageQueue : public MessageQueueIF {
friend class MessageQueueSenderIF; friend class MessageQueueSenderIF;
public: public:
/** /**
* @brief The constructor initializes and configures the message queue. * @brief The constructor initializes and configures the message queue.
* @details By making use of the according operating system call, a message queue is created * @details
* and initialized. The message depth - the maximum number of messages to be * By making use of the according operating system call, a message queue
* buffered - may be set with the help of a parameter, whereas the message size is * is created and initialized. The message depth - the maximum number of
* automatically set to the maximum message queue message size. The operating system * messages to be buffered - may be set with the help of a parameter,
* sets the message queue id, or i case of failure, it is set to zero. * whereas the message size is automatically set to the maximum message
* @param message_depth The number of messages to be buffered before passing an error to the * queue message size. The operating system sets the message queue id, or
* in case of failure, it is set to zero.
* @param message_depth
* The number of messages to be buffered before passing an error to the
* sender. Default is three. * sender. Default is three.
* @param max_message_size With this parameter, the maximum message size can be adjusted. * @param max_message_size
* With this parameter, the maximum message size can be adjusted.
* This should be left default. * This should be left default.
*/ */
MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); MessageQueue( size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE );
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete;
/** /**
* @brief The destructor deletes the formerly created message queue. * @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system. * @details This is accomplished by using the delete call provided
* by the operating system.
*/ */
virtual ~MessageQueue(); virtual ~MessageQueue();
/** /**
* @brief This operation sends a message to the given destination. * This function is used to switch the call context. This has to be called
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its * if a message is sent or received from an ISR!
* queue id as "sentFrom" parameter. * @param callContext
* @param sendTo This parameter specifies the message queue id of the destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/ */
void switchSystemContext(CallContext callContext);
/** MessageQueueIF implementation */
ReturnValue_t sendMessage(MessageQueueId_t sendTo, ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault = false ); MessageQueueMessageIF* message, bool ignoreFault = false) override;
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the sendToDefault call of the
* MessageQueueSender parent class and adds its queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t sendToDefault( MessageQueueMessage* message );
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using the stored
* lastParnter information as destination. If there was no message received yet
* (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t reply( MessageQueueMessage* message );
/** ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
* @brief This function reads available messages from the message queue and returns the sender.
* @details It works identically to the other receiveMessage call, but in addition returns the
* sender's queue id.
* @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessage* message,
MessageQueueId_t *receivedFrom);
/** ReturnValue_t reply(MessageQueueMessageIF* message) override;
* @brief This function reads available messages from the message queue. virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo,
* @details If data is available it is stored in the passed message pointer. The message's MessageQueueMessageIF* message,
* original content is overwritten and the sendFrom information is stored in the MessageQueueId_t sentFrom = NO_QUEUE,
* lastPartner attribute. Else, the lastPartner information remains untouched, the bool ignoreFault = false) override;
* message's content is cleared and the function returns immediately.
* @param message A pointer to a message in which the received data is stored. virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
*/ MessageQueueId_t sentFrom = NO_QUEUE,
ReturnValue_t receiveMessage(MessageQueueMessage* message); bool ignoreFault = false) override;
/**
* Deletes all pending messages in the queue. ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
* @param count The number of flushed messages. MessageQueueId_t *receivedFrom) override;
* @return RETURN_OK on success.
*/ ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
ReturnValue_t flush(uint32_t* count);
/** ReturnValue_t flush(uint32_t* count) override;
* @brief This method returns the message queue id of the last communication partner.
*/ MessageQueueId_t getLastPartner() const override;
MessageQueueId_t getLastPartner() const;
/** MessageQueueId_t getId() const override;
* @brief This method returns the message queue id of this class's message queue.
*/ void setDefaultDestination(MessageQueueId_t defaultDestination) override;
MessageQueueId_t getId() const;
/** MessageQueueId_t getDefaultDestination() const override;
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
* \details This method takes the message provided, adds the sentFrom information and passes bool isDefaultDestinationSet() const override;
* it on to the destination provided with an operating system call. The OS's return
* value is returned.
* \param sendTo This parameter specifies the message queue id to send the message to.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/**
* \brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
*/
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/**
* \brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination);
/**
* \brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const;
bool isDefaultDestinationSet() const;
protected: protected:
/** /**
* Implementation to be called from any send Call within MessageQueue and MessageQueueSenderIF * @brief Implementation to be called from any send Call within
* \details This method takes the message provided, adds the sentFrom information and passes * MessageQueue and MessageQueueSenderIF.
* it on to the destination provided with an operating system call. The OS's return * @details
* value is returned. * This method takes the message provided, adds the sentFrom information and
* \param sendTo This parameter specifies the message queue id to send the message to. * passes it on to the destination provided with an operating system call.
* \param message This is a pointer to a previously created message, which is sent. * The OS's return value is returned.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * @param sendTo
* This variable is set to zero by default. * This parameter specifies the message queue id to send the message to.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. * @param message
* This is a pointer to a previously created message, which is sent.
* @param sentFrom
* The sentFrom information can be set to inject the sender's queue id into
* the message. This variable is set to zero by default.
* @param ignoreFault
* If set to true, the internal software fault counter is not incremented
* if queue is full.
* @param context Specify whether call is made from task or from an ISR.
*/ */
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE,bool ignoreFault=false); static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false, CallContext callContext = CallContext::TASK);
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private: private:
bool defaultDestinationSet = false;
QueueHandle_t handle; QueueHandle_t handle;
MessageQueueId_t defaultDestination; MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
MessageQueueId_t lastPartner; MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
const size_t maxMessageSize;
//! Stores the current system context
CallContext callContext = CallContext::TASK;
}; };
#endif /* MESSAGEQUEUE_H_ */ #endif /* FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ */

View File

@ -1,14 +1,14 @@
#include "MessageQueue.h"
#include "../../ipc/MessageQueueSenderIF.h" #include "../../ipc/MessageQueueSenderIF.h"
#include "../../ipc/QueueFactory.h" #include "../../ipc/QueueFactory.h"
#include "MessageQueue.h"
QueueFactory* QueueFactory::factoryInstance = nullptr; QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault) {
return MessageQueue::sendMessageFromMessageQueue(sendTo,message, return MessageQueue::sendMessageFromMessageQueue(sendTo,message,
sentFrom,ignoreFault); sentFrom,ignoreFault);

View File

@ -1,6 +1,11 @@
#include "MessageQueue.h"
#include "../../ipc/MessageQueueSenderIF.h"
#include "../../ipc/MessageQueueMessageIF.h"
#include "../../ipc/QueueFactory.h" #include "../../ipc/QueueFactory.h"
#include "../../osal/host/MessageQueue.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
#include <cstring> #include <cstring>
QueueFactory* QueueFactory::factoryInstance = nullptr; QueueFactory* QueueFactory::factoryInstance = nullptr;

View File

@ -9,9 +9,11 @@
#include <errno.h> #include <errno.h>
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize):
id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE), id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE),
defaultDestination(MessageQueueIF::NO_QUEUE) { defaultDestination(MessageQueueIF::NO_QUEUE),
maxMessageSize(maxMessageSize) {
//debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl; //debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl;
mq_attr attributes; mq_attr attributes;
this->id = 0; this->id = 0;
@ -61,22 +63,27 @@ ReturnValue_t MessageQueue::handleError(mq_attr* attributes,
// Just an additional helpful printout :-) // Just an additional helpful printout :-)
if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >> if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >>
defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) { defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) {
// See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html /*
// This happens if the msg_max value is not large enough See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html
// It is ignored if the executable is run in privileged mode. This happens if the msg_max value is not large enough
// Run the unlockRealtime script or grant the mode manually by using: It is ignored if the executable is run in privileged mode.
// sudo setcap 'CAP_SYS_RESOURCE=+ep' <pathToBinary> Run the unlockRealtime script or grant the mode manually by using:
sudo setcap 'CAP_SYS_RESOURCE=+ep' <pathToBinary>
// Persistent solution for session: Persistent solution for session:
// echo <newMsgMax> | sudo tee /proc/sys/fs/mqueue/msg_max echo <newMsgMax> | sudo tee /proc/sys/fs/mqueue/msg_max
// Permanent solution: Permanent solution:
// sudo nano /etc/sysctl.conf sudo nano /etc/sysctl.conf
// Append at end: fs/mqueue/msg_max = <newMsgMaxLen> Append at end: fs/mqueue/msg_max = <newMsgMaxLen>
// Apply changes with: sudo sysctl -p Apply changes with: sudo sysctl -p
*/
sif::error << "MessageQueue::MessageQueue: Default MQ size " sif::error << "MessageQueue::MessageQueue: Default MQ size "
<< defaultMqMaxMsg << " is too small for requested size " << defaultMqMaxMsg << " is too small for requested size "
<< messageDepth << std::endl; << messageDepth << std::endl;
sif::error << "This error can be fixed by setting the maximum "
"allowed message size higher!" << std::endl;
} }
break; break;
} }
@ -118,15 +125,15 @@ ReturnValue_t MessageQueue::handleError(mq_attr* attributes,
} }
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault) { MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), false); return sendMessageFrom(sendTo, message, this->getId(), false);
} }
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId()); return sendToDefaultFrom(message, this->getId());
} }
ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) { if (this->lastPartner != 0) {
return sendMessageFrom(this->lastPartner, message, this->getId()); return sendMessageFrom(this->lastPartner, message, this->getId());
} else { } else {
@ -134,21 +141,34 @@ ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) {
} }
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) { MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message); ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->lastPartner; *receivedFrom = this->lastPartner;
return status; return status;
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(message == nullptr) {
sif::error << "MessageQueue::receiveMessage: Message is "
"nullptr!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(message->getMaximumMessageSize() < maxMessageSize) {
sif::error << "MessageQueue::receiveMessage: Message size "
<< message->getMaximumMessageSize()
<< " too small to receive data!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
unsigned int messagePriority = 0; unsigned int messagePriority = 0;
int status = mq_receive(id,reinterpret_cast<char*>(message->getBuffer()), int status = mq_receive(id,reinterpret_cast<char*>(message->getBuffer()),
message->MAX_MESSAGE_SIZE,&messagePriority); message->getMaximumMessageSize(),&messagePriority);
if (status > 0) { if (status > 0) {
this->lastPartner = message->getSender(); this->lastPartner = message->getSender();
//Check size of incoming message. //Check size of incoming message.
if (message->messageSize < message->getMinimumMessageSize()) { if (message->getMessageSize() < message->getMinimumMessageSize()) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
@ -158,7 +178,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) {
} else { } else {
//No message was received. Keep lastPartner anyway, I might send //No message was received. Keep lastPartner anyway, I might send
//something later. But still, delete packet content. //something later. But still, delete packet content.
memset(message->getData(), 0, message->MAX_DATA_SIZE); memset(message->getData(), 0, message->getMaximumMessageSize());
switch(errno){ switch(errno){
case EAGAIN: case EAGAIN:
//O_NONBLOCK or MQ_NONBLOCK was set and there are no messages //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages
@ -258,18 +278,19 @@ void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDestination = defaultDestination; this->defaultDestination = defaultDestination;
} }
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault); return sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault);
} }
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
MessageQueueId_t MessageQueue::getDefaultDestination() const { MessageQueueId_t MessageQueue::getDefaultDestination() const {
return this->defaultDestination; return this->defaultDestination;
} }
@ -281,11 +302,18 @@ bool MessageQueue::isDefaultDestinationSet() const {
uint16_t MessageQueue::queueCounter = 0; uint16_t MessageQueue::queueCounter = 0;
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessage *message, MessageQueueId_t sentFrom, MessageQueueMessageIF *message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault) {
if(message == nullptr) {
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is "
"nullptr!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
message->setSender(sentFrom); message->setSender(sentFrom);
int result = mq_send(sendTo, int result = mq_send(sendTo,
reinterpret_cast<const char*>(message->getBuffer()), message->messageSize,0); reinterpret_cast<const char*>(message->getBuffer()),
message->getMessageSize(),0);
//TODO: Check if we're in ISR. //TODO: Check if we're in ISR.
if (result != 0) { if (result != 0) {
@ -303,13 +331,16 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
//MQ_NONBLOCK flag was set in its attributes, and the //MQ_NONBLOCK flag was set in its attributes, and the
//specified queue is full. //specified queue is full.
return MessageQueueIF::FULL; return MessageQueueIF::FULL;
case EBADF: case EBADF: {
//mq_des doesn't represent a valid message queue descriptor, //mq_des doesn't represent a valid message queue descriptor,
//or mq_des wasn't opened for writing. //or mq_des wasn't opened for writing.
sif::error << "MessageQueue::sendMessage: Configuration error " sif::error << "MessageQueue::sendMessage: Configuration error, MQ"
<< strerror(errno) << " in mq_send mqSendTo: " << sendTo << " destination invalid." << std::endl;
<< " sent from " << sentFrom << std::endl; sif::error << strerror(errno) << " in "
/*NO BREAK*/ <<"mq_send to: " << sendTo << " sent from "
<< sentFrom << std::endl;
return DESTINVATION_INVALID;
}
case EINTR: case EINTR:
//The call was interrupted by a signal. //The call was interrupted by a signal.
case EINVAL: case EINVAL:

View File

@ -1,5 +1,5 @@
#ifndef MESSAGEQUEUE_H_ #ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
#define MESSAGEQUEUE_H_ #define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h" #include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h" #include "../../ipc/MessageQueueIF.h"
@ -56,14 +56,14 @@ public:
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/ */
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault = false ); MessageQueueMessageIF* message, bool ignoreFault = false );
/** /**
* @brief This operation sends a message to the default destination. * @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the sendToDefault call of the * @details As in the sendMessage method, this function uses the sendToDefault call of the
* MessageQueueSender parent class and adds its queue id as "sentFrom" information. * MessageQueueSender parent class and adds its queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
*/ */
virtual ReturnValue_t sendToDefault( MessageQueueMessage* message ); virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message );
/** /**
* @brief This operation sends a message to the last communication partner. * @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using the stored * @details This operation simplifies answering an incoming message by using the stored
@ -71,7 +71,7 @@ public:
* (i.e. lastPartner is zero), an error code is returned. * (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
*/ */
ReturnValue_t reply( MessageQueueMessage* message ); ReturnValue_t reply( MessageQueueMessageIF* message );
/** /**
* @brief This function reads available messages from the message queue and returns the sender. * @brief This function reads available messages from the message queue and returns the sender.
@ -80,7 +80,7 @@ public:
* @param message A pointer to a message in which the received data is stored. * @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored. * @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/ */
ReturnValue_t receiveMessage(MessageQueueMessage* message, ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t *receivedFrom); MessageQueueId_t *receivedFrom);
/** /**
@ -91,7 +91,7 @@ public:
* message's content is cleared and the function returns immediately. * message's content is cleared and the function returns immediately.
* @param message A pointer to a message in which the received data is stored. * @param message A pointer to a message in which the received data is stored.
*/ */
ReturnValue_t receiveMessage(MessageQueueMessage* message); ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
/** /**
* Deletes all pending messages in the queue. * Deletes all pending messages in the queue.
* @param count The number of flushed messages. * @param count The number of flushed messages.
@ -114,7 +114,9 @@ public:
* This variable is set to zero by default. * This variable is set to zero by default.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/ */
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ); virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault = false );
/** /**
* \brief The sendToDefault method sends a queue message to the default destination. * \brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method. * \details In all other aspects, it works identical to the sendMessage method.
@ -122,7 +124,8 @@ public:
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default. * This variable is set to zero by default.
*/ */
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/** /**
* \brief This method is a simple setter for the default destination. * \brief This method is a simple setter for the default destination.
*/ */
@ -145,7 +148,9 @@ protected:
* This variable is set to zero by default. * This variable is set to zero by default.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/ */
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE,bool ignoreFault=false); static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false);
private: private:
/** /**
* @brief The class stores the queue id it got assigned from the operating system in this attribute. * @brief The class stores the queue id it got assigned from the operating system in this attribute.
@ -171,11 +176,12 @@ private:
/** /**
* The name of the message queue, stored for unlinking * The name of the message queue, stored for unlinking
*/ */
char name[5]; char name[16];
static uint16_t queueCounter; static uint16_t queueCounter;
const size_t maxMessageSize;
ReturnValue_t handleError(mq_attr* attributes, uint32_t messageDepth); ReturnValue_t handleError(mq_attr* attributes, uint32_t messageDepth);
}; };
#endif /* MESSAGEQUEUE_H_ */ #endif /* FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ */

View File

@ -15,7 +15,7 @@ QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault) {
return MessageQueue::sendMessageFromMessageQueue(sendTo,message, return MessageQueue::sendMessageFromMessageQueue(sendTo,message,
sentFrom,ignoreFault); sentFrom,ignoreFault);

View File

@ -33,7 +33,7 @@ ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
while(1) { while(1) {
//! Sender Address is cached here. //! Sender Address is cached here.
struct sockaddr_in senderAddress; struct sockaddr_in senderAddress;
socklen_t senderSockLen = 0; socklen_t senderSockLen = sizeof(senderAddress);
ssize_t bytesReceived = recvfrom(serverUdpSocket, ssize_t bytesReceived = recvfrom(serverUdpSocket,
receptionBuffer.data(), frameSize, receptionFlags, receptionBuffer.data(), frameSize, receptionFlags,
reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen); reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen);

View File

@ -65,9 +65,13 @@ TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0; int flags = 0;
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
if(ipAddrAnySet){
clientAddress.sin_addr.s_addr = htons(INADDR_ANY); clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
//clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1"); //clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1");
clientAddressLen = sizeof(serverAddress); clientAddressLen = sizeof(serverAddress);
}
// char ipAddress [15]; // char ipAddress [15];
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, // sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
@ -85,7 +89,7 @@ ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10); MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
// char ipAddress [15]; // char ipAddress [15];
@ -168,3 +172,7 @@ void TmTcUnixUdpBridge::handleSendError() {
} }
} }
void TmTcUnixUdpBridge::setClientAddressToAny(bool ipAddrAnySet){
this->ipAddrAnySet = ipAddrAnySet;
}

View File

@ -20,8 +20,9 @@ public:
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF); uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
virtual~ TmTcUnixUdpBridge(); virtual~ TmTcUnixUdpBridge();
void checkAndSetClientAddress(sockaddr_in clientAddress); void checkAndSetClientAddress(sockaddr_in& clientAddress);
void setClientAddressToAny(bool ipAddrAnySet);
protected: protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override; virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
@ -36,6 +37,8 @@ private:
struct sockaddr_in serverAddress; struct sockaddr_in serverAddress;
socklen_t serverAddressLen = 0; socklen_t serverAddressLen = 0;
bool ipAddrAnySet = false;
//! Access to the client address is mutex protected as it is set //! Access to the client address is mutex protected as it is set
//! by another task. //! by another task.
MutexIF* mutex; MutexIF* mutex;

View File

@ -3,7 +3,7 @@
#include <rtems/score/todimpl.h> #include <rtems/score/todimpl.h>
uint16_t Clock::leapSeconds = 0; uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL; MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void){ uint32_t Clock::getTicksPerSecond(void){
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
@ -40,7 +40,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
//SHOULDDO: Not sure if we need to protect this call somehow (by thread lock or something). //SHOULDDO: Not sure if we need to protect this call somehow (by thread lock or something).
//Uli: rtems docu says you can call this from an ISR, not sure if this means no protetion needed //Uli: rtems docu says you can call this from an ISR, not sure if this means no protetion needed
//TODO Second parameter is ISR_lock_Context //TODO Second parameter is ISR_lock_Context
_TOD_Set(&newTime,NULL); _TOD_Set(&newTime,nullptr);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -131,7 +131,7 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds) //SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == NULL) { if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -157,40 +157,34 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); MutexHelper helper(timeMutex);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
leapSeconds = leapSeconds_; leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex();
return result; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex==NULL){ if(timeMutex==nullptr){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); MutexHelper helper(timeMutex);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*leapSeconds_ = leapSeconds; *leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex(); return HasReturnvaluesIF::RETURN_OK;
return result;
} }
ReturnValue_t Clock::checkOrCreateClockMutex(){ ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex==NULL){ if(timeMutex==nullptr){
MutexFactory* mutexFactory = MutexFactory::instance(); MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == NULL) { if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
timeMutex = mutexFactory->createMutex(); timeMutex = mutexFactory->createMutex();
if (timeMutex == NULL) { if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }

View File

@ -158,7 +158,7 @@ uint32_t CpuUsage::ThreadData::getSerializedSize() const {
} }
ReturnValue_t CpuUsage::ThreadData::deSerialize(const uint8_t** buffer, ReturnValue_t CpuUsage::ThreadData::deSerialize(const uint8_t** buffer,
int32_t* size, Endianness streamEndianness) { size_t* size, Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::deSerialize(&id, buffer, ReturnValue_t result = SerializeAdapter::deSerialize(&id, buffer,
size, streamEndianness); size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -12,8 +12,8 @@ ReturnValue_t InternalErrorCodes::translate(uint8_t code) {
// return INVALID_WORKSPACE_ADDRESS; // return INVALID_WORKSPACE_ADDRESS;
case INTERNAL_ERROR_TOO_LITTLE_WORKSPACE: case INTERNAL_ERROR_TOO_LITTLE_WORKSPACE:
return TOO_LITTLE_WORKSPACE; return TOO_LITTLE_WORKSPACE;
case INTERNAL_ERROR_WORKSPACE_ALLOCATION: // case INTERNAL_ERROR_WORKSPACE_ALLOCATION:
return WORKSPACE_ALLOCATION; // return WORKSPACE_ALLOCATION;
// case INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL: // case INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL:
// return INTERRUPT_STACK_TOO_SMALL; // return INTERRUPT_STACK_TOO_SMALL;
case INTERNAL_ERROR_THREAD_EXITTED: case INTERNAL_ERROR_THREAD_EXITTED:

View File

@ -1,86 +0,0 @@
#include "Interrupt.h"
extern "C" {
#include <bsp_flp/hw_timer/hw_timer.h>
#include <bsp_flp/hw_uart/hw_uart.h>
}
#include "RtemsBasic.h"
ReturnValue_t Interrupt::enableInterrupt(InterruptNumber_t interruptNumber) {
volatile uint32_t* irqMask = hw_irq_mask;
uint32_t expectedValue = *irqMask | (1 << interruptNumber);
*irqMask = expectedValue;
uint32_t tempValue = *irqMask;
if (tempValue == expectedValue) {
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Interrupt::setInterruptServiceRoutine(IsrHandler_t handler,
InterruptNumber_t interrupt, IsrHandler_t* oldHandler) {
IsrHandler_t oldHandler_local;
if (oldHandler == NULL) {
oldHandler = &oldHandler_local;
}
//+ 0x10 comes because of trap type assignment to IRQs in UT699 processor
rtems_status_code status = rtems_interrupt_catch(handler, interrupt + 0x10,
oldHandler);
switch(status){
case RTEMS_SUCCESSFUL:
//ISR established successfully
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_INVALID_NUMBER:
//illegal vector number
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
//illegal ISR entry point or invalid old_isr_handler
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Interrupt::disableInterrupt(InterruptNumber_t interruptNumber) {
//TODO Not implemented
return HasReturnvaluesIF::RETURN_FAILED;
}
//SHOULDDO: Make default values (edge, polarity) settable?
ReturnValue_t Interrupt::enableGpioInterrupt(InterruptNumber_t interrupt) {
volatile uint32_t* irqMask = hw_irq_mask;
uint32_t expectedValue = *irqMask | (1 << interrupt);
*irqMask = expectedValue;
uint32_t tempValue = *irqMask;
if (tempValue == expectedValue) {
volatile hw_gpio_port_t* ioPorts = hw_gpio_port;
ioPorts->direction &= ~(1 << interrupt); //Direction In
ioPorts->interrupt_edge |= 1 << interrupt; //Edge triggered
ioPorts->interrupt_polarity |= 1 << interrupt; //Trigger on rising edge
ioPorts->interrupt_mask |= 1 << interrupt; //Enable
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Interrupt::disableGpioInterrupt(InterruptNumber_t interrupt) {
volatile uint32_t* irqMask = hw_irq_mask;
uint32_t expectedValue = *irqMask & ~(1 << interrupt);
*irqMask = expectedValue;
uint32_t tempValue = *irqMask;
if (tempValue == expectedValue) {
//Disable gpio IRQ
volatile hw_gpio_port_t* ioPorts = hw_gpio_port;
ioPorts->interrupt_mask &= ~(1 << interrupt);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
bool Interrupt::isInterruptInProgress() {
return rtems_interrupt_is_in_progress();
}

View File

@ -1,50 +0,0 @@
#ifndef OS_RTEMS_INTERRUPT_H_
#define OS_RTEMS_INTERRUPT_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include <cstring>
#include <rtems.h>
typedef rtems_isr_entry IsrHandler_t;
typedef rtems_isr IsrReturn_t;
typedef rtems_vector_number InterruptNumber_t;
class Interrupt {
public:
virtual ~Interrupt(){};
/**
* Establishes a new interrupt service routine.
* @param handler The service routine to establish
* @param interrupt The interrupt (NOT trap type) the routine shall react to.
* @return RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t setInterruptServiceRoutine(IsrHandler_t handler,
InterruptNumber_t interrupt, IsrHandler_t *oldHandler = NULL);
static ReturnValue_t enableInterrupt(InterruptNumber_t interruptNumber);
static ReturnValue_t disableInterrupt(InterruptNumber_t interruptNumber);
/**
* Enables the interrupt given.
* The function tests, if the InterruptMask register was written successfully.
* @param interrupt The interrupt to enable.
* @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else.
*/
static ReturnValue_t enableGpioInterrupt(InterruptNumber_t interrupt);
/**
* Disables the interrupt given.
* @param interrupt The interrupt to disable.
* @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else.
*/
static ReturnValue_t disableGpioInterrupt(InterruptNumber_t interrupt);
/**
* Checks if the current executing context is an ISR.
* @return true if handling an interrupt, false else.
*/
static bool isInterruptInProgress();
};
#endif /* OS_RTEMS_INTERRUPT_H_ */

View File

@ -1,14 +1,15 @@
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "MessageQueue.h" #include "MessageQueue.h"
#include "RtemsBasic.h" #include "RtemsBasic.h"
#include <cstring> #include <cstring>
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) :
id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(NULL) { id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) {
rtems_name name = ('Q' << 24) + (queueCounter++ << 8); rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
rtems_status_code status = rtems_message_queue_create(name, message_depth, rtems_status_code status = rtems_message_queue_create(name, message_depth,
max_message_size, 0, &(this->id)); max_message_size, 0, &(this->id));
if (status != RTEMS_SUCCESSFUL) { if (status != RTEMS_SUCCESSFUL) {
error << "MessageQueue::MessageQueue: Creating Queue " << std::hex sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex
<< name << std::dec << " failed with status:" << name << std::dec << " failed with status:"
<< (uint32_t) status << std::endl; << (uint32_t) status << std::endl;
this->id = 0; this->id = 0;
@ -20,15 +21,15 @@ MessageQueue::~MessageQueue() {
} }
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault) { MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
} }
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId()); return sendToDefaultFrom(message, this->getId());
} }
ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) { if (this->lastPartner != 0) {
return sendMessage(this->lastPartner, message, this->getId()); return sendMessage(this->lastPartner, message, this->getId());
} else { } else {
@ -36,27 +37,29 @@ ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) {
} }
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) { MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message); ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->lastPartner; *receivedFrom = this->lastPartner;
return status; return status;
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
size_t size = 0;
rtems_status_code status = rtems_message_queue_receive(id, rtems_status_code status = rtems_message_queue_receive(id,
message->getBuffer(), &(message->messageSize), message->getBuffer(),&size,
RTEMS_NO_WAIT, 1); RTEMS_NO_WAIT, 1);
if (status == RTEMS_SUCCESSFUL) { if (status == RTEMS_SUCCESSFUL) {
message->setMessageSize(size);
this->lastPartner = message->getSender(); this->lastPartner = message->getSender();
//Check size of incoming message. //Check size of incoming message.
if (message->messageSize < message->getMinimumMessageSize()) { if (message->getMessageSize() < message->getMinimumMessageSize()) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} else { } else {
//No message was received. Keep lastPartner anyway, I might send something later. //No message was received. Keep lastPartner anyway, I might send something later.
//But still, delete packet content. //But still, delete packet content.
memset(message->getData(), 0, message->MAX_DATA_SIZE); memset(message->getData(), 0, message->getMaximumMessageSize());
} }
return convertReturnCode(status); return convertReturnCode(status);
} }
@ -79,20 +82,20 @@ void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
} }
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault) {
message->setSender(sentFrom); message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo, rtems_status_code result = rtems_message_queue_send(sendTo,
message->getBuffer(), message->messageSize); message->getBuffer(), message->getMessageSize());
//TODO: Check if we're in ISR. //TODO: Check if we're in ISR.
if (result != RTEMS_SUCCESSFUL && !ignoreFault) { if (result != RTEMS_SUCCESSFUL && !ignoreFault) {
if (internalErrorReporter == NULL) { if (internalErrorReporter == nullptr) {
internalErrorReporter = objectManager->get<InternalErrorReporterIF>( internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER); objects::INTERNAL_ERROR_REPORTER);
} }
if (internalErrorReporter != NULL) { if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
} }
@ -105,7 +108,7 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
return returnCode; return returnCode;
} }
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) { MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
} }

View File

@ -1,14 +1,5 @@
/** #ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
* @file MessageQueue.h #define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
*
* @date 10/02/2012
* @author Bastian Baetz
*
* @brief This file contains the definition of the MessageQueue class.
*/
#ifndef MESSAGEQUEUE_H_
#define MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h" #include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h" #include "../../ipc/MessageQueueIF.h"
@ -60,14 +51,14 @@ public:
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/ */
ReturnValue_t sendMessage(MessageQueueId_t sendTo, ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault = false ); MessageQueueMessageIF* message, bool ignoreFault = false );
/** /**
* @brief This operation sends a message to the default destination. * @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the sendToDefault call of the * @details As in the sendMessage method, this function uses the sendToDefault call of the
* MessageQueueSender parent class and adds its queue id as "sentFrom" information. * MessageQueueSender parent class and adds its queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
*/ */
ReturnValue_t sendToDefault( MessageQueueMessage* message ); ReturnValue_t sendToDefault( MessageQueueMessageIF* message );
/** /**
* @brief This operation sends a message to the last communication partner. * @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using the stored * @details This operation simplifies answering an incoming message by using the stored
@ -75,7 +66,7 @@ public:
* (i.e. lastPartner is zero), an error code is returned. * (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
*/ */
ReturnValue_t reply( MessageQueueMessage* message ); ReturnValue_t reply( MessageQueueMessageIF* message );
/** /**
* @brief This function reads available messages from the message queue and returns the sender. * @brief This function reads available messages from the message queue and returns the sender.
@ -84,7 +75,7 @@ public:
* @param message A pointer to a message in which the received data is stored. * @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored. * @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/ */
ReturnValue_t receiveMessage(MessageQueueMessage* message, ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t *receivedFrom); MessageQueueId_t *receivedFrom);
/** /**
@ -95,7 +86,7 @@ public:
* message's content is cleared and the function returns immediately. * message's content is cleared and the function returns immediately.
* @param message A pointer to a message in which the received data is stored. * @param message A pointer to a message in which the received data is stored.
*/ */
ReturnValue_t receiveMessage(MessageQueueMessage* message); ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
/** /**
* Deletes all pending messages in the queue. * Deletes all pending messages in the queue.
* @param count The number of flushed messages. * @param count The number of flushed messages.
@ -121,7 +112,7 @@ public:
* This variable is set to zero by default. * This variable is set to zero by default.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/ */
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/** /**
* \brief The sendToDefault method sends a queue message to the default destination. * \brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method. * \details In all other aspects, it works identical to the sendMessage method.
@ -129,7 +120,7 @@ public:
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default. * This variable is set to zero by default.
*/ */
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/** /**
* \brief This method is a simple setter for the default destination. * \brief This method is a simple setter for the default destination.
*/ */
@ -178,4 +169,4 @@ private:
static ReturnValue_t convertReturnCode(rtems_status_code inValue); static ReturnValue_t convertReturnCode(rtems_status_code inValue);
}; };
#endif /* MESSAGEQUEUE_H_ */ #endif /* FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ */

View File

@ -30,7 +30,7 @@ ReturnValue_t MultiObjectTask::startTask() {
rtems_status_code status = rtems_task_start(id, MultiObjectTask::taskEntryPoint, rtems_status_code status = rtems_task_start(id, MultiObjectTask::taskEntryPoint,
rtems_task_argument((void *) this)); rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) { if (status != RTEMS_SUCCESSFUL) {
error << "ObjectTask::startTask for " << std::hex << this->getId() sif::error << "ObjectTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl; << std::dec << " failed." << std::endl;
} }
switch(status){ switch(status){
@ -63,8 +63,8 @@ void MultiObjectTask::taskFunctionality() {
char nameSpace[8] = { 0 }; char nameSpace[8] = { 0 };
char* ptr = rtems_object_get_name(getId(), sizeof(nameSpace), char* ptr = rtems_object_get_name(getId(), sizeof(nameSpace),
nameSpace); nameSpace);
error << "ObjectTask: " << ptr << " Deadline missed." << std::endl; sif::error << "ObjectTask: " << ptr << " Deadline missed." << std::endl;
if (this->deadlineMissedFunc != NULL) { if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc(); this->deadlineMissedFunc();
} }
} }
@ -74,7 +74,7 @@ void MultiObjectTask::taskFunctionality() {
ReturnValue_t MultiObjectTask::addComponent(object_id_t object) { ReturnValue_t MultiObjectTask::addComponent(object_id_t object) {
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);

View File

@ -80,7 +80,7 @@ protected:
/** /**
* @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 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, * So, each may react individually on a timing failure. The pointer may be nullptr,
* then nothing happens on missing the deadline. The deadline is equal to the next execution * then nothing happens on missing the deadline. The deadline is equal to the next execution
* of the periodic task. * of the periodic task.
*/ */

View File

@ -10,7 +10,7 @@ Mutex::Mutex() :
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0, RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0,
&mutexId); &mutexId);
if (status != RTEMS_SUCCESSFUL) { if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: creation with name, id " << mutexName << ", " << mutexId sif::error << "Mutex: creation with name, id " << mutexName << ", " << mutexId
<< " failed with " << status << std::endl; << " failed with " << status << std::endl;
} }
} }
@ -18,24 +18,25 @@ Mutex::Mutex() :
Mutex::~Mutex() { Mutex::~Mutex() {
rtems_status_code status = rtems_semaphore_delete(mutexId); rtems_status_code status = rtems_semaphore_delete(mutexId);
if (status != RTEMS_SUCCESSFUL) { if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: deletion for id " << mutexId sif::error << "Mutex: deletion for id " << mutexId
<< " failed with " << status << std::endl; << " failed with " << status << std::endl;
} }
} }
ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType = ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType =
TimeoutType::BLOCKING, uint32_t timeoutMs) { TimeoutType::BLOCKING, uint32_t timeoutMs) {
rtems_status_code status = RTEMS_INVALID_ID;
if(timeoutMs == MutexIF::TimeoutType::BLOCKING) { if(timeoutMs == MutexIF::TimeoutType::BLOCKING) {
rtems_status_code status = rtems_semaphore_obtain(mutexId, status = rtems_semaphore_obtain(mutexId,
RTEMS_WAIT, RTEMS_NO_TIMEOUT); RTEMS_WAIT, RTEMS_NO_TIMEOUT);
} }
else if(timeoutMs == MutexIF::TimeoutType::POLLING) { else if(timeoutMs == MutexIF::TimeoutType::POLLING) {
timeoutMs = RTEMS_NO_TIMEOUT; timeoutMs = RTEMS_NO_TIMEOUT;
rtems_status_code status = rtems_semaphore_obtain(mutexId, status = rtems_semaphore_obtain(mutexId,
RTEMS_NO_WAIT, 0); RTEMS_NO_WAIT, 0);
} }
else { else {
rtems_status_code status = rtems_semaphore_obtain(mutexId, status = rtems_semaphore_obtain(mutexId,
RTEMS_WAIT, timeoutMs); RTEMS_WAIT, timeoutMs);
} }

View File

@ -1,5 +1,5 @@
#ifndef FRAMEWORK_OSAL_RTEMS_MUTEX_H_ #ifndef FSFW_OSAL_RTEMS_MUTEX_H_
#define FRAMEWORK_OSAL_RTEMS_MUTEX_H_ #define FSFW_OSAL_RTEMS_MUTEX_H_
#include "../../ipc/MutexIF.h" #include "../../ipc/MutexIF.h"
#include "RtemsBasic.h" #include "RtemsBasic.h"
@ -15,4 +15,4 @@ private:
static uint8_t count; static uint8_t count;
}; };
#endif /* OS_RTEMS_MUTEX_H_ */ #endif /* FSFW_OSAL_RTEMS_MUTEX_H_ */

View File

@ -2,7 +2,6 @@
#include "Mutex.h" #include "Mutex.h"
#include "RtemsBasic.h" #include "RtemsBasic.h"
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory::MutexFactory() { MutexFactory::MutexFactory() {

View File

@ -1,5 +1,6 @@
#include "../../devicehandlers/FixedSequenceSlot.h" #include "../../tasks/FixedSequenceSlot.h"
#include "../../objectmanager/SystemObjectIF.h" #include "../../objectmanager/SystemObjectIF.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "PollingTask.h" #include "PollingTask.h"
#include "RtemsBasic.h" #include "RtemsBasic.h"
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
@ -34,14 +35,14 @@ rtems_task PollingTask::taskEntryPoint(rtems_task_argument argument) {
PollingTask *originalTask(reinterpret_cast<PollingTask*>(argument)); PollingTask *originalTask(reinterpret_cast<PollingTask*>(argument));
//The task's functionality is called. //The task's functionality is called.
originalTask->taskFunctionality(); originalTask->taskFunctionality();
debug << "Polling task " << originalTask->getId() sif::debug << "Polling task " << originalTask->getId()
<< " returned from taskFunctionality." << std::endl; << " returned from taskFunctionality." << std::endl;
} }
void PollingTask::missedDeadlineCounter() { void PollingTask::missedDeadlineCounter() {
PollingTask::deadlineMissedCount++; PollingTask::deadlineMissedCount++;
if (PollingTask::deadlineMissedCount % 10 == 0) { if (PollingTask::deadlineMissedCount % 10 == 0) {
error << "PST missed " << PollingTask::deadlineMissedCount sif::error << "PST missed " << PollingTask::deadlineMissedCount
<< " deadlines." << std::endl; << " deadlines." << std::endl;
} }
} }
@ -50,7 +51,7 @@ ReturnValue_t PollingTask::startTask() {
rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint, rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint,
rtems_task_argument((void *) this)); rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) { if (status != RTEMS_SUCCESSFUL) {
error << "PollingTask::startTask for " << std::hex << this->getId() sif::error << "PollingTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl; << std::dec << " failed." << std::endl;
} }
switch(status){ switch(status){
@ -68,12 +69,13 @@ ReturnValue_t PollingTask::startTask() {
ReturnValue_t PollingTask::addSlot(object_id_t componentId, ReturnValue_t PollingTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) { uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) { ExecutableObjectIF* object = objectManager->get<ExecutableObjectIF>(componentId);
pst.addSlot(componentId, slotTimeMs, executionStep, this); if (object != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, object, this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
error << "Component " << std::hex << componentId << sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl; " not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -90,11 +92,10 @@ ReturnValue_t PollingTask::checkSequence() const {
void PollingTask::taskFunctionality() { void PollingTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry. // A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
std::list<FixedSequenceSlot*>::iterator it = pst.current; FixedSlotSequence::SlotListIter it = pst.current;
//The start time for the first entry is read. //The start time for the first entry is read.
rtems_interval interval = RtemsBasic::convertMsToTicks( rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs);
(*it)->pollingTimeMs);
TaskBase::setAndStartPeriod(interval,&periodId); TaskBase::setAndStartPeriod(interval,&periodId);
//The task's "infinite" inner loop is entered. //The task's "infinite" inner loop is entered.
while (1) { while (1) {
@ -107,7 +108,7 @@ void PollingTask::taskFunctionality() {
//If the deadline was missed, the deadlineMissedFunc is called. //If the deadline was missed, the deadlineMissedFunc is called.
rtems_status_code status = TaskBase::restartPeriod(interval,periodId); rtems_status_code status = TaskBase::restartPeriod(interval,periodId);
if (status == RTEMS_TIMEOUT) { if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != NULL) { if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc(); this->deadlineMissedFunc();
} }
} }

View File

@ -1,7 +1,7 @@
#ifndef POLLINGTASK_H_ #ifndef FSFW_OSAL_RTEMS_POLLINGTASK_H_
#define POLLINGTASK_H_ #define FSFW_OSAL_RTEMS_POLLINGTASK_H_
#include "../../devicehandlers/FixedSlotSequence.h" #include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h" #include "../../tasks/FixedTimeslotTaskIF.h"
#include "TaskBase.h" #include "TaskBase.h"
@ -82,4 +82,4 @@ protected:
void taskFunctionality( void ); void taskFunctionality( void );
}; };
#endif /* POLLINGTASK_H_ */ #endif /* FSFW_OSAL_RTEMS_POLLINGTASK_H_ */

View File

@ -1,16 +1,17 @@
#include "../../ipc/QueueFactory.h" #include "../../ipc/QueueFactory.h"
#include "../../ipc/MessageQueueSenderIF.h"
#include "MessageQueue.h" #include "MessageQueue.h"
#include "RtemsBasic.h" #include "RtemsBasic.h"
QueueFactory* QueueFactory::factoryInstance = NULL; QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) { MessageQueueMessageIF* message, MessageQueueId_t sentFrom,bool ignoreFault) {
//TODO add ignoreFault functionality //TODO add ignoreFault functionality
message->setSender(sentFrom); message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(), rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(),
message->messageSize); message->getMessageSize());
switch(result){ switch(result){
case RTEMS_SUCCESSFUL: case RTEMS_SUCCESSFUL:
//message sent successfully //message sent successfully
@ -37,7 +38,7 @@ ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
} }
QueueFactory* QueueFactory::instance() { QueueFactory* QueueFactory::instance() {
if (factoryInstance == NULL) { if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory; factoryInstance = new QueueFactory;
} }
return factoryInstance; return factoryInstance;

View File

@ -1,5 +1,5 @@
#ifndef OS_RTEMS_RTEMSBASIC_H_ #ifndef FSFW_OSAL_RTEMS_RTEMSBASIC_H_
#define OS_RTEMS_RTEMSBASIC_H_ #define FSFW_OSAL_RTEMS_RTEMSBASIC_H_
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
#include <rtems.h> #include <rtems.h>
@ -22,4 +22,4 @@ public:
} }
}; };
#endif /* OS_RTEMS_RTEMSBASIC_H_ */ #endif /* FSFW_OSAL_RTEMS_RTEMSBASIC_H_ */

View File

@ -22,7 +22,7 @@ TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size,
} }
ReturnValue_t result = convertReturnCode(status); ReturnValue_t result = convertReturnCode(status);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
error << "TaskBase::TaskBase: createTask with name " << std::hex sif::error << "TaskBase::TaskBase: createTask with name " << std::hex
<< osalName << std::dec << " failed with return code " << osalName << std::dec << " failed with return code "
<< (uint32_t) status << std::endl; << (uint32_t) status << std::endl;
this->id = 0; this->id = 0;

View File

@ -1,5 +1,5 @@
#ifndef TASKBASE_H_ #ifndef FSFW_OSAL_RTEMS_TASKBASE_H_
#define TASKBASE_H_ #define FSFW_OSAL_RTEMS_TASKBASE_H_
#include "RtemsBasic.h" #include "RtemsBasic.h"
#include "../../tasks/PeriodicTaskIF.h" #include "../../tasks/PeriodicTaskIF.h"
@ -44,4 +44,4 @@ private:
}; };
#endif /* TASKBASE_H_ */ #endif /* FSFW_OSAL_RTEMS_TASKBASE_H_ */

View File

@ -0,0 +1,148 @@
#include "TcWinUdpPollingTask.h"
#include "../../globalfunctions/arrayprinter.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <winsock2.h>
#include <windows.h>
TcWinUdpPollingTask::TcWinUdpPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t frameSize,
double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) {
if(frameSize > 0) {
this->frameSize = frameSize;
}
else {
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
}
// Set up reception buffer with specified frame size.
// For now, it is assumed that only one frame is held in the buffer!
receptionBuffer.reserve(this->frameSize);
receptionBuffer.resize(this->frameSize);
if(timeoutSeconds == -1) {
receptionTimeout = DEFAULT_TIMEOUT;
}
else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
TcWinUdpPollingTask::~TcWinUdpPollingTask() {}
ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) {
// Poll for new UDP datagrams in permanent loop.
while(true) {
//! Sender Address is cached here.
struct sockaddr_in senderAddress;
int senderAddressSize = sizeof(senderAddress);
ssize_t bytesReceived = recvfrom(serverUdpSocket,
reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
receptionFlags, reinterpret_cast<sockaddr*>(&senderAddress),
&senderAddressSize);
if(bytesReceived == SOCKET_ERROR) {
// handle error
sif::error << "TcWinUdpPollingTask::performOperation: Reception"
" error." << std::endl;
handleReadError();
continue;
}
//sif::debug << "TcWinUdpPollingTask::performOperation: " << bytesReceived
// << " bytes received" << std::endl;
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if(result != HasReturnvaluesIF::RETURN_FAILED) {
}
tmtcBridge->registerCommConnect();
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId,
receptionBuffer.data(), bytesRead);
// arrayprinter::print(receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
"storage failed" << std::endl;
sif::error << "Packet size: " << bytesRead << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Serial Polling: Sending message to queue failed"
<< std::endl;
tcStore->deleteData(storeId);
}
return result;
}
ReturnValue_t TcWinUdpPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<TmTcWinUdpBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) {
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
" TMTC bridge object!" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
serverUdpSocket = tmtcBridge->serverSocket;
//sif::info << "TcWinUdpPollingTask::initialize: Server UDP socket "
// << serverUdpSocket << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcWinUdpPollingTask::initializeAfterTaskCreation() {
// Initialize the destination after task creation. This ensures
// that the destination has already been set in the TMTC bridge.
targetTcDestination = tmtcBridge->getRequestQueue();
return HasReturnvaluesIF::RETURN_OK;
}
void TcWinUdpPollingTask::setTimeout(double timeoutSeconds) {
DWORD timeoutMs = timeoutSeconds * 1000.0;
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
if(result == -1) {
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
}
}
void TcWinUdpPollingTask::handleReadError() {
int error = WSAGetLastError();
switch(error) {
case(WSANOTINITIALISED): {
sif::info << "TmTcWinUdpBridge::handleReadError: WSANOTINITIALISED: "
<< "WSAStartup(...) call " << "necessary" << std::endl;
break;
}
case(WSAEFAULT): {
sif::info << "TmTcWinUdpBridge::handleReadError: WSADEFAULT: "
<< "Bad address " << std::endl;
break;
}
default: {
sif::info << "TmTcWinUdpBridge::handleReadError: Error code: "
<< error << std::endl;
break;
}
}
// to prevent spam.
Sleep(1000);
}

View File

@ -0,0 +1,67 @@
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
#include "TmTcWinUdpBridge.h"
#include "../../objectmanager/SystemObject.h"
#include "../../tasks/ExecutableObjectIF.h"
#include "../../storagemanager/StorageManagerIF.h"
#include <vector>
/**
* @brief This class can be used to implement the polling of a Unix socket,
* using UDP for now.
* @details
* The task will be blocked while the specified number of bytes has not been
* received, so TC reception is handled inside a separate task.
* This class caches the IP address of the sender. It is assumed there
* is only one sender for now.
*/
class TcWinUdpPollingTask: public SystemObject,
public ExecutableObjectIF {
friend class TmTcWinUdpBridge;
public:
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
//! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
TcWinUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
size_t frameSize = 0, double timeoutSeconds = -1);
virtual~ TcWinUdpPollingTask();
/**
* Turn on optional timeout for UDP polling. In the default mode,
* the receive function will block until a packet is received.
* @param timeoutSeconds
*/
void setTimeout(double timeoutSeconds);
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
protected:
StorageManagerIF* tcStore = nullptr;
private:
//! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT;
TmTcWinUdpBridge* tmtcBridge = nullptr;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
//! Reception flags: https://linux.die.net/man/2/recvfrom.
int receptionFlags = 0;
//! Server socket, which is member of TMTC bridge and is assigned in
//! constructor
SOCKET serverUdpSocket = 0;
std::vector<uint8_t> receptionBuffer;
size_t frameSize = 0;
timeval receptionTimeout;
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
void handleReadError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */

View File

@ -0,0 +1,176 @@
#include <fsfw/ipc/MutexHelper.h>
#include "TmTcWinUdpBridge.h"
TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId,
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort, uint16_t clientPort):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
// Initiates Winsock DLL.
WSAData wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge:"
"WSAStartup failed with error: " << err << std::endl;
return;
}
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
if(serverPort != 0xFFFF) {
setServerPort = serverPort;
}
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
if(clientPort != 0xFFFF) {
setClientPort = clientPort;
}
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(serverSocket == INVALID_SOCKET) {
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not open"
" UDP socket!" << std::endl;
handleSocketError();
return;
}
serverAddress.sin_family = AF_INET;
// Accept packets from any interface. (potentially insecure).
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(setServerPort);
serverAddressLen = sizeof(serverAddress);
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<const char*>(&serverSocketOptions),
sizeof(serverSocketOptions));
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddress.sin_port = htons(setClientPort);
clientAddressLen = sizeof(clientAddress);
int result = bind(serverSocket,
reinterpret_cast<struct sockaddr*>(&serverAddress),
serverAddressLen);
if(result != 0) {
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind "
"local port " << setServerPort << " to server socket!"
<< std::endl;
handleBindError();
}
}
TmTcWinUdpBridge::~TmTcWinUdpBridge() {
WSACleanup();
}
ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
//clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
//clientAddressLen = sizeof(serverAddress);
// char ipAddress [15];
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
ssize_t bytesSent = sendto(serverSocket,
reinterpret_cast<const char*>(data), dataLen, flags,
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
if(bytesSent == SOCKET_ERROR) {
sif::error << "TmTcWinUdpBridge::sendTm: Send operation failed."
<< std::endl;
handleSendError();
}
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
// " sent." << std::endl;
return HasReturnvaluesIF::RETURN_OK;
return HasReturnvaluesIF::RETURN_OK;
}
void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
// char ipAddress [15];
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// Set new IP address if it has changed.
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
clientAddressLen = sizeof(clientAddress);
}
}
void TmTcWinUdpBridge::handleSocketError() {
int errCode = WSAGetLastError();
switch(errCode) {
case(WSANOTINITIALISED): {
sif::info << "TmTcWinUdpBridge::handleSocketError: WSANOTINITIALISED: "
<< "WSAStartup(...) call " << "necessary" << std::endl;
break;
}
default: {
/*
https://docs.microsoft.com/en-us/windows/win32/winsock/
windows-sockets-error-codes-2
*/
sif::info << "TmTcWinUdpBridge::handleSocketError: Error code: "
<< errCode << std::endl;
break;
}
}
}
void TmTcWinUdpBridge::handleBindError() {
int errCode = WSAGetLastError();
switch(errCode) {
case(WSANOTINITIALISED): {
sif::info << "TmTcWinUdpBridge::handleBindError: WSANOTINITIALISED: "
<< "WSAStartup(...) call " << "necessary" << std::endl;
break;
}
default: {
/*
https://docs.microsoft.com/en-us/windows/win32/winsock/
windows-sockets-error-codes-2
*/
sif::info << "TmTcWinUdpBridge::handleBindError: Error code: "
<< errCode << std::endl;
break;
}
}
}
void TmTcWinUdpBridge::handleSendError() {
int errCode = WSAGetLastError();
switch(errCode) {
case(WSANOTINITIALISED): {
sif::info << "TmTcWinUdpBridge::handleSendError: WSANOTINITIALISED: "
<< "WSAStartup(...) call " << "necessary" << std::endl;
break;
}
case(WSAEADDRNOTAVAIL): {
sif::info << "TmTcWinUdpBridge::handleReadError: WSAEADDRNOTAVAIL: "
<< "Check target address. " << std::endl;
break;
}
default: {
/*
https://docs.microsoft.com/en-us/windows/win32/winsock/
windows-sockets-error-codes-2
*/
sif::info << "TmTcWinUdpBridge::handleSendError: Error code: "
<< errCode << std::endl;
break;
}
}
}

View File

@ -0,0 +1,49 @@
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
#include "../../tmtcservices/TmTcBridge.h"
#include <winsock2.h>
#include <windows.h>
class TmTcWinUdpBridge: public TmTcBridge {
friend class TcWinUdpPollingTask;
public:
// The ports chosen here should not be used by any other process.
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
virtual~ TmTcWinUdpBridge();
void checkAndSetClientAddress(sockaddr_in clientAddress);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
SOCKET serverSocket = 0;
const int serverSocketOptions = 0;
struct sockaddr_in clientAddress;
int clientAddressLen = 0;
struct sockaddr_in serverAddress;
int serverAddressLen = 0;
//! Access to the client address is mutex protected as it is set
//! by another task.
MutexIF* mutex;
void handleSocketError();
void handleBindError();
void handleSendError();
};
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */

View File

@ -1,5 +1,5 @@
#ifndef FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ #ifndef FSFW_RETURNVALUES_HASRETURNVALUESIF_H_
#define FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ #define FSFW_RETURNVALUES_HASRETURNVALUESIF_H_
#include "FwClassIds.h" #include "FwClassIds.h"
#include <config/returnvalues/classIds.h> #include <config/returnvalues/classIds.h>
@ -15,9 +15,17 @@ public:
static const ReturnValue_t RETURN_FAILED = 1; static const ReturnValue_t RETURN_FAILED = 1;
virtual ~HasReturnvaluesIF() {} virtual ~HasReturnvaluesIF() {}
static ReturnValue_t makeReturnCode(uint8_t interfaceId, uint8_t number) { /**
return (interfaceId << 8) + number; * It is discouraged to use the input parameters 0,0 and 0,1 as this
* will generate the RETURN_OK and RETURN_FAILED returnvalues.
* @param interfaceId
* @param number
* @return
*/
static constexpr ReturnValue_t makeReturnCode(uint8_t interfaceId,
uint8_t number) {
return (static_cast<ReturnValue_t>(interfaceId) << 8) + number;
} }
}; };
#endif /* FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ */ #endif /* FSFW_RETURNVALUES_HASRETURNVALUESIF_H_ */

View File

@ -1,31 +1,39 @@
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "CCSDSDistributor.h" #include "CCSDSDistributor.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../tmtcpacket/SpacePacketBase.h" #include "../tmtcpacket/SpacePacketBase.h"
CCSDSDistributor::CCSDSDistributor( uint16_t setDefaultApid, object_id_t setObjectId ) : CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid,
TcDistributor( setObjectId ), default_apid( setDefaultApid ), tcStore(NULL) { object_id_t setObjectId):
TcDistributor(setObjectId), defaultApid( setDefaultApid ) {
} }
CCSDSDistributor::~CCSDSDistributor() { CCSDSDistributor::~CCSDSDistributor() {}
} TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() {
// sif::debug << "CCSDSDistributor::selectDestination received: " <<
iterator_t CCSDSDistributor::selectDestination() { // this->currentMessage.getStorageId().pool_index << ", " <<
// sif::debug << "CCSDSDistributor::selectDestination received: " << this->currentMessage.getStorageId().pool_index << ", " << this->currentMessage.getStorageId().packet_index << std::endl; // this->currentMessage.getStorageId().packet_index << std::endl;
const uint8_t* p_packet = NULL; const uint8_t* packet = nullptr;
size_t size = 0; size_t size = 0;
//TODO check returncode? ReturnValue_t result = this->tcStore->getData(currentMessage.getStorageId(),
this->tcStore->getData( this->currentMessage.getStorageId(), &p_packet, &size ); &packet, &size );
SpacePacketBase current_packet( p_packet ); if(result != HasReturnvaluesIF::RETURN_OK) {
// info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex << current_packet.getAPID() << std::dec << std::endl; sif::error << "CCSDSDistributor::selectDestination: Getting data from"
iterator_t position = this->queueMap.find( current_packet.getAPID() ); " store failed!" << std::endl;
}
SpacePacketBase currentPacket(packet);
// sif:: info << "CCSDSDistributor::selectDestination has packet with APID "
// << std::hex << currentPacket.getAPID() << std::dec << std::endl;
TcMqMapIter position = this->queueMap.find(currentPacket.getAPID());
if ( position != this->queueMap.end() ) { if ( position != this->queueMap.end() ) {
return position; return position;
} else { } else {
//The APID was not found. Forward packet to main SW-APID anyway to create acceptance failure report. //The APID was not found. Forward packet to main SW-APID anyway to
return this->queueMap.find( this->default_apid ); // create acceptance failure report.
return this->queueMap.find( this->defaultApid );
} }
} }
MessageQueueId_t CCSDSDistributor::getRequestQueue() { MessageQueueId_t CCSDSDistributor::getRequestQueue() {
@ -35,9 +43,9 @@ MessageQueueId_t CCSDSDistributor::getRequestQueue() {
ReturnValue_t CCSDSDistributor::registerApplication( ReturnValue_t CCSDSDistributor::registerApplication(
AcceptsTelecommandsIF* application) { AcceptsTelecommandsIF* application) {
ReturnValue_t returnValue = RETURN_OK; ReturnValue_t returnValue = RETURN_OK;
bool errorCode = true; auto insertPair = this->queueMap.emplace(application->getIdentifier(),
errorCode = this->queueMap.insert( std::pair<uint32_t, MessageQueueId_t>( application->getIdentifier(), application->getRequestQueue() ) ).second; application->getRequestQueue());
if( errorCode == false ) { if(not insertPair.second) {
returnValue = RETURN_FAILED; returnValue = RETURN_FAILED;
} }
return returnValue; return returnValue;
@ -46,9 +54,8 @@ ReturnValue_t CCSDSDistributor::registerApplication(
ReturnValue_t CCSDSDistributor::registerApplication(uint16_t apid, ReturnValue_t CCSDSDistributor::registerApplication(uint16_t apid,
MessageQueueId_t id) { MessageQueueId_t id) {
ReturnValue_t returnValue = RETURN_OK; ReturnValue_t returnValue = RETURN_OK;
bool errorCode = true; auto insertPair = this->queueMap.emplace(apid, id);
errorCode = this->queueMap.insert( std::pair<uint32_t, MessageQueueId_t>( apid, id ) ).second; if(not insertPair.second) {
if( errorCode == false ) {
returnValue = RETURN_FAILED; returnValue = RETURN_FAILED;
} }
return returnValue; return returnValue;
@ -62,7 +69,11 @@ uint16_t CCSDSDistributor::getIdentifier() {
ReturnValue_t CCSDSDistributor::initialize() { ReturnValue_t CCSDSDistributor::initialize() {
ReturnValue_t status = this->TcDistributor::initialize(); ReturnValue_t status = this->TcDistributor::initialize();
this->tcStore = objectManager->get<StorageManagerIF>( objects::TC_STORE ); this->tcStore = objectManager->get<StorageManagerIF>( objects::TC_STORE );
if (this->tcStore == NULL) status = RETURN_FAILED; if (this->tcStore == nullptr) {
sif::error << "CCSDSDistributor::initialize: Could not initialize"
" TC store!" << std::endl;
status = RETURN_FAILED;
}
return status; return status;
} }

View File

@ -1,58 +1,71 @@
#ifndef CCSDSDISTRIBUTOR_H_ #ifndef FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_
#define CCSDSDISTRIBUTOR_H_ #define FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
#include "../storagemanager/StorageManagerIF.h" #include "../storagemanager/StorageManagerIF.h"
#include "CCSDSDistributorIF.h" #include "../tcdistribution/CCSDSDistributorIF.h"
#include "TcDistributor.h" #include "../tcdistribution/TcDistributor.h"
#include "../tmtcservices/AcceptsTelecommandsIF.h" #include "../tmtcservices/AcceptsTelecommandsIF.h"
/** /**
* An instantiation of the CCSDSDistributorIF. * @brief An instantiation of the CCSDSDistributorIF.
* It receives Space Packets, and selects a destination depending on the APID of the telecommands. * @details
* It receives Space Packets, and selects a destination depending on the
* APID of the telecommands.
* The Secondary Header (with Service/Subservice) is ignored. * The Secondary Header (with Service/Subservice) is ignored.
* \ingroup tc_distribution * @ingroup tc_distribution
*/ */
class CCSDSDistributor : public TcDistributor, public CCSDSDistributorIF, public AcceptsTelecommandsIF { class CCSDSDistributor : public TcDistributor,
protected: public CCSDSDistributorIF,
/** public AcceptsTelecommandsIF {
* This implementation checks if an Application with fitting APID has registered and forwards the
* packet to the according message queue.
* If the packet is not found, it returns the queue to \c default_apid, where a Acceptance Failure
* message should be generated.
* @return Iterator to map entry of found APID or iterator to default APID.
*/
iterator_t selectDestination();
/**
* The default APID, where packets with unknown APID are sent to.
*/
uint16_t default_apid;
/**
* A reference to the TC storage must be maintained, as this class handles pure Space Packets and there
* exists no SpacePacketStored class.
*/
StorageManagerIF* tcStore;
/**
* The callback here handles the generation of acceptance success/failure messages.
*/
ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus );
public: public:
/** /**
* The constructor sets the default APID and calls the TcDistributor ctor with a certain object id. * @brief The constructor sets the default APID and calls the
* \c tcStore is set in the \c initialize method. * TcDistributor ctor with a certain object id.
* @param set_default_apid The default APID, where packets with unknown destination are sent to. * @details
* @c tcStore is set in the @c initialize method.
* @param setDefaultApid The default APID, where packets with unknown
* destination are sent to.
*/ */
CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId); CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId);
/** /**
* The destructor is empty. * The destructor is empty.
*/ */
~CCSDSDistributor(); virtual ~CCSDSDistributor();
MessageQueueId_t getRequestQueue();
ReturnValue_t registerApplication( uint16_t apid, MessageQueueId_t id ); MessageQueueId_t getRequestQueue() override;
ReturnValue_t registerApplication( AcceptsTelecommandsIF* application ); ReturnValue_t registerApplication( uint16_t apid,
uint16_t getIdentifier(); MessageQueueId_t id) override;
ReturnValue_t initialize(); ReturnValue_t registerApplication(
AcceptsTelecommandsIF* application) override;
uint16_t getIdentifier() override;
ReturnValue_t initialize() override;
protected:
/**
* This implementation checks if an application with fitting APID has
* registered and forwards the packet to the according message queue.
* If the packet is not found, it returns the queue to @c defaultApid,
* where a Acceptance Failure message should be generated.
* @return Iterator to map entry of found APID or iterator to default APID.
*/
TcMqMapIter selectDestination() override;
/**
* The callback here handles the generation of acceptance
* success/failure messages.
*/
ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ) override;
/**
* The default APID, where packets with unknown APID are sent to.
*/
uint16_t defaultApid;
/**
* A reference to the TC storage must be maintained, as this class handles
* pure Space Packets and there exists no SpacePacketStored class.
*/
StorageManagerIF* tcStore = nullptr;
}; };
#endif /* FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ */
#endif /* CCSDSDISTRIBUTOR_H_ */

View File

@ -1,34 +1,38 @@
#ifndef CCSDSDISTRIBUTORIF_H_ #ifndef FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_
#define CCSDSDISTRIBUTORIF_H_ #define FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_
#include "../tmtcservices/AcceptsTelecommandsIF.h" #include "../tmtcservices/AcceptsTelecommandsIF.h"
#include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueSenderIF.h"
/** /**
* This is the Interface to a CCSDS Distributor. * This is the Interface to a CCSDS Distributor.
* On a CCSDS Distributor, Applications (in terms of CCSDS) may register themselves, * On a CCSDS Distributor, Applications (in terms of CCSDS) may register
* either by passing a pointer to themselves (and implementing the CCSDSApplicationIF, * themselves, either by passing a pointer to themselves (and implementing the
* or by explicitly passing an APID and a MessageQueueId to route the TC's to. * CCSDSApplicationIF), or by explicitly passing an APID and a MessageQueueId
* \ingroup tc_distribution * to route the TC's to.
* @ingroup tc_distribution
*/ */
class CCSDSDistributorIF { class CCSDSDistributorIF {
public: public:
/** /**
* With this call, a class implementing the CCSDSApplicationIF can register at the * With this call, a class implementing the CCSDSApplicationIF can register
* distributor. * at the distributor.
* @param application A pointer to the Application to register. * @param application A pointer to the Application to register.
* @return - \c RETURN_OK on success, * @return - @c RETURN_OK on success,
* - \c RETURN_FAILED on failure. * - @c RETURN_FAILED on failure.
*/ */
virtual ReturnValue_t registerApplication( AcceptsTelecommandsIF* application ) = 0; virtual ReturnValue_t registerApplication(
AcceptsTelecommandsIF* application) = 0;
/** /**
* With this call, other Applications can register to the CCSDS distributor. * With this call, other Applications can register to the CCSDS distributor.
* This is done by passing an APID and a MessageQueueId to the method. * This is done by passing an APID and a MessageQueueId to the method.
* @param apid The APID to register. * @param apid The APID to register.
* @param id The MessageQueueId of the message queue to send the TC Packets to. * @param id The MessageQueueId of the message queue to send the
* @return - \c RETURN_OK on success, * TC Packets to.
* - \c RETURN_FAILED on failure. * @return - @c RETURN_OK on success,
* - @c RETURN_FAILED on failure.
*/ */
virtual ReturnValue_t registerApplication( uint16_t apid, MessageQueueId_t id ) = 0; virtual ReturnValue_t registerApplication( uint16_t apid,
MessageQueueId_t id) = 0;
/** /**
* The empty virtual destructor. * The empty virtual destructor.
*/ */
@ -37,4 +41,4 @@ public:
}; };
#endif /* CCSDSDISTRIBUTORIF_H_ */ #endif /* FSFW_TCDISTRIBUTION_CCSDSDISTRIBUTORIF_H_ */

View File

@ -1,61 +1,74 @@
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "CCSDSDistributorIF.h" #include "CCSDSDistributorIF.h"
#include "PUSDistributor.h" #include "PUSDistributor.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../tmtcpacket/pus/TcPacketStored.h" #include "../tmtcpacket/pus/TcPacketStored.h"
#include "../tmtcservices/PusVerificationReport.h" #include "../tmtcservices/PusVerificationReport.h"
PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId, object_id_t setPacketSource) : PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId,
TcDistributor(setObjectId), checker(setApid), verifyChannel(), currentPacket(), tcStatus( object_id_t setPacketSource) :
RETURN_FAILED), packetSource(setPacketSource) { TcDistributor(setObjectId), checker(setApid), verifyChannel(),
tcStatus(RETURN_FAILED), packetSource(setPacketSource) {}
PUSDistributor::~PUSDistributor() {}
PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
// sif:: debug << "PUSDistributor::handlePacket received: "
// << this->current_packet_id.store_index << ", "
// << this->current_packet_id.packet_index << std::endl;
TcMqMapIter queueMapIt = this->queueMap.end();
if(this->currentPacket == nullptr) {
return queueMapIt;
} }
this->currentPacket->setStoreAddress(this->currentMessage.getStorageId());
PUSDistributor::~PUSDistributor() { if (currentPacket->getWholeData() != nullptr) {
tcStatus = checker.checkPacket(currentPacket);
#ifdef DEBUG
if(tcStatus != HasReturnvaluesIF::RETURN_OK) {
sif::debug << "PUSDistributor::handlePacket: Packet format "
<< "invalid, code "<< static_cast<int>(tcStatus)
<< std::endl;
} }
#endif
iterator_t PUSDistributor::selectDestination() { uint32_t queue_id = currentPacket->getService();
// sif::debug << "PUSDistributor::handlePacket received "<<std::endl;// << this->currentPacket.store_index << ", " << this->current_packet_id.packet_index << std::endl;
iterator_t queueMapIt = this->queueMap.end();
this->currentPacket.setStoreAddress(this->currentMessage.getStorageId());
if (currentPacket.getWholeData() != NULL) {
tcStatus = checker.checkPacket(&currentPacket);
// info << "PUSDistributor::handlePacket: packetCheck returned with " << (int)tc_status << std::endl;
uint32_t queue_id = currentPacket.getService();
queueMapIt = this->queueMap.find(queue_id); queueMapIt = this->queueMap.find(queue_id);
} else { }
else {
tcStatus = PACKET_LOST; tcStatus = PACKET_LOST;
} }
if (queueMapIt == this->queueMap.end()) { if (queueMapIt == this->queueMap.end()) {
tcStatus = DESTINATION_NOT_FOUND; tcStatus = DESTINATION_NOT_FOUND;
#ifdef DEBUG
sif::debug << "PUSDistributor::handlePacket: Destination not found, "
<< "code "<< static_cast<int>(tcStatus) << std::endl;
#endif
} }
if (tcStatus != RETURN_OK) { if (tcStatus != RETURN_OK) {
sif::debug << "PUSDistributor::handlePacket: error with " << (int) tcStatus sif::debug << "PUSDistributor::handlePacket: error with " << (int) tcStatus
<< std::endl; << std::endl;
return this->queueMap.end(); return this->queueMap.end();
} else { }
else {
return queueMapIt; return queueMapIt;
} }
} }
//uint16_t PUSDistributor::createDestination( uint8_t service_id, uint8_t subservice_id ) {
// return ( service_id << 8 ) + subservice_id;
//}
ReturnValue_t PUSDistributor::registerService(AcceptsTelecommandsIF* service) { ReturnValue_t PUSDistributor::registerService(AcceptsTelecommandsIF* service) {
ReturnValue_t returnValue = RETURN_OK;
bool errorCode = true;
uint16_t serviceId = service->getIdentifier(); uint16_t serviceId = service->getIdentifier();
// sif::info << "Service ID: " << (int)serviceId << std::endl;
MessageQueueId_t queue = service->getRequestQueue(); MessageQueueId_t queue = service->getRequestQueue();
errorCode = this->queueMap.insert( auto returnPair = queueMap.emplace(serviceId, queue);
std::pair<uint32_t, MessageQueueId_t>(serviceId, queue)).second; if (not returnPair.second) {
if (errorCode == false) { sif::error << "PUSDistributor::registerService: Service ID already"
//TODO Return Code " exists in map." << std::endl;
returnValue = MessageQueueIF::NO_QUEUE; return SERVICE_ID_ALREADY_EXISTS;
} }
return returnValue; return HasReturnvaluesIF::RETURN_OK;
} }
MessageQueueId_t PUSDistributor::getRequestQueue() { MessageQueueId_t PUSDistributor::getRequestQueue() {
@ -68,13 +81,14 @@ ReturnValue_t PUSDistributor::callbackAfterSending(ReturnValue_t queueStatus) {
} }
if (tcStatus != RETURN_OK) { if (tcStatus != RETURN_OK) {
this->verifyChannel.sendFailureReport(TC_VERIFY::ACCEPTANCE_FAILURE, this->verifyChannel.sendFailureReport(TC_VERIFY::ACCEPTANCE_FAILURE,
&currentPacket, tcStatus); currentPacket, tcStatus);
//A failed packet is deleted immediately after reporting, otherwise it will block memory. // A failed packet is deleted immediately after reporting,
currentPacket.deletePacket(); // otherwise it will block memory.
currentPacket->deletePacket();
return RETURN_FAILED; return RETURN_FAILED;
} else { } else {
this->verifyChannel.sendSuccessReport(TC_VERIFY::ACCEPTANCE_SUCCESS, this->verifyChannel.sendSuccessReport(TC_VERIFY::ACCEPTANCE_SUCCESS,
&currentPacket); currentPacket);
return RETURN_OK; return RETURN_OK;
} }
} }
@ -84,11 +98,19 @@ uint16_t PUSDistributor::getIdentifier() {
} }
ReturnValue_t PUSDistributor::initialize() { ReturnValue_t PUSDistributor::initialize() {
currentPacket = new TcPacketStored();
if(currentPacket == nullptr) {
// Should not happen, memory allocation failed!
return ObjectManagerIF::CHILD_INIT_FAILED;
}
CCSDSDistributorIF* ccsdsDistributor = CCSDSDistributorIF* ccsdsDistributor =
objectManager->get<CCSDSDistributorIF>(packetSource); objectManager->get<CCSDSDistributorIF>(packetSource);
if (ccsdsDistributor == NULL) { if (ccsdsDistributor == nullptr) {
sif::error << "PUSDistributor::initialize: Packet source invalid."
<< " Make sure it exists and implements CCSDSDistributorIF!"
<< std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} else { }
return ccsdsDistributor->registerApplication(this); return ccsdsDistributor->registerApplication(this);
} }
}

View File

@ -1,67 +1,79 @@
#ifndef PUSDISTRIBUTOR_H_ #ifndef FSFW_TCDISTRIBUTION_PUSDISTRIBUTOR_H_
#define PUSDISTRIBUTOR_H_ #define FSFW_TCDISTRIBUTION_PUSDISTRIBUTOR_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include "PUSDistributorIF.h" #include "PUSDistributorIF.h"
#include "TcDistributor.h" #include "TcDistributor.h"
#include "TcPacketCheck.h" #include "TcPacketCheck.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../tmtcservices/AcceptsTelecommandsIF.h" #include "../tmtcservices/AcceptsTelecommandsIF.h"
#include "../tmtcservices/VerificationReporter.h" #include "../tmtcservices/VerificationReporter.h"
/** /**
* This class accepts PUS Telecommands and forwards them to Application services. * This class accepts PUS Telecommands and forwards them to Application
* In addition, the class performs a formal packet check and sends acceptance success * services. In addition, the class performs a formal packet check and
* or failure messages. * sends acceptance success or failure messages.
* \ingroup tc_distribution * @ingroup tc_distribution
*/ */
class PUSDistributor: public TcDistributor, class PUSDistributor: public TcDistributor,
public PUSDistributorIF, public PUSDistributorIF,
public AcceptsTelecommandsIF { public AcceptsTelecommandsIF {
public: public:
/** /**
* The ctor passes \c set_apid to the checker class and calls the TcDistribution ctor with a certain object id. * The ctor passes @c set_apid to the checker class and calls the
* TcDistribution ctor with a certain object id.
* @param setApid The APID of this receiving Application. * @param setApid The APID of this receiving Application.
* @param setObjectId Object ID of the distributor itself * @param setObjectId Object ID of the distributor itself
* @param setPacketSource Object ID of the source of TC packets. Must implement CCSDSDistributorIF. * @param setPacketSource Object ID of the source of TC packets.
* Must implement CCSDSDistributorIF.
*/ */
PUSDistributor(uint16_t setApid, object_id_t setObjectId, object_id_t setPacketSource); PUSDistributor(uint16_t setApid, object_id_t setObjectId,
object_id_t setPacketSource);
/** /**
* The destructor is empty. * The destructor is empty.
*/ */
virtual ~PUSDistributor(); virtual ~PUSDistributor();
ReturnValue_t registerService(AcceptsTelecommandsIF* service); ReturnValue_t registerService(AcceptsTelecommandsIF* service) override;
MessageQueueId_t getRequestQueue(); MessageQueueId_t getRequestQueue() override;
uint16_t getIdentifier(); ReturnValue_t initialize() override;
ReturnValue_t initialize(); uint16_t getIdentifier() override;
protected: protected:
/** /**
* This attribute contains the class, that performs a formal packet check. * This attribute contains the class, that performs a formal packet check.
*/ */
TcPacketCheck checker; TcPacketCheck checker;
/** /**
* With this class, verification messages are sent to the TC Verification service. * With this class, verification messages are sent to the
* TC Verification service.
*/ */
VerificationReporter verifyChannel; VerificationReporter verifyChannel;
/** /**
* The currently handled packet is stored here. * The currently handled packet is stored here.
*/ */
TcPacketStored currentPacket; TcPacketStored* currentPacket = nullptr;
/** /**
* With this variable, the current check status is stored to generate acceptance messages later. * With this variable, the current check status is stored to generate
* acceptance messages later.
*/ */
ReturnValue_t tcStatus; ReturnValue_t tcStatus;
const object_id_t packetSource; const object_id_t packetSource;
/** /**
* This method reads the packet service, checks if such a service is registered and forwards the packet to the destination. * This method reads the packet service, checks if such a service is
* It also initiates the formal packet check and sending of verification messages. * registered and forwards the packet to the destination.
* @return Iterator to map entry of found service id or iterator to \c map.end(). * It also initiates the formal packet check and sending of verification
* messages.
* @return Iterator to map entry of found service id
* or iterator to @c map.end().
*/ */
iterator_t selectDestination(); TcMqMapIter selectDestination() override;
/** /**
* The callback here handles the generation of acceptance success/failure messages. * The callback here handles the generation of acceptance
* success/failure messages.
*/ */
ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus); ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus) override;
}; };
#endif /* PUSDISTRIBUTOR_H_ */ #endif /* FSFW_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ */

View File

@ -1,11 +1,12 @@
#ifndef PUSDISTRIBUTORIF_H_ #ifndef FSFW_TCDISTRIBUTION_PUSDISTRIBUTORIF_H_
#define PUSDISTRIBUTORIF_H_ #define FSFW_TCDISTRIBUTION_PUSDISTRIBUTORIF_H_
#include "../tmtcservices/AcceptsTelecommandsIF.h" #include "../tmtcservices/AcceptsTelecommandsIF.h"
#include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueSenderIF.h"
/** /**
* This interface allows PUS Services to register themselves at a PUS Distributor. * This interface allows PUS Services to register themselves at a PUS Distributor.
* \ingroup tc_distribution * @ingroup tc_distribution
*/ */
class PUSDistributorIF { class PUSDistributorIF {
public: public:
@ -17,10 +18,10 @@ public:
/** /**
* With this method, Services can register themselves at the PUS Distributor. * With this method, Services can register themselves at the PUS Distributor.
* @param service A pointer to the registering Service. * @param service A pointer to the registering Service.
* @return - \c RETURN_OK on success, * @return - @c RETURN_OK on success,
* - \c RETURN_FAILED on failure. * - @c RETURN_FAILED on failure.
*/ */
virtual ReturnValue_t registerService( AcceptsTelecommandsIF* service ) = 0; virtual ReturnValue_t registerService( AcceptsTelecommandsIF* service ) = 0;
}; };
#endif /* PUSDISTRIBUTORIF_H_ */ #endif /* FSFW_TCDISTRIBUTION_PUSDISTRIBUTORIF_H_ */

View File

@ -1,12 +1,13 @@
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "TcDistributor.h" #include "TcDistributor.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../tmtcservices/TmTcMessage.h" #include "../tmtcservices/TmTcMessage.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
TcDistributor::TcDistributor(object_id_t set_object_id) : TcDistributor::TcDistributor(object_id_t objectId) :
SystemObject(set_object_id), tcQueue(NULL) { SystemObject(objectId) {
tcQueue = QueueFactory::instance()->createMessageQueue(DISTRIBUTER_MAX_PACKETS); tcQueue = QueueFactory::instance()->
createMessageQueue(DISTRIBUTER_MAX_PACKETS);
} }
TcDistributor::~TcDistributor() { TcDistributor::~TcDistributor() {
@ -15,7 +16,6 @@ TcDistributor::~TcDistributor() {
ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { ReturnValue_t TcDistributor::performOperation(uint8_t opCode) {
ReturnValue_t status = RETURN_OK; ReturnValue_t status = RETURN_OK;
//sif::debug << "TcDistributor: performing Operation." << std::endl;
for (status = tcQueue->receiveMessage(&currentMessage); status == RETURN_OK; for (status = tcQueue->receiveMessage(&currentMessage); status == RETURN_OK;
status = tcQueue->receiveMessage(&currentMessage)) { status = tcQueue->receiveMessage(&currentMessage)) {
status = handlePacket(); status = handlePacket();
@ -29,7 +29,7 @@ ReturnValue_t TcDistributor::performOperation(uint8_t opCode) {
ReturnValue_t TcDistributor::handlePacket() { ReturnValue_t TcDistributor::handlePacket() {
iterator_t queueMapIt = this->selectDestination(); TcMqMapIter queueMapIt = this->selectDestination();
ReturnValue_t returnValue = RETURN_FAILED; ReturnValue_t returnValue = RETURN_FAILED;
// sif::debug << "TcDistributor::handlePacket" << std::endl; // sif::debug << "TcDistributor::handlePacket" << std::endl;
if (queueMapIt != this->queueMap.end()) { if (queueMapIt != this->queueMap.end()) {
@ -40,14 +40,14 @@ ReturnValue_t TcDistributor::handlePacket() {
} }
void TcDistributor::print() { void TcDistributor::print() {
sif::debug << "Distributor content is: " << std::endl << "ID\t| message queue id" sif::debug << "Distributor content is: " << std::endl
<< std::endl; << "ID\t| Message Queue ID" << std::endl;
for (iterator_t it = this->queueMap.begin(); it != this->queueMap.end(); sif::debug << std::setfill('0') << std::setw(8) << std::hex;
it++) { for (const auto& queueMapIter: queueMap) {
sif::debug << it->first << "\t| 0x" << std::hex << it->second << std::dec sif::debug << queueMapIter.first << "\t| 0x" << queueMapIter.second
<< std::endl; << std::endl;
} }
sif::debug << std::dec; sif::debug << std::setfill(' ') << std::dec;
} }

View File

@ -1,5 +1,6 @@
#ifndef TCDISTRIBUTOR_H_ #ifndef FSFW_TMTCSERVICES_TCDISTRIBUTOR_H_
#define TCDISTRIBUTOR_H_ #define FSFW_TMTCSERVICES_TCDISTRIBUTOR_H_
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
@ -9,16 +10,12 @@
#include "../ipc/MessageQueueIF.h" #include "../ipc/MessageQueueIF.h"
#include <map> #include <map>
/** /**
* \defgroup tc_distribution Telecommand Distribution * @defgroup tc_distribution Telecommand Distribution
* All classes associated with Routing and Distribution of Telecommands belong to this group. * All classes associated with Routing and Distribution of Telecommands
* belong to this group.
*/ */
/**
* This typedef simplifies writing down the \c map iterator.
*/
typedef std::map<uint32_t, MessageQueueId_t>::iterator iterator_t;
/** /**
* This is the base class to implement distributors for Space Packets. * This is the base class to implement distributors for Space Packets.
@ -28,62 +25,19 @@ typedef std::map<uint32_t, MessageQueueId_t>::iterator iterator_t;
* message queue ids to some identifier. The process of unpacking the * message queue ids to some identifier. The process of unpacking the
* destination information from the packet is handled by the child class * destination information from the packet is handled by the child class
* implementations. * implementations.
* \ingroup tc_distribution * @ingroup tc_distribution
*/ */
class TcDistributor : public SystemObject, public ExecutableObjectIF, public HasReturnvaluesIF { class TcDistributor : public SystemObject,
private: public ExecutableObjectIF,
/** public HasReturnvaluesIF {
* This constant sets the maximum number of packets distributed per call.
*/
static const uint8_t DISTRIBUTER_MAX_PACKETS = 128;
protected:
/**
* This is the receiving queue for incoming Telecommands.
* The child classes must make its queue id public.
*/
MessageQueueIF* tcQueue;
/**
* The last received incoming packet information is stored in this
* member.
* As different child classes unpack the incoming packet differently
* (i.e. as a CCSDS Space Packet or as a PUS Telecommand Packet), it
* is not tried to unpack the packet information within this class.
*/
TmTcMessage currentMessage;
/**
* The map that links certain packet information to a destination.
* The packet information may be the APID of the packet or the service
* identifier. Filling of the map is under control of the different child
* classes.
*/
std::map<uint32_t, MessageQueueId_t> queueMap;
/**
* This method shall unpack the routing information from the incoming
* packet and select the map entry which represents the packet's target.
* @return An iterator to the map element to forward to or queuMap.end().
*/
virtual iterator_t selectDestination() = 0;
/**
* The handlePacket method calls the child class's selectDestination method
* and forwards the packet to its destination, if found.
* @return The message queue return value or \c RETURN_FAILED, in case no
* destination was found.
*/
ReturnValue_t handlePacket();
/**
* This method gives the child class a chance to perform some kind of operation
* after the parent tried to forward the message.
* A typically application would be sending success/failure messages.
* The default implementation just returns \c RETURN_OK.
* @param queueStatus The status of the message queue after an attempt to send the TC.
* @return - \c RETURN_OK on success
* - \c RETURN_FAILED on failure
*/
virtual ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus );
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::PACKET_DISTRIBUTION; using TcMessageQueueMap = std::map<uint32_t, MessageQueueId_t>;
static const ReturnValue_t PACKET_LOST = MAKE_RETURN_CODE( 1 ); using TcMqMapIter = std::map<uint32_t, MessageQueueId_t>::iterator;
static const ReturnValue_t DESTINATION_NOT_FOUND = MAKE_RETURN_CODE( 2 );
static constexpr uint8_t INTERFACE_ID = CLASS_ID::PACKET_DISTRIBUTION;
static constexpr ReturnValue_t PACKET_LOST = MAKE_RETURN_CODE( 1 );
static constexpr ReturnValue_t DESTINATION_NOT_FOUND = MAKE_RETURN_CODE( 2 );
static constexpr ReturnValue_t SERVICE_ID_ALREADY_EXISTS = MAKE_RETURN_CODE(3);
/** /**
* Within the default constructor, the SystemObject id is set and the * Within the default constructor, the SystemObject id is set and the
* message queue is initialized. * message queue is initialized.
@ -91,7 +45,7 @@ public:
* @param set_object_id This id is assigned to the distributor * @param set_object_id This id is assigned to the distributor
* implementation. * implementation.
*/ */
TcDistributor( object_id_t set_object_id ); TcDistributor(object_id_t objectId);
/** /**
* The destructor is empty, the message queues are not in the vicinity of * The destructor is empty, the message queues are not in the vicinity of
* this class. * this class.
@ -110,7 +64,59 @@ public:
* queueMap. * queueMap.
*/ */
void print(); void print();
protected:
/**
* This is the receiving queue for incoming Telecommands.
* The child classes must make its queue id public.
*/
MessageQueueIF* tcQueue = nullptr;
/**
* The last received incoming packet information is stored in this
* member.
* As different child classes unpack the incoming packet differently
* (i.e. as a CCSDS Space Packet or as a PUS Telecommand Packet), it
* is not tried to unpack the packet information within this class.
*/
TmTcMessage currentMessage;
/**
* The map that links certain packet information to a destination.
* The packet information may be the APID of the packet or the service
* identifier. Filling of the map is under control of the different child
* classes.
*/
TcMessageQueueMap queueMap;
/**
* This method shall unpack the routing information from the incoming
* packet and select the map entry which represents the packet's target.
* @return An iterator to the map element to forward to or queuMap.end().
*/
virtual TcMqMapIter selectDestination() = 0;
/**
* The handlePacket method calls the child class's selectDestination method
* and forwards the packet to its destination, if found.
* @return The message queue return value or @c RETURN_FAILED, in case no
* destination was found.
*/
ReturnValue_t handlePacket();
/**
* This method gives the child class a chance to perform some kind of
* operation after the parent tried to forward the message.
* A typically application would be sending success/failure messages.
* The default implementation just returns @c RETURN_OK.
* @param queueStatus The status of the message queue after an attempt
* to send the TC.
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
virtual ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus );
private:
/**
* This constant sets the maximum number of packets distributed per call.
*/
static constexpr uint8_t DISTRIBUTER_MAX_PACKETS = 128;
}; };
#endif /* TCDISTRIBUTOR_H_ */ #endif /* FSFW_TMTCSERVICES_TCDISTRIBUTOR_H_ */

View File

@ -1,31 +1,33 @@
#include "TcPacketCheck.h"
#include "../globalfunctions/CRC.h" #include "../globalfunctions/CRC.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
#include "../storagemanager/StorageManagerIF.h" #include "../storagemanager/StorageManagerIF.h"
#include "TcPacketCheck.h"
#include "../tmtcservices/VerificationCodes.h" #include "../tmtcservices/VerificationCodes.h"
TcPacketCheck::TcPacketCheck( uint16_t set_apid ) : apid(set_apid) { TcPacketCheck::TcPacketCheck( uint16_t setApid ) : apid(setApid) {
} }
ReturnValue_t TcPacketCheck::checkPacket( TcPacketStored* current_packet ) { ReturnValue_t TcPacketCheck::checkPacket( TcPacketStored* currentPacket ) {
uint16_t calculated_crc = CRC::crc16ccitt( current_packet->getWholeData(), current_packet->getFullSize() ); uint16_t calculated_crc = CRC::crc16ccitt( currentPacket->getWholeData(),
currentPacket->getFullSize() );
if ( calculated_crc != 0 ) { if ( calculated_crc != 0 ) {
return INCORRECT_CHECKSUM; return INCORRECT_CHECKSUM;
} }
bool condition = !(current_packet->hasSecondaryHeader()) || bool condition = (not currentPacket->hasSecondaryHeader()) or
current_packet->getPacketVersionNumber() != CCSDS_VERSION_NUMBER || (currentPacket->getPacketVersionNumber() != CCSDS_VERSION_NUMBER) or
!(current_packet->isTelecommand()); (not currentPacket->isTelecommand());
if ( condition ) { if ( condition ) {
return INCORRECT_PRIMARY_HEADER; return INCORRECT_PRIMARY_HEADER;
} }
if ( current_packet->getAPID() != this->apid ) if ( currentPacket->getAPID() != this->apid )
return ILLEGAL_APID; return ILLEGAL_APID;
if ( !current_packet->isSizeCorrect() ) { if ( not currentPacket->isSizeCorrect() ) {
return INCOMPLETE_PACKET; return INCOMPLETE_PACKET;
} }
condition = (current_packet->getSecondaryHeaderFlag() != CCSDS_SECONDARY_HEADER_FLAG) || condition = (currentPacket->getSecondaryHeaderFlag() != CCSDS_SECONDARY_HEADER_FLAG) ||
(current_packet->getPusVersionNumber() != PUS_VERSION_NUMBER); (currentPacket->getPusVersionNumber() != PUS_VERSION_NUMBER);
if ( condition ) { if ( condition ) {
return INCORRECT_SECONDARY_HEADER; return INCORRECT_SECONDARY_HEADER;
} }

View File

@ -1,28 +1,29 @@
#ifndef TCPACKETCHECK_H_ #ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_
#define TCPACKETCHECK_H_ #define FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "../tmtcpacket/pus/TcPacketStored.h" #include "../tmtcpacket/pus/TcPacketStored.h"
#include "../tmtcservices/PusVerificationReport.h" #include "../tmtcservices/PusVerificationReport.h"
/** /**
* This class performs a formal packet check for incoming PUS Telecommand Packets. * This class performs a formal packet check for incoming PUS Telecommand Packets.
* Currently, it only checks if the APID and CRC are correct. * Currently, it only checks if the APID and CRC are correct.
* \ingroup tc_distribution * @ingroup tc_distribution
*/ */
class TcPacketCheck : public HasReturnvaluesIF { class TcPacketCheck : public HasReturnvaluesIF {
protected: protected:
/** /**
* Describes the version number a packet must have to pass. * Describes the version number a packet must have to pass.
*/ */
static const uint8_t CCSDS_VERSION_NUMBER = 0; static constexpr uint8_t CCSDS_VERSION_NUMBER = 0;
/** /**
* Describes the secondary header a packet must have to pass. * Describes the secondary header a packet must have to pass.
*/ */
static const uint8_t CCSDS_SECONDARY_HEADER_FLAG = 0; static constexpr uint8_t CCSDS_SECONDARY_HEADER_FLAG = 0;
/** /**
* Describes the TC Packet PUS Version Number a packet must have to pass. * Describes the TC Packet PUS Version Number a packet must have to pass.
*/ */
static const uint8_t PUS_VERSION_NUMBER = 1; static constexpr uint8_t PUS_VERSION_NUMBER = 1;
/** /**
* The packet id each correct packet should have. * The packet id each correct packet should have.
* It is composed of the APID and some static fields. * It is composed of the APID and some static fields.
@ -41,19 +42,19 @@ public:
* The constructor only sets the APID attribute. * The constructor only sets the APID attribute.
* @param set_apid The APID to set. * @param set_apid The APID to set.
*/ */
TcPacketCheck( uint16_t set_apid ); TcPacketCheck( uint16_t setApid );
/** /**
* This is the actual method to formally check a certain Telecommand Packet. * This is the actual method to formally check a certain Telecommand Packet.
* The packet's Application Data can not be checked here. * The packet's Application Data can not be checked here.
* @param current_packet The packt to check * @param current_packet The packt to check
* @return - \c RETURN_OK on success. * @return - @c RETURN_OK on success.
* - \c INCORRECT_CHECKSUM if checksum is invalid. * - @c INCORRECT_CHECKSUM if checksum is invalid.
* - \c ILLEGAL_APID if APID does not match. * - @c ILLEGAL_APID if APID does not match.
*/ */
ReturnValue_t checkPacket( TcPacketStored* current_packet ); ReturnValue_t checkPacket( TcPacketStored* currentPacket );
uint16_t getApid() const; uint16_t getApid() const;
}; };
#endif /* TCPACKETCHECK_H_ */ #endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ */

View File

@ -1,8 +1,9 @@
#include "../timemanager/CCSDSTime.h" #include "CCSDSTime.h"
#include <cstdio> #include <cstdio>
#include <cinttypes> #include <cinttypes>
#include <cmath> #include <cmath>
#include <FSFWConfig.h>
CCSDSTime::CCSDSTime() { CCSDSTime::CCSDSTime() {
} }
@ -158,15 +159,16 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
} }
// Newlib nano can't parse uint8, see SCNu8 documentation and https://sourceware.org/newlib/README // 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. // Suggestion: use uint16 all the time. This should work on all systems.
#ifdef NEWLIB_NANO_NO_C99_IO #if FSFW_NO_C99_IO == 1
uint16_t year; uint16_t year;
uint16_t month; uint16_t month;
uint16_t day; uint16_t day;
uint16_t hour; uint16_t hour;
uint16_t minute; uint16_t minute;
float second; float second;
int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%"
&month, &day, &hour, &minute, &second); "2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &month, &day, &hour,
&minute, &second);
if (count == 6) { if (count == 6) {
to->year = year; to->year = year;
to->month = month; to->month = month;
@ -179,12 +181,13 @@ 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, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &day, count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%"
&hour, &minute, &second); "2" SCNu16 ":%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, ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year,
reinterpret_cast<uint8_t *>(&month), reinterpret_cast<uint8_t *>(&tempDay)); reinterpret_cast<uint8_t *>(&month),
reinterpret_cast<uint8_t *>(&tempDay));
if (result != RETURN_OK) { if (result != RETURN_OK) {
return RETURN_FAILED; return RETURN_FAILED;
} }

View File

@ -2,7 +2,7 @@
#define FRAMEWORK_TIMEMANAGER_CLOCK_H_ #define FRAMEWORK_TIMEMANAGER_CLOCK_H_
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexHelper.h"
#include "../globalfunctions/timevalOperations.h" #include "../globalfunctions/timevalOperations.h"
#include <cstdint> #include <cstdint>

View File

@ -14,8 +14,12 @@ public:
static const uint8_t INTERFACE_ID = CLASS_ID::TIME_STAMPER_IF; static const uint8_t INTERFACE_ID = CLASS_ID::TIME_STAMPER_IF;
static const ReturnValue_t BAD_TIMESTAMP = MAKE_RETURN_CODE(1); static const ReturnValue_t BAD_TIMESTAMP = MAKE_RETURN_CODE(1);
static const uint8_t MISSION_TIMESTAMP_SIZE = 8; //!< This is a mission-specific constant and determines the total size reserved for timestamps. //! This is a mission-specific constant and determines the total
virtual ReturnValue_t addTimeStamp(uint8_t* buffer, const uint8_t maxSize) = 0; //! size reserved for timestamps.
//! TODO: Default define in FSFWConfig ?
static const uint8_t MISSION_TIMESTAMP_SIZE = 8;
virtual ReturnValue_t addTimeStamp(uint8_t* buffer,
const uint8_t maxSize) = 0;
virtual ~TimeStamperIF() {} virtual ~TimeStamperIF() {}
}; };

View File

@ -1,6 +1,6 @@
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "SpacePacketBase.h" #include "SpacePacketBase.h"
#include <string.h> #include "../serviceinterface/ServiceInterfaceStream.h"
#include <cstring>
SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) { SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) {
this->data = (SpacePacketPointer*) set_address; this->data = (SpacePacketPointer*) set_address;
@ -14,7 +14,8 @@ uint8_t SpacePacketBase::getPacketVersionNumber( void ) {
return (this->data->header.packet_id_h & 0b11100000) >> 5; return (this->data->header.packet_id_h & 0b11100000) >> 5;
} }
void SpacePacketBase::initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) { void SpacePacketBase::initSpacePacketHeader(bool isTelecommand,
bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) {
//reset header to zero: //reset header to zero:
memset(data,0, sizeof(this->data->header) ); memset(data,0, sizeof(this->data->header) );
//Set TC/TM bit. //Set TC/TM bit.
@ -81,7 +82,7 @@ void SpacePacketBase::setPacketDataLength( uint16_t new_length) {
this->data->header.packet_length_l = ( new_length & 0x00FF ); this->data->header.packet_length_l = ( new_length & 0x00FF );
} }
uint32_t SpacePacketBase::getFullSize() { size_t SpacePacketBase::getFullSize() {
//+1 is done because size in packet data length field is: size of data field -1 //+1 is done because size in packet data length field is: size of data field -1
return this->getPacketDataLength() + sizeof(this->data->header) + 1; return this->getPacketDataLength() + sizeof(this->data->header) + 1;
} }

View File

@ -1,10 +1,11 @@
#ifndef SPACEPACKETBASE_H_ #ifndef FSFW_TMTCPACKET_SPACEPACKETBASE_H_
#define SPACEPACKETBASE_H_ #define FSFW_TMTCPACKET_SPACEPACKETBASE_H_
#include "ccsds_header.h" #include "ccsds_header.h"
#include <cstddef>
/** /**
* \defgroup tmtcpackets Space Packets * @defgroup tmtcpackets Space Packets
* This is the group, where all classes associated with Telecommand and * This is the group, where all classes associated with Telecommand and
* Telemetry packets belong to. * Telemetry packets belong to.
* The class hierarchy resembles the dependency between the different standards * The class hierarchy resembles the dependency between the different standards
@ -81,7 +82,8 @@ public:
*/ */
bool isTelecommand( void ); bool isTelecommand( void );
void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount = 0); void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader,
uint16_t apid, uint16_t sequenceCount = 0);
/** /**
* The CCSDS header provides a secondary header flag (the fifth-highest bit), * The CCSDS header provides a secondary header flag (the fifth-highest bit),
* which is checked with this method. * which is checked with this method.
@ -167,10 +169,10 @@ public:
* This method returns the full raw packet size. * This method returns the full raw packet size.
* @return The full size of the packet in bytes. * @return The full size of the packet in bytes.
*/ */
uint32_t getFullSize(); size_t getFullSize();
uint32_t getApidAndSequenceCount() const; uint32_t getApidAndSequenceCount() const;
}; };
#endif /* SPACEPACKETBASE_H_ */ #endif /* FSFW_TMTCPACKET_SPACEPACKETBASE_H_ */

View File

@ -7,7 +7,8 @@ class TmPacketMinimal;
class PacketTimestampInterpreterIF { class PacketTimestampInterpreterIF {
public: public:
virtual ~PacketTimestampInterpreterIF() {} virtual ~PacketTimestampInterpreterIF() {}
virtual ReturnValue_t getPacketTime(TmPacketMinimal* packet, timeval* timestamp) const = 0; virtual ReturnValue_t getPacketTime(TmPacketMinimal* packet,
timeval* timestamp) const = 0;
virtual ReturnValue_t getPacketTimeRaw(TmPacketMinimal* packet, const uint8_t** timePtr, uint32_t* size) const = 0; virtual ReturnValue_t getPacketTimeRaw(TmPacketMinimal* packet, const uint8_t** timePtr, uint32_t* size) const = 0;
}; };

View File

@ -1,11 +1,14 @@
#include "../../globalfunctions/CRC.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "TcPacketBase.h" #include "TcPacketBase.h"
#include <string.h>
TcPacketBase::TcPacketBase(const uint8_t* set_data) : #include "../../globalfunctions/CRC.h"
SpacePacketBase(set_data) { #include "../../globalfunctions/arrayprinter.h"
tcData = (TcPacketPointer*) set_data; #include "../../serviceinterface/ServiceInterfaceStream.h"
#include <cstring>
TcPacketBase::TcPacketBase(const uint8_t* setData) :
SpacePacketBase(setData) {
tcData = reinterpret_cast<TcPacketPointer*>(const_cast<uint8_t*>(setData));
} }
TcPacketBase::~TcPacketBase() { TcPacketBase::~TcPacketBase() {
@ -13,28 +16,28 @@ TcPacketBase::~TcPacketBase() {
} }
uint8_t TcPacketBase::getService() { uint8_t TcPacketBase::getService() {
return tcData->data_field.service_type; return tcData->dataField.service_type;
} }
uint8_t TcPacketBase::getSubService() { uint8_t TcPacketBase::getSubService() {
return tcData->data_field.service_subtype; return tcData->dataField.service_subtype;
} }
uint8_t TcPacketBase::getAcknowledgeFlags() { uint8_t TcPacketBase::getAcknowledgeFlags() {
return tcData->data_field.version_type_ack & 0b00001111; return tcData->dataField.version_type_ack & 0b00001111;
} }
const uint8_t* TcPacketBase::getApplicationData() const { const uint8_t* TcPacketBase::getApplicationData() const {
return &tcData->data; return &tcData->appData;
} }
uint16_t TcPacketBase::getApplicationDataSize() { uint16_t TcPacketBase::getApplicationDataSize() {
return getPacketDataLength() - sizeof(tcData->data_field) - CRC_SIZE + 1; return getPacketDataLength() - sizeof(tcData->dataField) - CRC_SIZE + 1;
} }
uint16_t TcPacketBase::getErrorControl() { uint16_t TcPacketBase::getErrorControl() {
uint16_t size = getApplicationDataSize() + CRC_SIZE; uint16_t size = getApplicationDataSize() + CRC_SIZE;
uint8_t* p_to_buffer = &tcData->data; uint8_t* p_to_buffer = &tcData->appData;
return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1];
} }
@ -42,41 +45,42 @@ void TcPacketBase::setErrorControl() {
uint32_t full_size = getFullSize(); uint32_t full_size = getFullSize();
uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE);
uint32_t size = getApplicationDataSize(); uint32_t size = getApplicationDataSize();
(&tcData->data)[size] = (crc & 0XFF00) >> 8; // CRCH (&tcData->appData)[size] = (crc & 0XFF00) >> 8; // CRCH
(&tcData->data)[size + 1] = (crc) & 0X00FF; // CRCL (&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL
} }
void TcPacketBase::setData(const uint8_t* p_Data) { void TcPacketBase::setData(const uint8_t* pData) {
SpacePacketBase::setData(p_Data); SpacePacketBase::setData(pData);
tcData = (TcPacketPointer*) p_Data; tcData = (TcPacketPointer*) pData;
} }
uint8_t TcPacketBase::getSecondaryHeaderFlag() { uint8_t TcPacketBase::getSecondaryHeaderFlag() {
return (tcData->data_field.version_type_ack & 0b10000000) >> 7; return (tcData->dataField.version_type_ack & 0b10000000) >> 7;
} }
uint8_t TcPacketBase::getPusVersionNumber() { uint8_t TcPacketBase::getPusVersionNumber() {
return (tcData->data_field.version_type_ack & 0b01110000) >> 4; return (tcData->dataField.version_type_ack & 0b01110000) >> 4;
} }
void TcPacketBase::print() { void TcPacketBase::print() {
uint8_t * wholeData = getWholeData(); sif::debug << "TcPacketBase::print: " << std::endl;
sif::debug << "TcPacket contains: " << std::endl; arrayprinter::print(getWholeData(), getFullSize());
for (uint8_t count = 0; count < getFullSize(); ++count) {
sif::debug << std::hex << (uint16_t) wholeData[count] << " ";
}
sif::debug << std::dec << std::endl;
} }
void TcPacketBase::initializeTcPacket(uint16_t apid, uint16_t sequenceCount, void TcPacketBase::initializeTcPacket(uint16_t apid, uint16_t sequenceCount,
uint8_t ack, uint8_t service, uint8_t subservice) { uint8_t ack, uint8_t service, uint8_t subservice) {
initSpacePacketHeader(true, true, apid, sequenceCount); initSpacePacketHeader(true, true, apid, sequenceCount);
memset(&tcData->data_field, 0, sizeof(tcData->data_field)); std::memset(&tcData->dataField, 0, sizeof(tcData->dataField));
setPacketDataLength(sizeof(tcData->data_field) + CRC_SIZE); setPacketDataLength(sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1);
//Data Field Header: //Data Field Header:
//Set CCSDS_secondary_header_flag to 0, version number to 001 and ack to 0000 //Set CCSDS_secondary_header_flag to 0 and version number to 001
tcData->data_field.version_type_ack = 0b00010000; tcData->dataField.version_type_ack = 0b00010000;
tcData->data_field.version_type_ack |= (ack & 0x0F); tcData->dataField.version_type_ack |= (ack & 0x0F);
tcData->data_field.service_type = service; tcData->dataField.service_type = service;
tcData->data_field.service_subtype = subservice; tcData->dataField.service_subtype = subservice;
}
size_t TcPacketBase::calculateFullPacketLength(size_t appDataLen) {
return sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) +
appDataLen + TcPacketBase::CRC_SIZE;
} }

Some files were not shown because too many files have changed in this diff Show More