Compare commits

..

2 Commits

Author SHA1 Message Date
2a7e82bd28 Merge branch 'master' into source/vorago 2020-08-21 15:27:28 +02:00
b400deed1a removed config includes 2020-07-17 14:37:54 +02:00
350 changed files with 6338 additions and 17772 deletions

0
.gitmodules vendored
View File

View File

@@ -1,12 +0,0 @@
#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,8 +4,6 @@ The initial version of the Flight Software Framework was developed during
the Flying Laptop Project by the Universität Stuttgart in coorporation
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.
No copyright assignment is required to contribute to the Flight Software Framework.

159
README.md
View File

@@ -1,159 +0,0 @@
![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,12 +1,9 @@
#include "ActionHelper.h"
#include "HasActionsIF.h"
#include "../ipc/MessageQueueSenderIF.h"
#include "../objectmanager/ObjectManagerIF.h"
ActionHelper::ActionHelper(HasActionsIF* setOwner,
MessageQueueIF* useThisQueue) :
owner(setOwner), queueToUse(useThisQueue) {
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) :
owner(setOwner), queueToUse(useThisQueue), ipcStore(nullptr) {
}
ActionHelper::~ActionHelper() {
@@ -35,15 +32,13 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
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;
ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result);
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;
ActionMessage::setCompletionReply(&reply, commandId, result);
queueToUse->sendMessage(reportTo, &reply);
@@ -53,8 +48,8 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) {
queueToUse = queue;
}
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy,
ActionId_t actionId, store_address_t dataAddress) {
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress) {
const uint8_t* dataPtr = NULL;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
@@ -66,11 +61,6 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy,
}
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
ipcStore->deleteData(dataAddress);
if(result == HasActionsIF::EXECUTION_FINISHED) {
CommandMessage reply;
ActionMessage::setCompletionReply(&reply, actionId, result);
queueToUse->sendMessage(commandedBy, &reply);
}
if (result != HasReturnvaluesIF::RETURN_OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result);
@@ -95,28 +85,22 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
if (result != HasReturnvaluesIF::RETURN_OK) {
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) {
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.
//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) {
//TODO Service Implementation sucks at the moment
if (hideSender){
result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
}
else {
} else {
result = queueToUse->sendMessage(reportTo, &reply);
}
if (result != HasReturnvaluesIF::RETURN_OK){
if ( result != HasReturnvaluesIF::RETURN_OK){
ipcStore->deleteData(storeAddress);
}
return result;
@@ -124,39 +108,3 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
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,18 +1,15 @@
#ifndef FSFW_ACTION_ACTIONHELPER_H_
#define FSFW_ACTION_ACTIONHELPER_H_
#ifndef ACTIONHELPER_H_
#define ACTIONHELPER_H_
#include "ActionMessage.h"
#include "../serialize/SerializeIF.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.
* 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!
* Components which use the HasActionIF this helper can be used to handle the action messages.
* 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 it needs a valid messageQueueIF pointer!
*/
class HasActionsIF;
@@ -21,8 +18,7 @@ public:
/**
* Constructor of the action helper
* @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);
@@ -30,36 +26,28 @@ public:
/**
* 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 invalid or the callback fails a message reply will be
* send to the sender of the message automatically.
* If the message is a valid action message the helper will use the 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
* @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);
/**
* Helper initialize function. Must be called before use of any other
* helper function
* @param queueToUse_ Pointer to the messageQueue to be used, optional
* if queue was set in constructor
* Helper initialize function. Must be called before use of any other helper function
* @param queueToUse_ Pointer to the messageQueue to be used, optional if queue was set in constructor
* @return Returns RETURN_OK if successful
*/
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 reportTo The messageQueueId to report the step message to
* @param commandId ID of the executed command
* @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
*
@@ -67,59 +55,39 @@ public:
* @param commandId ID of the executed command
* @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.
* Takes a SerializeIF* pointer and serializes it into the IPC store.
* @param reportTo MessageQueueId_t to report the action completion
* message to
* Function to be called by the owner if an action does report data
*
* @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,
SerializeIF* data, bool hideSender = false);
/**
* Function to be called by the owner if an action does report data.
* 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);
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 message queue is unavailable at construction
* and initialize but must be setup before first call of other functions.
* 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
*/
void setQueueToUse(MessageQueueIF *queue);
protected:
//!< Increase of value of this per step
static const uint8_t STEP_OFFSET = 1;
static const uint8_t STEP_OFFSET = 1;//!< Increase of value of this per step
HasActionsIF* owner;//!< Pointer to the owner
//! Queue to be used as response sender, has to be set in ctor or with
//! setQueueToUse
MessageQueueIF* queueToUse;
//! Pointer to an IPC Store, initialized during construction or
StorageManagerIF* ipcStore = nullptr;
MessageQueueIF* queueToUse;//!< Queue to be used as response sender, has to be set with
StorageManagerIF* ipcStore;//!< Pointer to an IPC Store, initialized during construction or initialize(MessageQueueIF* queueToUse_) or with setQueueToUse(MessageQueueIF *queue)
/**
* Internal function called by handleActionMessage
*Internal function called by handleActionMessage(CommandMessage* command)
*
* @param commandedBy MessageQueueID of Commander
* @param actionId ID of action to be done
* @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();
};
#endif /* FSFW_ACTION_ACTIONHELPER_H_ */
#endif /* ACTIONHELPER_H_ */

View File

@@ -1,5 +1,5 @@
#ifndef FSFW_ACTION_ACTIONMESSAGE_H_
#define FSFW_ACTION_ACTIONMESSAGE_H_
#ifndef ACTIONMESSAGE_H_
#define ACTIONMESSAGE_H_
#include "../ipc/CommandMessage.h"
#include "../objectmanager/ObjectManagerIF.h"
@@ -10,7 +10,7 @@ class ActionMessage {
private:
ActionMessage();
public:
static const uint8_t MESSAGE_ID = messagetypes::ACTION;
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::ACTION;
static const Command_t EXECUTE_ACTION = MAKE_COMMAND_ID(1);
static const Command_t STEP_SUCCESS = MAKE_COMMAND_ID(2);
static const Command_t STEP_FAILED = MAKE_COMMAND_ID(3);
@@ -18,19 +18,15 @@ public:
static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5);
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
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 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 ReturnValue_t getReturnCode(const CommandMessage* message );
static void setDataReply(CommandMessage* message, ActionId_t actionId,
store_address_t data);
static void setCompletionReply(CommandMessage* message, ActionId_t fid,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void setDataReply(CommandMessage* message, ActionId_t actionId, store_address_t data);
static void setCompletionReply(CommandMessage* message, ActionId_t fid, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void clear(CommandMessage* message);
};
#endif /* FSFW_ACTION_ACTIONMESSAGE_H_ */
#endif /* ACTIONMESSAGE_H_ */

View File

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

View File

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

View File

@@ -1,17 +1,16 @@
#include "HasActionsIF.h"
#include "SimpleActionHelper.h"
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner,
MessageQueueIF* useThisQueue) :
ActionHelper(setOwner, useThisQueue), isExecuting(false) {
ActionHelper(setOwner, useThisQueue), isExecuting(false), lastCommander(
0), lastAction(0), stepCount(0) {
}
SimpleActionHelper::~SimpleActionHelper() {
}
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,
result);
if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@@ -1,13 +1,8 @@
#ifndef FSFW_ACTION_SIMPLEACTIONHELPER_H_
#define FSFW_ACTION_SIMPLEACTIONHELPER_H_
#ifndef SIMPLEACTIONHELPER_H_
#define SIMPLEACTIONHELPER_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 {
public:
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
@@ -17,14 +12,13 @@ public:
ReturnValue_t reportData(SerializeIF* data);
protected:
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress);
virtual void resetHelper();
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress);
virtual void resetHelper();
private:
bool isExecuting;
MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE;
ActionId_t lastAction = 0;
uint8_t stepCount = 0;
MessageQueueId_t lastCommander;
ActionId_t lastAction;
uint8_t stepCount;
};
#endif /* SIMPLEACTIONHELPER_H_ */

View File

@@ -1,15 +1,15 @@
#ifndef FSFW_CONTAINER_ARRAYLIST_H_
#define FSFW_CONTAINER_ARRAYLIST_H_
#ifndef ARRAYLIST_H_
#define ARRAYLIST_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../serialize/SerializeAdapter.h"
#include "../serialize/SerializeIF.h"
/**
* @brief A List that stores its values in an array.
* @details
* The underlying storage is an array that can be allocated by the class
* itself or supplied via ctor.
* A List that stores its values in an array.
*
* The backend is an array that can be allocated by the class itself or supplied via ctor.
*
*
* @ingroup container
*/
@@ -20,53 +20,6 @@ public:
static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
/**
* This is the allocating constructor.
* It allocates an array of the specified size.
* @param maxSize
*/
ArrayList(count_t maxSize) :
size(0), maxSize_(maxSize), allocated(true) {
entries = new T[maxSize];
}
/**
* This is the non-allocating constructor
*
* It expects a pointer to an array of a certain size and initializes
* itself to it.
*
* @param storage the array to use as backend
* @param maxSize size of storage
* @param size size of data already present in storage
*/
ArrayList(T *storage, count_t maxSize, count_t size = 0) :
size(size), entries(storage), maxSize_(maxSize), allocated(false) {
}
/**
* Copying is forbiden by declaring copy ctor and copy assignment deleted
* It is too ambigous in this case.
* (Allocate a new backend? Use the same? What to do in an modifying call?)
*/
ArrayList(const ArrayList& other) = delete;
const ArrayList& operator=(const ArrayList& other) = delete;
/**
* Number of Elements stored in this List
*/
count_t size;
/**
* Destructor, if the allocating constructor was used, it deletes the array.
*/
virtual ~ArrayList() {
if (allocated) {
delete[] entries;
}
}
/**
* An Iterator to go trough an ArrayList
*
@@ -78,7 +31,10 @@ public:
/**
* Empty ctor, points to NULL
*/
Iterator(): value(0) {}
Iterator() :
value(0) {
}
/**
* Initializes the Iterator to point to an element
@@ -116,11 +72,7 @@ public:
return tmp;
}
T& operator*() {
return *value;
}
const T& operator*() const {
T operator*() {
return *value;
}
@@ -128,19 +80,59 @@ public:
return value;
}
const T *operator->() const {
const T *operator->() const{
return value;
}
};
friend bool operator==(const ArrayList::Iterator& lhs,
const ArrayList::Iterator& rhs) {
return (lhs.value == rhs.value);
//SHOULDDO this should be implemented as non-member
bool operator==(const typename ArrayList<T, count_t>::Iterator& other) const{
return (value == other.value);
}
//SHOULDDO this should be implemented as non-member
bool operator!=(const typename ArrayList<T, count_t>::Iterator& other) const {
return !(*this == other);
}
}
;
/**
* Number of Elements stored in this List
*/
count_t size;
/**
* This is the allocating constructor;
*
* It allocates an array of the specified size.
*
* @param maxSize
*/
ArrayList(count_t maxSize) :
size(0), maxSize_(maxSize), allocated(true) {
entries = new T[maxSize];
}
friend bool operator!=(const ArrayList::Iterator& lhs,
const ArrayList::Iterator& rhs) {
return not (lhs.value == rhs.value);
/**
* This is the non-allocating constructor
*
* It expects a pointer to an array of a certain size and initializes itself to it.
*
* @param storage the array to use as backend
* @param maxSize size of storage
* @param size size of data already present in storage
*/
ArrayList(T *storage, count_t maxSize, count_t size = 0) :
size(size), entries(storage), maxSize_(maxSize), allocated(false) {
}
/**
* Destructor, if the allocating constructor was used, it deletes the array.
*/
virtual ~ArrayList() {
if (allocated) {
delete[] entries;
}
}
/**
@@ -196,7 +188,7 @@ public:
*
* @return maximum number of elements
*/
size_t maxSize() const {
uint32_t maxSize() const {
return this->maxSize_;
}
@@ -231,7 +223,19 @@ public:
count_t remaining() {
return (maxSize_ - size);
}
private:
/**
* This is the copy constructor
*
* It is private, as copying is too ambigous in this case. (Allocate a new backend? Use the same?
* What to do in an modifying call?)
*
* @param other
*/
ArrayList(const ArrayList& other) :
size(other.size), entries(other.entries), maxSize_(other.maxSize_), allocated(
false) {
}
protected:
/**
* pointer to the array in which the entries are stored
@@ -240,14 +244,12 @@ protected:
/**
* remembering the maximum size
*/
size_t maxSize_;
uint32_t maxSize_;
/**
* true if the array was allocated and needs to be deleted in the destructor.
*/
bool allocated;
};
#endif /* FSFW_CONTAINER_ARRAYLIST_H_ */
#endif /* ARRAYLIST_H_ */

View File

@@ -1,55 +0,0 @@
#ifndef FSFW_CONTAINER_DYNAMICFIFO_H_
#define FSFW_CONTAINER_DYNAMICFIFO_H_
#include "FIFOBase.h"
#include <vector>
/**
* @brief Simple First-In-First-Out data structure. The maximum size
* can be set in the constructor.
* @details
* The maximum capacity can be determined at run-time, so this container
* performs dynamic memory allocation!
* The public interface of FIFOBase exposes the user interface for the FIFO.
* @tparam T Entry Type
* @tparam capacity Maximum capacity
*/
template<typename T>
class DynamicFIFO: public FIFOBase<T> {
public:
DynamicFIFO(size_t maxCapacity): FIFOBase<T>(nullptr, maxCapacity),
fifoVector(maxCapacity) {
// trying to pass the pointer of the uninitialized vector
// to the FIFOBase constructor directly lead to a super evil bug.
// So we do it like this now.
this->setContainer(fifoVector.data());
};
/**
* @brief Custom copy constructor which prevents setting the
* underlying pointer wrong. This function allocates memory!
* @details This is a very heavy operation so try to avoid this!
*
*/
DynamicFIFO(const DynamicFIFO& other): FIFOBase<T>(other),
fifoVector(other.maxCapacity) {
this->fifoVector = other.fifoVector;
this->setContainer(fifoVector.data());
}
/**
* @brief Custom assignment operator
* @details This is a very heavy operation so try to avoid this!
* @param other DyamicFIFO to copy from
*/
DynamicFIFO& operator=(const DynamicFIFO& other){
FIFOBase<T>::operator=(other);
this->fifoVector = other.fifoVector;
this->setContainer(fifoVector.data());
return *this;
}
private:
std::vector<T> fifoVector;
};
#endif /* FSFW_CONTAINER_DYNAMICFIFO_H_ */

View File

@@ -1,47 +1,82 @@
#ifndef FSFW_CONTAINER_FIFO_H_
#define FSFW_CONTAINER_FIFO_H_
#ifndef FIFO_H_
#define FIFO_H_
#include "FIFOBase.h"
#include <array>
#include "../returnvalues/HasReturnvaluesIF.h"
/**
* @brief Simple First-In-First-Out data structure with size fixed at
* compile time
* @details
* Performs no dynamic memory allocation.
* The public interface of FIFOBase exposes the user interface for the FIFO.
* @brief Simple First-In-First-Out data structure
* @tparam T Entry Type
* @tparam capacity Maximum capacity
*/
template<typename T, size_t capacity>
class FIFO: public FIFOBase<T> {
public:
FIFO(): FIFOBase<T>(nullptr, capacity) {
this->setContainer(fifoArray.data());
};
/**
* @brief Custom copy constructor to set pointer correctly.
* @param other
*/
FIFO(const FIFO& other): FIFOBase<T>(other) {
this->fifoArray = other.fifoArray;
this->setContainer(fifoArray.data());
}
/**
* @brief Custom assignment operator
* @param other
*/
FIFO& operator=(const FIFO& other){
FIFOBase<T>::operator=(other);
this->fifoArray = other.fifoArray;
this->setContainer(fifoArray.data());
return *this;
}
template<typename T, uint8_t capacity>
class FIFO {
private:
std::array<T, capacity> fifoArray;
uint8_t readIndex, writeIndex, currentSize;
T data[capacity];
uint8_t next(uint8_t current) {
++current;
if (current == capacity) {
current = 0;
}
return current;
}
public:
FIFO() :
readIndex(0), writeIndex(0), currentSize(0) {
}
bool empty() {
return (currentSize == 0);
}
bool full() {
return (currentSize == capacity);
}
uint8_t size(){
return currentSize;
}
ReturnValue_t insert(T value) {
if (full()) {
return FULL;
} else {
data[writeIndex] = value;
writeIndex = next(writeIndex);
++currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
}
ReturnValue_t retrieve(T *value) {
if (empty()) {
return EMPTY;
} else {
*value = data[readIndex];
readIndex = next(readIndex);
--currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
}
ReturnValue_t peek(T * value) {
if(empty()) {
return EMPTY;
} else {
*value = data[readIndex];
return HasReturnvaluesIF::RETURN_OK;
}
}
ReturnValue_t pop() {
T value;
return this->retrieve(&value);
}
static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(1);
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2);
};
#endif /* FSFW_CONTAINER_FIFO_H_ */
#endif /* FIFO_H_ */

View File

@@ -1,79 +0,0 @@
#ifndef FSFW_CONTAINER_FIFOBASE_H_
#define FSFW_CONTAINER_FIFOBASE_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
#include <cstring>
template <typename T>
class FIFOBase {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(1);
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2);
/** Default ctor, takes pointer to first entry of underlying container
* and maximum capacity */
FIFOBase(T* values, const size_t maxCapacity);
/**
* Insert value into FIFO
* @param value
* @return RETURN_OK on success, FULL if full
*/
ReturnValue_t insert(T value);
/**
* Retrieve item from FIFO. This removes the item from the FIFO.
* @param value Must point to a valid T
* @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed
*/
ReturnValue_t retrieve(T *value);
/**
* Retrieve item from FIFO without removing it from FIFO.
* @param value Must point to a valid T
* @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed
*/
ReturnValue_t peek(T * value);
/**
* Remove item from FIFO.
* @return RETURN_OK on success, EMPTY if empty
*/
ReturnValue_t pop();
/***
* Check if FIFO is empty
* @return True if empty, False if not
*/
bool empty();
/***
* Check if FIFO is Full
* @return True if full, False if not
*/
bool full();
/***
* Current used size (elements) used
* @return size_t in elements
*/
size_t size();
/***
* Get maximal capacity of fifo
* @return size_t with max capacity of this fifo
*/
size_t getMaxCapacity() const;
protected:
void setContainer(T* data);
size_t maxCapacity = 0;
T* values;
size_t readIndex = 0;
size_t writeIndex = 0;
size_t currentSize = 0;
size_t next(size_t current);
};
#include "FIFOBase.tpp"
#endif /* FSFW_CONTAINER_FIFOBASE_H_ */

View File

@@ -1,93 +0,0 @@
#ifndef FSFW_CONTAINER_FIFOBASE_TPP_
#define FSFW_CONTAINER_FIFOBASE_TPP_
#ifndef FSFW_CONTAINER_FIFOBASE_H_
#error Include FIFOBase.h before FIFOBase.tpp!
#endif
template<typename T>
inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity):
maxCapacity(maxCapacity), values(values){};
template<typename T>
inline ReturnValue_t FIFOBase<T>::insert(T value) {
if (full()) {
return FULL;
} else {
values[writeIndex] = value;
writeIndex = next(writeIndex);
++currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
};
template<typename T>
inline ReturnValue_t FIFOBase<T>::retrieve(T* value) {
if (empty()) {
return EMPTY;
} else {
if (value == nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
*value = values[readIndex];
readIndex = next(readIndex);
--currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
};
template<typename T>
inline ReturnValue_t FIFOBase<T>::peek(T* value) {
if(empty()) {
return EMPTY;
} else {
if (value == nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
*value = values[readIndex];
return HasReturnvaluesIF::RETURN_OK;
}
};
template<typename T>
inline ReturnValue_t FIFOBase<T>::pop() {
T value;
return this->retrieve(&value);
};
template<typename T>
inline bool FIFOBase<T>::empty() {
return (currentSize == 0);
};
template<typename T>
inline bool FIFOBase<T>::full() {
return (currentSize == maxCapacity);
}
template<typename T>
inline size_t FIFOBase<T>::size() {
return currentSize;
}
template<typename T>
inline size_t FIFOBase<T>::next(size_t current) {
++current;
if (current == maxCapacity) {
current = 0;
}
return current;
}
template<typename T>
inline size_t FIFOBase<T>::getMaxCapacity() const {
return maxCapacity;
}
template<typename T>
inline void FIFOBase<T>::setContainer(T *data) {
this->values = data;
}
#endif

View File

@@ -2,13 +2,11 @@
#define FIXEDARRAYLIST_H_
#include "ArrayList.h"
#include <cmath>
/**
* \ingroup container
*/
template<typename T, size_t MAX_SIZE, typename count_t = uint8_t>
template<typename T, uint32_t MAX_SIZE, typename count_t = uint8_t>
class FixedArrayList: public ArrayList<T, count_t> {
static_assert(MAX_SIZE <= (pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE");
private:
T data[MAX_SIZE];
public:
@@ -20,13 +18,11 @@ public:
ArrayList<T, count_t>(data, MAX_SIZE) {
memcpy(this->data, other.data, sizeof(this->data));
this->entries = data;
this->size = other.size;
}
FixedArrayList& operator=(FixedArrayList other) {
memcpy(this->data, other.data, sizeof(this->data));
this->entries = data;
this->size = other.size;
return *this;
}

View File

@@ -1,27 +1,15 @@
#ifndef FSFW_CONTAINER_FIXEDMAP_H_
#define FSFW_CONTAINER_FIXEDMAP_H_
#ifndef FIXEDMAP_H_
#define FIXEDMAP_H_
#include "ArrayList.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include <utility>
#include <type_traits>
/**
* @brief Map implementation for maps with a pre-defined size.
* @details
* Can be initialized with desired maximum size.
* Iterator is used to access <key,value> pair and iterate through map entries.
* Complexity O(n).
* @warning Iterators return a non-const key_t in the pair.
* @warning A User is not allowed to change the key, otherwise the map is corrupted.
* @ingroup container
* \ingroup container
*/
template<typename key_t, typename T>
class FixedMap: public SerializeIF {
static_assert (std::is_trivially_copyable<T>::value or
std::is_base_of<SerializeIF, T>::value,
"Types used in FixedMap must either be trivial copy-able or a "
"derived class from SerializeIF to be serialize-able");
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
@@ -59,18 +47,17 @@ public:
Iterator(std::pair<key_t, T> *pair) :
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) {
}
T operator*() {
return ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
}
T *operator->() {
return &ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
}
};
friend bool operator==(const typename FixedMap::Iterator& lhs,
const typename FixedMap::Iterator& rhs) {
return (lhs.value == rhs.value);
}
friend bool operator!=(const typename FixedMap::Iterator& lhs,
const typename FixedMap::Iterator& rhs) {
return not (lhs.value == rhs.value);
}
Iterator begin() const {
return Iterator(&theMap[0]);
}
@@ -83,7 +70,7 @@ public:
return _size;
}
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr) {
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) {
if (exists(key) == HasReturnvaluesIF::RETURN_OK) {
return KEY_ALREADY_EXISTS;
}
@@ -92,7 +79,7 @@ public:
}
theMap[_size].first = key;
theMap[_size].second = value;
if (storedValue != nullptr) {
if (storedValue != NULL) {
*storedValue = Iterator(&theMap[_size]);
}
++_size;
@@ -100,7 +87,7 @@ public:
}
ReturnValue_t insert(std::pair<key_t, T> pair) {
return insert(pair.first, pair.second);
return insert(pair.fist, pair.second);
}
ReturnValue_t exists(key_t key) const {
@@ -153,24 +140,6 @@ public:
return HasReturnvaluesIF::RETURN_OK;
}
bool empty() {
if(_size == 0) {
return true;
}
else {
return false;
}
}
bool full() {
if(_size >= theMap.maxSize()) {
return true;
}
else {
return false;
}
}
void clear() {
_size = 0;
}
@@ -227,4 +196,4 @@ public:
};
#endif /* FSFW_CONTAINER_FIXEDMAP_H_ */
#endif /* FIXEDMAP_H_ */

View File

@@ -1,206 +1,181 @@
#ifndef FSFW_CONTAINER_FIXEDORDEREDMULTIMAP_H_
#define FSFW_CONTAINER_FIXEDORDEREDMULTIMAP_H_
#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_
#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_
#include "ArrayList.h"
#include <cstring>
#include <set>
/**
* @brief An associative container which allows multiple entries of the same key.
* @details
* Same keys are ordered by KEY_COMPARE function which is std::less<key_t> > by default.
*
* It uses the ArrayList, so technically this is not a real map, it is an array of pairs
* of type key_t, T. It is ordered by key_t as FixedMap but allows same keys. Thus it has a linear
* complexity O(n). As long as the number of entries remains low, this
* should not be an issue.
* The number of insertion and deletion operation should be minimized
* as those incur extensive memory move operations (the underlying container
* is not node based).
*
* Its of fixed size so no allocations are performed after the construction.
*
* The maximum size is given as first parameter of the constructor.
*
* It provides an iterator to do list iterations.
*
* The type T must have a copy constructor if it is not trivial copy-able.
*
* @warning Iterators return a non-const key_t in the pair.
* @warning A User is not allowed to change the key, otherwise the map is corrupted.
*
* \ingroup container
*/
template<typename key_t, typename T, typename KEY_COMPARE = std::less<key_t>>
class FixedOrderedMultimap {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MULTIMAP;
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x02);
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
/***
* Constructor which needs a size_t for the maximum allowed size
*
* Can not be resized during runtime
*
* Allocates memory at construction
* @param maxSize size_t of Maximum allowed size
*/
FixedOrderedMultimap(size_t maxSize):theMap(maxSize), _size(0){
}
private:
typedef KEY_COMPARE compare;
compare myComp;
ArrayList<std::pair<key_t, T>, uint32_t> theMap;
uint32_t _size;
/***
* Virtual destructor frees Memory by deleting its member
*/
uint32_t findFirstIndex(key_t key, uint32_t startAt = 0) const {
if (startAt >= _size) {
return startAt + 1;
}
uint32_t i = startAt;
for (i = startAt; i < _size; ++i) {
if (theMap[i].first == key) {
return i;
}
}
return i;
}
uint32_t findNicePlace(key_t key) const {
uint32_t i = 0;
for (i = 0; i < _size; ++i) {
if (myComp(key, theMap[i].first)) {
return i;
}
}
return i;
}
void removeFromPosition(uint32_t position) {
if (_size <= position) {
return;
}
memmove(&theMap[position], &theMap[position + 1],
(_size - position - 1) * sizeof(std::pair<key_t,T>));
--_size;
}
public:
FixedOrderedMultimap(uint32_t maxSize) :
theMap(maxSize), _size(0) {
}
virtual ~FixedOrderedMultimap() {
}
/***
* Special iterator for FixedOrderedMultimap
*/
class Iterator: public ArrayList<std::pair<key_t, T>, size_t>::Iterator {
class Iterator: public ArrayList<std::pair<key_t, T>, uint32_t>::Iterator {
public:
Iterator() :
ArrayList<std::pair<key_t, T>, size_t>::Iterator() {
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator() {
}
Iterator(std::pair<key_t, T> *pair) :
ArrayList<std::pair<key_t, T>, size_t>::Iterator(pair) {
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) {
}
T operator*() {
return ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
}
T *operator->() {
return &ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
}
};
/***
* Returns an iterator pointing to the first element
* @return Iterator pointing to first element
*/
Iterator begin() const {
return Iterator(&theMap[0]);
}
/**
* Returns an iterator pointing to one element past the end
* @return Iterator pointing to one element past the end
*/
Iterator end() const {
return Iterator(&theMap[_size]);
}
/***
* Returns the current size of the map (not maximum size!)
* @return Current size
*/
size_t size() const{
uint32_t size() const {
return _size;
}
/**
* Clears the map, does not deallocate any memory
*/
void clear(){
_size = 0;
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) {
if (_size == theMap.maxSize()) {
return MAP_FULL;
}
uint32_t position = findNicePlace(key);
memmove(&theMap[position + 1], &theMap[position],
(_size - position) * sizeof(std::pair<key_t,T>));
theMap[position].first = key;
theMap[position].second = value;
++_size;
if (storedValue != NULL) {
*storedValue = Iterator(&theMap[position]);
}
return HasReturnvaluesIF::RETURN_OK;
}
/**
* Returns the maximum size of the map
* @return Maximum size of the map
*/
size_t maxSize() const{
return theMap.maxSize();
ReturnValue_t insert(std::pair<key_t, T> pair) {
return insert(pair.fist, pair.second);
}
/***
* Used to insert a key and value separately.
*
* @param[in] key Key of the new element
* @param[in] value Value of the new element
* @param[in/out] (optional) storedValue On success this points to the new value, otherwise a nullptr
* @return RETURN_OK if insert was successful, MAP_FULL if no space is available
*/
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr);
ReturnValue_t exists(key_t key) const {
ReturnValue_t result = KEY_DOES_NOT_EXIST;
if (findFirstIndex(key) < _size) {
result = HasReturnvaluesIF::RETURN_OK;
}
return result;
}
/***
* Used to insert new pair instead of single values
*
* @param pair Pair to be inserted
* @return RETURN_OK if insert was successful, MAP_FULL if no space is available
*/
ReturnValue_t insert(std::pair<key_t, T> pair);
ReturnValue_t erase(Iterator *iter) {
uint32_t i;
if ((i = findFirstIndex((*iter).value->first)) >= _size) {
return KEY_DOES_NOT_EXIST;
}
removeFromPosition(i);
if (*iter != begin()) {
(*iter)--;
} else {
*iter = begin();
}
return HasReturnvaluesIF::RETURN_OK;
}
/***
* Can be used to check if a certain key is in the map
* @param key Key to be checked
* @return RETURN_OK if the key exists KEY_DOES_NOT_EXIST otherwise
*/
ReturnValue_t exists(key_t key) const;
ReturnValue_t erase(key_t key) {
uint32_t i;
if ((i = findFirstIndex(key)) >= _size) {
return KEY_DOES_NOT_EXIST;
}
do {
removeFromPosition(i);
i = findFirstIndex(key, i);
} while (i < _size);
return HasReturnvaluesIF::RETURN_OK;
}
/***
* Used to delete the element in the iterator
*
* The iterator will point to the element before or begin(),
* but never to one element in front of the map.
*
* @warning The iterator needs to be valid and dereferenceable
* @param[in/out] iter Pointer to iterator to the element that needs to be ereased
* @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this
*/
ReturnValue_t erase(Iterator *iter);
//This is potentially unsafe
// T *findValue(key_t key) const {
// return &theMap[findFirstIndex(key)].second;
// }
/***
* Used to erase by key
* @param key Key to be erased
* @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this
*/
ReturnValue_t erase(key_t key);
/***
* Find returns the first appearance of the key
*
* If the key does not exist, it points to end()
*
* @param key Key to search for
* @return Iterator pointing to the first entry of key
*/
Iterator find(key_t key) const{
Iterator find(key_t key) const {
ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) {
return end();
}
return Iterator(&theMap[findFirstIndex(key)]);
};
/***
* Finds first entry of the given key and returns a
* pointer to the value
*
* @param key Key to search for
* @param value Found value
* @return RETURN_OK if it points to the value,
* KEY_DOES_NOT_EXIST if the key is not in the map
*/
ReturnValue_t find(key_t key, T **value) const;
friend bool operator==(const typename FixedOrderedMultimap::Iterator& lhs,
const typename FixedOrderedMultimap::Iterator& rhs) {
return (lhs.value == rhs.value);
}
friend bool operator!=(const typename FixedOrderedMultimap::Iterator& lhs,
const typename FixedOrderedMultimap::Iterator& rhs) {
return not (lhs.value == rhs.value);
ReturnValue_t find(key_t key, T **value) const {
ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*value = &theMap[findFirstIndex(key)].second;
return HasReturnvaluesIF::RETURN_OK;
}
private:
typedef KEY_COMPARE compare;
compare myComp;
ArrayList<std::pair<key_t, T>, size_t> theMap;
size_t _size;
void clear() {
_size = 0;
}
size_t findFirstIndex(key_t key, size_t startAt = 0) const;
uint32_t maxSize() const {
return theMap.maxSize();
}
size_t findNicePlace(key_t key) const;
void removeFromPosition(size_t position);
};
#include "FixedOrderedMultimap.tpp"
#endif /* FSFW_CONTAINER_FIXEDORDEREDMULTIMAP_H_ */
#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_ */

View File

@@ -1,109 +0,0 @@
#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t key, T value, Iterator *storedValue) {
if (_size == theMap.maxSize()) {
return MAP_FULL;
}
size_t position = findNicePlace(key);
memmove(static_cast<void*>(&theMap[position + 1]),static_cast<void*>(&theMap[position]),
(_size - position) * sizeof(std::pair<key_t,T>));
theMap[position].first = key;
theMap[position].second = value;
++_size;
if (storedValue != nullptr) {
*storedValue = Iterator(&theMap[position]);
}
return HasReturnvaluesIF::RETURN_OK;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(std::pair<key_t, T> pair) {
return insert(pair.first, pair.second);
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::exists(key_t key) const {
ReturnValue_t result = KEY_DOES_NOT_EXIST;
if (findFirstIndex(key) < _size) {
result = HasReturnvaluesIF::RETURN_OK;
}
return result;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(Iterator *iter) {
size_t i;
if ((i = findFirstIndex((*iter).value->first)) >= _size) {
return KEY_DOES_NOT_EXIST;
}
removeFromPosition(i);
if (*iter != begin()) {
(*iter)--;
} else {
*iter = begin();
}
return HasReturnvaluesIF::RETURN_OK;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(key_t key) {
size_t i;
if ((i = findFirstIndex(key)) >= _size) {
return KEY_DOES_NOT_EXIST;
}
do {
removeFromPosition(i);
i = findFirstIndex(key, i);
} while (i < _size);
return HasReturnvaluesIF::RETURN_OK;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::find(key_t key, T **value) const {
ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*value = &theMap[findFirstIndex(key)].second;
return HasReturnvaluesIF::RETURN_OK;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t key, size_t startAt) const {
if (startAt >= _size) {
return startAt + 1;
}
size_t i = startAt;
for (i = startAt; i < _size; ++i) {
if (theMap[i].first == key) {
return i;
}
}
return i;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findNicePlace(key_t key) const {
size_t i = 0;
for (i = 0; i < _size; ++i) {
if (myComp(key, theMap[i].first)) {
return i;
}
}
return i;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline void FixedOrderedMultimap<key_t, T, KEY_COMPARE>::removeFromPosition(size_t position) {
if (_size <= position) {
return;
}
memmove(static_cast<void*>(&theMap[position]), static_cast<void*>(&theMap[position + 1]),
(_size - position - 1) * sizeof(std::pair<key_t,T>));
--_size;
}
#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ */

41
container/IsDerivedFrom.h Normal file
View File

@@ -0,0 +1,41 @@
#ifndef ISDERIVEDFROM_H_
#define ISDERIVEDFROM_H_
template<typename D, typename B>
class IsDerivedFrom {
class No {
};
class Yes {
No no[3];
};
static Yes Test(B*); // declared, but not defined
static No Test(... ); // declared, but not defined
public:
enum {
Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes)
};
};
template<typename, typename>
struct is_same {
static bool const value = false;
};
template<typename A>
struct is_same<A, A> {
static bool const value = true;
};
template<bool C, typename T = void>
struct enable_if {
typedef T type;
};
template<typename T>
struct enable_if<false, T> { };
#endif /* ISDERIVEDFROM_H_ */

View File

@@ -3,62 +3,26 @@
#include "../storagemanager/StorageManagerIF.h"
#include <utility>
/**
* The Placement Factory is used to create objects at runtime in a specific pool.
* In general, this should be avoided and it should only be used if you know what you are doing.
* You are not allowed to use this container with a type that allocates memory internally like ArrayList.
*
* Also, you have to check the returned pointer in generate against nullptr!
*
* A backend of Type StorageManagerIF must be given as a place to store the new objects.
* Therefore ThreadSafety is only provided by your StorageManager Implementation.
*
* Objects must be destroyed by the user with "destroy"! Otherwise the pool will not be cleared.
*
* The concept is based on the placement new operator.
*
* @warning Do not use with any Type that allocates memory internally!
* @ingroup container
*/
class PlacementFactory {
public:
PlacementFactory(StorageManagerIF* backend) :
dataBackend(backend) {
}
/***
* Generates an object of type T in the backend storage.
*
* @warning Do not use with any Type that allocates memory internally!
*
* @tparam T Type of Object
* @param args Constructor Arguments to be passed
* @return A pointer to the new object or a nullptr in case of failure
*/
template<typename T, typename ... Args>
T* generate(Args&&... args) {
store_address_t tempId;
uint8_t* pData = nullptr;
uint8_t* pData = NULL;
ReturnValue_t result = dataBackend->getFreeElement(&tempId, sizeof(T),
&pData);
if (result != HasReturnvaluesIF::RETURN_OK) {
return nullptr;
return NULL;
}
T* temp = new (pData) T(std::forward<Args>(args)...);
return temp;
}
/***
* Function to destroy the object allocated with generate and free space in backend.
* This must be called by the user.
*
* @param thisElement Element to be destroyed
* @return RETURN_OK if the element was destroyed, different errors on failure
*/
template<typename T>
ReturnValue_t destroy(T* thisElement) {
if (thisElement == nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
//Need to call destructor first, in case something was allocated by the object (shouldn't do that, however).
thisElement->~T();
uint8_t* pointer = (uint8_t*) (thisElement);

View File

@@ -1,113 +1,96 @@
#ifndef FSFW_CONTAINER_RINGBUFFERBASE_H_
#define FSFW_CONTAINER_RINGBUFFERBASE_H_
#ifndef FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_
#define FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
template<uint8_t N_READ_PTRS = 1>
class RingBufferBase {
public:
RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) :
start(startAddress), write(startAddress), size(size),
overwriteOld(overwriteOld) {
RingBufferBase(uint32_t startAddress, uint32_t size, bool overwriteOld) :
start(startAddress), write(startAddress), size(size), overwriteOld(overwriteOld) {
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = startAddress;
}
}
virtual ~RingBufferBase() {}
bool isFull(uint8_t n = 0) {
return (availableWriteSpace(n) == 0);
}
bool isEmpty(uint8_t n = 0) {
return (getAvailableReadData(n) == 0);
}
size_t getAvailableReadData(uint8_t n = 0) const {
return ((write + size) - read[n]) % size;
}
size_t availableWriteSpace(uint8_t n = 0) const {
//One less to avoid ambiguous full/empty problem.
return (((read[n] + size) - write - 1) % size);
}
bool overwritesOld() const {
return overwriteOld;
}
size_t getMaxSize() const {
return size - 1;
}
void clear() {
write = start;
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = start;
}
}
size_t writeTillWrap() {
return (start + size) - write;
}
size_t readTillWrap(uint8_t n = 0) {
return (start + size) - read[n];
}
size_t getStart() const {
return start;
}
protected:
const size_t start;
size_t write;
size_t read[N_READ_PTRS];
const size_t size;
const bool overwriteOld;
void incrementWrite(uint32_t amount) {
write = ((write + amount - start) % size) + start;
}
void incrementRead(uint32_t amount, uint8_t n = 0) {
read[n] = ((read[n] + amount - start) % size) + start;
}
ReturnValue_t readData(uint32_t amount, uint8_t n = 0) {
if (getAvailableReadData(n) >= amount) {
if (availableReadData(n) >= amount) {
incrementRead(amount, n);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t writeData(uint32_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) {
if (availableWriteSpace() >= amount || overwriteOld) {
incrementWrite(amount);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint32_t availableReadData(uint8_t n = 0) const {
return ((write + size) - read[n]) % size;
}
uint32_t availableWriteSpace(uint8_t n = 0) const {
//One less to avoid ambiguous full/empty problem.
return (((read[n] + size) - write - 1) % size);
}
bool isFull(uint8_t n = 0) {
return (availableWriteSpace(n) == 0);
}
bool isEmpty(uint8_t n = 0) {
return (availableReadData(n) == 0);
}
virtual ~RingBufferBase() {
size_t getRead(uint8_t n = 0) const {
}
uint32_t getRead(uint8_t n = 0) const {
return read[n];
}
void setRead(uint32_t read, uint8_t n = 0) {
if (read >= start && read < (start+size)) {
this->read[n] = read;
}
}
uint32_t getWrite() const {
return write;
}
void setWrite(uint32_t write) {
this->write = write;
}
void clear() {
write = start;
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = start;
}
}
uint32_t writeTillWrap() {
return (start + size) - write;
}
uint32_t readTillWrap(uint8_t n = 0) {
return (start + size) - read[n];
}
uint32_t getStart() const {
return start;
}
bool overwritesOld() const {
return overwriteOld;
}
uint32_t maxSize() const {
return size - 1;
}
protected:
const uint32_t start;
uint32_t write;
uint32_t read[N_READ_PTRS];
const uint32_t size;
const bool overwriteOld;
void incrementWrite(uint32_t amount) {
write = ((write + amount - start) % size) + start;
}
void incrementRead(uint32_t amount, uint8_t n = 0) {
read[n] = ((read[n] + amount - start) % size) + start;
}
};
#endif /* FSFW_CONTAINER_RINGBUFFERBASE_H_ */
#endif /* FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ */

View File

@@ -0,0 +1,79 @@
#include <iostream>
#include "SimpleRingBuffer.h"
int main() {
using namespace std;
SimpleRingBuffer buffer(64, false);
uint8_t data[8] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};
ReturnValue_t result = buffer.writeData(data, 8);
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "writeData failed." << endl;
}
result = buffer.writeData(data, 8);
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "writeData failed." << endl;
}
uint8_t buffer2[47] = {0};
for (uint8_t count = 0; count<sizeof(buffer2); count++) {
buffer2[count] = count;
}
result = buffer.writeData(buffer2, sizeof(buffer2));
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "writeData failed." << endl;
}
result = buffer.writeData(buffer2, sizeof(buffer2));
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "writeData failed." << endl;
}
uint8_t readBuffer[64] = {0};
uint32_t writtenData = 0;
result = buffer.readData(readBuffer, 12, true, &writtenData);
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "readData failed." << endl;
} else {
cout << "Read data: " << writtenData << endl;
for (uint32_t count = 0; count < writtenData; count++) {
cout << hex << (uint16_t)readBuffer[count] << " ";
}
cout << dec << endl;
}
result = buffer.readData(readBuffer, 60, true, &writtenData);
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "readData failed." << endl;
} else {
cout << "Read data: " << writtenData << endl;
for (uint32_t count = 0; count < writtenData; count++) {
cout << hex << (uint16_t)readBuffer[count] << " ";
}
cout << dec << endl;
}
result = buffer.writeData(data, sizeof(data));
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "writeData failed." << endl;
}
result = buffer.readData(readBuffer, 60, true, &writtenData);
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "readData failed." << endl;
} else {
cout << "Read data: " << writtenData << endl;
for (uint32_t count = 0; count < writtenData; count++) {
cout << hex << (uint16_t)readBuffer[count] << " ";
}
cout << dec << endl;
}
result = buffer.writeData(readBuffer, sizeof(readBuffer));
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "writeData failed." << endl;
}
result = buffer.writeData(readBuffer, sizeof(readBuffer)-1);
if (result != HasReturnvaluesIF::RETURN_OK) {
cout << "writeData failed." << endl;
} else {
cout << "write done." << endl;
}
}

View File

@@ -1,55 +0,0 @@
#include "SharedRingBuffer.h"
#include "../ipc/MutexFactory.h"
#include "../ipc/MutexHelper.h"
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(size, overwriteOld,
maxExcessBytes) {
mutex = MutexFactory::instance()->createMutex();
}
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
const size_t size, bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld,
maxExcessBytes) {
mutex = MutexFactory::instance()->createMutex();
}
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
this->fifoDepth = fifoDepth;
}
ReturnValue_t SharedRingBuffer::lockRingBufferMutex(
MutexIF::TimeoutType timeoutType, dur_millis_t timeout) {
return mutex->lockMutex(timeoutType, timeout);
}
ReturnValue_t SharedRingBuffer::unlockRingBufferMutex() {
return mutex->unlockMutex();
}
MutexIF* SharedRingBuffer::getMutexHandle() const {
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

@@ -1,92 +0,0 @@
#ifndef FSFW_CONTAINER_SHAREDRINGBUFFER_H_
#define FSFW_CONTAINER_SHAREDRINGBUFFER_H_
#include "SimpleRingBuffer.h"
#include "DynamicFIFO.h"
#include "../ipc/MutexIF.h"
#include "../objectmanager/SystemObject.h"
#include "../timemanager/Clock.h"
/**
* @brief Ring buffer which can be shared among multiple objects
* @details
* This class offers a mutex to perform thread-safe operation on the ring
* buffer. It is still up to the developer to actually perform the lock
* and unlock operations.
*/
class SharedRingBuffer: public SystemObject,
public SimpleRingBuffer {
public:
/**
* This constructor allocates a new internal buffer with the supplied size.
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
*/
SharedRingBuffer(object_id_t objectId, const size_t size,
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.
* @param buffer
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
*/
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
bool overwriteOld, size_t maxExcessBytes);
/**
* Unless a read-only constant value is read, all operations on the
* shared ring buffer should be protected by calling this function.
* @param timeoutType
* @param timeout
* @return
*/
virtual ReturnValue_t lockRingBufferMutex(MutexIF::TimeoutType timeoutType,
dur_millis_t timeout);
/**
* Any locked mutex also has to be unlocked, otherwise, access to the
* shared ring buffer will be blocked.
* @return
*/
virtual ReturnValue_t unlockRingBufferMutex();
/**
* The mutex handle can be accessed directly, for example to perform
* the lock with the #MutexHelper for a RAII compliant lock operation.
* @return
*/
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:
MutexIF* mutex = nullptr;
size_t fifoDepth = 0;
DynamicFIFO<size_t>* receiveSizesFIFO = nullptr;
};
#endif /* FSFW_CONTAINER_SHAREDRINGBUFFER_H_ */

View File

@@ -1,69 +1,22 @@
#include "SimpleRingBuffer.h"
#include <cstring>
#include <string.h>
SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld,
size_t maxExcessBytes) :
RingBufferBase<>(0, size, overwriteOld),
maxExcessBytes(maxExcessBytes) {
if(maxExcessBytes > size) {
this->maxExcessBytes = size;
}
else {
this->maxExcessBytes = maxExcessBytes;
}
buffer = new uint8_t[size + maxExcessBytes];
}
SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size,
bool overwriteOld, size_t maxExcessBytes):
RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {
if(maxExcessBytes > size) {
this->maxExcessBytes = size;
}
else {
this->maxExcessBytes = maxExcessBytes;
}
SimpleRingBuffer::SimpleRingBuffer(uint32_t size, bool overwriteOld) :
RingBufferBase<>(0, size, overwriteOld), buffer(NULL) {
buffer = new uint8_t[size];
}
SimpleRingBuffer::~SimpleRingBuffer() {
delete[] buffer;
}
ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer,
size_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) {
size_t amountTillWrap = writeTillWrap();
if (amountTillWrap < amount) {
if((amount - amountTillWrap + excessBytes) > maxExcessBytes) {
return HasReturnvaluesIF::RETURN_FAILED;
}
excessBytes = amount - amountTillWrap;
}
*writePointer = &buffer[write];
return HasReturnvaluesIF::RETURN_OK;
}
else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
void SimpleRingBuffer::confirmBytesWritten(size_t amount) {
if(getExcessBytes() > 0) {
moveExcessBytesToStart();
}
incrementWrite(amount);
}
ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data,
size_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) {
size_t amountTillWrap = writeTillWrap();
uint32_t amount) {
if (availableWriteSpace() >= amount || overwriteOld) {
uint32_t amountTillWrap = writeTillWrap();
if (amountTillWrap >= amount) {
// remaining size in buffer is sufficient to fit full amount.
memcpy(&buffer[write], data, amount);
}
else {
} else {
memcpy(&buffer[write], data, amountTillWrap);
memcpy(buffer, data + amountTillWrap, amount - amountTillWrap);
}
@@ -74,19 +27,18 @@ ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data,
}
}
ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount,
bool incrementReadPtr, bool readRemaining, size_t* trueAmount) {
size_t availableData = getAvailableReadData(READ_PTR);
size_t amountTillWrap = readTillWrap(READ_PTR);
ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, uint32_t amount,
bool readRemaining, uint32_t* trueAmount) {
uint32_t availableData = availableReadData(READ_PTR);
uint32_t amountTillWrap = readTillWrap(READ_PTR);
if (availableData < amount) {
if (readRemaining) {
// more data available than amount specified.
amount = availableData;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
if (trueAmount != nullptr) {
if (trueAmount != NULL) {
*trueAmount = amount;
}
if (amountTillWrap >= amount) {
@@ -95,27 +47,12 @@ ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount,
memcpy(data, &buffer[read[READ_PTR]], amountTillWrap);
memcpy(data + amountTillWrap, buffer, amount - amountTillWrap);
}
if(incrementReadPtr) {
deleteData(amount, readRemaining);
}
return HasReturnvaluesIF::RETURN_OK;
}
size_t SimpleRingBuffer::getExcessBytes() const {
return excessBytes;
}
void SimpleRingBuffer::moveExcessBytesToStart() {
if(excessBytes > 0) {
std::memcpy(buffer, &buffer[size], excessBytes);
excessBytes = 0;
}
}
ReturnValue_t SimpleRingBuffer::deleteData(size_t amount,
bool deleteRemaining, size_t* trueAmount) {
size_t availableData = getAvailableReadData(READ_PTR);
ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount,
bool deleteRemaining, uint32_t* trueAmount) {
uint32_t availableData = availableReadData(READ_PTR);
if (availableData < amount) {
if (deleteRemaining) {
amount = availableData;
@@ -123,7 +60,7 @@ ReturnValue_t SimpleRingBuffer::deleteData(size_t amount,
return HasReturnvaluesIF::RETURN_FAILED;
}
}
if (trueAmount != nullptr) {
if (trueAmount != NULL) {
*trueAmount = amount;
}
incrementRead(amount, READ_PTR);

View File

@@ -1,129 +1,21 @@
#ifndef FSFW_CONTAINER_SIMPLERINGBUFFER_H_
#define FSFW_CONTAINER_SIMPLERINGBUFFER_H_
#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_
#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_
#include "RingBufferBase.h"
#include <cstddef>
#include <stddef.h>
/**
* @brief Circular buffer implementation, useful for buffering
* into data streams.
* @details
* Note that the deleteData() has to be called to increment the read pointer.
* This class allocated dynamically, so
* @ingroup containers
*/
class SimpleRingBuffer: public RingBufferBase<> {
public:
/**
* This constructor allocates a new internal buffer with the supplied size.
*
* @param size
* @param overwriteOld If the ring buffer is overflowing at a write
* operation, the oldest data will be overwritten.
* @param maxExcessBytes These additional bytes will be allocated in addtion
* to the specified size to accomodate contiguous write operations
* with getFreeElement.
*
*/
SimpleRingBuffer(const size_t size, bool overwriteOld,
size_t maxExcessBytes = 0);
/**
* This constructor takes an external buffer with the specified size.
* @param buffer
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
* @param maxExcessBytes
* If the buffer can accomodate additional bytes for contigous write
* operations with getFreeElement, this is the maximum allowed additional
* size
*/
SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld,
size_t maxExcessBytes = 0);
SimpleRingBuffer(uint32_t size, bool overwriteOld);
virtual ~SimpleRingBuffer();
/**
* Write to circular buffer and increment write pointer by amount.
* @param data
* @param amount
* @return -@c RETURN_OK if write operation was successfull
* -@c RETURN_FAILED if
*/
ReturnValue_t writeData(const uint8_t* data, size_t amount);
/**
* Returns a pointer to a free element. If the remaining buffer is
* not large enough, the data will be written past the actual size
* and the amount of excess bytes will be cached. This function
* does not increment the write pointer!
* @param writePointer Pointer to a pointer which can be used to write
* contiguous blocks into the ring buffer
* @param amount
* @return
*/
ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount);
/**
* This increments the write pointer and also copies the excess bytes
* to the beginning. It should be called if the write operation
* conducted after calling getFreeElement() was performed.
* @return
*/
void confirmBytesWritten(size_t amount);
virtual size_t getExcessBytes() const;
/**
* Helper functions which moves any excess bytes to the start
* of the ring buffer.
* @return
*/
virtual void moveExcessBytesToStart();
/**
* Read from circular buffer at read pointer.
* @param data
* @param amount
* @param incrementReadPtr
* If this is set to true, the read pointer will be incremented.
* If readRemaining is set to true, the read pointer will be incremented
* accordingly.
* @param readRemaining
* If this is set to true, the data will be read even if the amount
* specified exceeds the read data available.
* @param trueAmount [out]
* If readRemaining was set to true, the true amount read will be assigned
* to the passed value.
* @return
* - @c RETURN_OK if data was read successfully
* - @c RETURN_FAILED if not enough data was available and readRemaining
* was set to false.
*/
ReturnValue_t readData(uint8_t* data, size_t amount,
bool incrementReadPtr = false, bool readRemaining = false,
size_t* trueAmount = nullptr);
/**
* Delete data by incrementing read pointer.
* @param amount
* @param deleteRemaining
* If the amount specified is larger than the remaing size to read and this
* is set to true, the remaining amount will be deleted as well
* @param trueAmount [out]
* If deleteRemaining was set to true, the amount deleted will be assigned
* to the passed value.
* @return
*/
ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false,
size_t* trueAmount = nullptr);
ReturnValue_t writeData(const uint8_t* data, uint32_t amount);
ReturnValue_t readData(uint8_t* data, uint32_t amount, bool readRemaining = false, uint32_t* trueAmount = NULL);
ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false, uint32_t* trueAmount = NULL);
private:
// static const uint8_t TEMP_READ_PTR = 1;
static const uint8_t READ_PTR = 0;
uint8_t* buffer = nullptr;
size_t maxExcessBytes;
size_t excessBytes = 0;
uint8_t* buffer;
};
#endif /* FSFW_CONTAINER_SIMPLERINGBUFFER_H_ */
#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */

View File

@@ -1,13 +1,10 @@
#ifndef FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_
#define FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_
#include <cstddef>
#include <cstdint>
#ifndef SINGLYLINKEDLIST_H_
#define SINGLYLINKEDLIST_H_
#include <stddef.h>
#include <stdint.h>
/**
* @brief Linked list data structure,
* each entry has a pointer to the next entry (singly)
* @ingroup container
* \ingroup container
*/
template<typename T>
class LinkedElement {
@@ -15,8 +12,11 @@ public:
T *value;
class Iterator {
public:
LinkedElement<T> *value = nullptr;
Iterator() {}
LinkedElement<T> *value;
Iterator() :
value(NULL) {
}
Iterator(LinkedElement<T> *element) :
value(element) {
@@ -45,11 +45,12 @@ public:
}
};
LinkedElement(T* setElement, LinkedElement<T>* setNext = nullptr):
value(setElement), next(setNext) {}
virtual ~LinkedElement(){}
LinkedElement(T* setElement, LinkedElement<T>* setNext = NULL) : value(setElement),
next(setNext) {
}
virtual ~LinkedElement(){
}
virtual LinkedElement* getNext() const {
return next;
}
@@ -57,16 +58,11 @@ public:
virtual void setNext(LinkedElement* next) {
this->next = next;
}
virtual void setEnd() {
this->next = nullptr;
}
LinkedElement* begin() {
return this;
}
LinkedElement* end() {
return nullptr;
return NULL;
}
private:
LinkedElement *next;
@@ -75,80 +71,37 @@ private:
template<typename T>
class SinglyLinkedList {
public:
using ElementIterator = typename LinkedElement<T>::Iterator;
SinglyLinkedList() {}
SinglyLinkedList(ElementIterator start) :
start(start.value) {}
SinglyLinkedList() :
start(NULL) {
}
SinglyLinkedList(typename LinkedElement<T>::Iterator start) :
start(start.value) {
}
SinglyLinkedList(LinkedElement<T>* startElement) :
start(startElement) {}
ElementIterator begin() const {
return ElementIterator::Iterator(start);
start(startElement) {
}
typename LinkedElement<T>::Iterator begin() const {
return LinkedElement<T>::Iterator::Iterator(start);
}
typename LinkedElement<T>::Iterator::Iterator end() const {
return LinkedElement<T>::Iterator::Iterator();
}
/** Returns iterator to nulltr */
ElementIterator end() const {
return ElementIterator::Iterator();
}
/**
* Returns last element in singly linked list.
* @return
*/
ElementIterator back() const {
LinkedElement<T> *element = start;
while (element->getNext() != nullptr) {
element = element->getNext();
}
return ElementIterator::Iterator(element);
}
size_t getSize() const {
size_t size = 0;
uint32_t getSize() const {
uint32_t size = 0;
LinkedElement<T> *element = start;
while (element != nullptr) {
while (element != NULL) {
size++;
element = element->getNext();
}
return size;
}
void setStart(LinkedElement<T>* firstElement) {
start = firstElement;
void setStart(LinkedElement<T>* setStart) {
start = setStart;
}
void setNext(LinkedElement<T>* currentElement,
LinkedElement<T>* nextElement) {
currentElement->setNext(nextElement);
}
void setLast(LinkedElement<T>* lastElement) {
lastElement->setEnd();
}
void insertElement(LinkedElement<T>* element, size_t position) {
LinkedElement<T> *currentElement = start;
for(size_t count = 0; count < position; count++) {
if(currentElement == nullptr) {
return;
}
currentElement = currentElement->getNext();
}
LinkedElement<T>* elementAfterCurrent = currentElement->next;
currentElement->setNext(element);
if(elementAfterCurrent != nullptr) {
element->setNext(elementAfterCurrent);
}
}
void insertBack(LinkedElement<T>* lastElement) {
back().value->setNext(lastElement);
}
protected:
LinkedElement<T> *start = nullptr;
LinkedElement<T> *start;
};
#endif /* SINGLYLINKEDLIST_H_ */

View File

@@ -0,0 +1,365 @@
#include "FixedArrayList.h"
#include "SinglyLinkedList.h"
#include "HybridIterator.h"
#include "FixedMap.h"
#include <stdio.h>
/*
class Packet: public SinglyLinkedList {
public:
SinglyLinkedList::Element<uint32_t> element1;
SinglyLinkedList::Element<uint32_t> element2;
Packet() {
this->start = &element1;
element1.next = &element2;
}
};
class Packet2: public SinglyLinkedList {
public:
SinglyLinkedList::Element<uint32_t> element1;
SinglyLinkedList::Element<FixedArrayList<FixedArrayList<uint8_t, 5>, 2>> element2;
SinglyLinkedList::Element<uint32_t> element3;
Packet2() {
this->start = &element1;
element1.next = &element2;
element2.next = &element3;
}
};
class Packet3: public SinglyLinkedList {
public:
SinglyLinkedList::TypedElement<uint32_t> element1;
SinglyLinkedList::TypedElement<uint32_t> element2;
Packet3() {
this->start = &element1;
element1.next = &element2;
}
};
void arrayList() {
puts("** Array List **");
FixedArrayList<uint32_t, 10, uint32_t> list;
FixedArrayList<uint32_t, 10, uint32_t> list2;
list.size = 2;
list[0] = 0xcafecafe;
list[1] = 0x12345678;
uint8_t buffer[100];
uint8_t *pointer = buffer;
uint32_t size = 0;
uint32_t maxSize = 100;
uint32_t i;
int32_t size2;
printf("printsize: %i\n", list.getPrintSize());
list.print(&pointer, &size, 100, true);
printf("buffer(%i):", size);
for (i = 0; i < size; ++i) {
printf("%02x", buffer[i]);
}
printf("\n");
pointer = buffer;
size2 = size;
printf("list2 read: %x\n", list2.read(&pointer, &size2, true));
printf("list2(%i):", list2.size);
for (ArrayList<uint32_t, uint32_t>::Iterator iter = list2.begin();
iter != list2.end(); iter++) {
printf("0x%04x ", *iter);
}
printf("\n");
HybridIterator<uint32_t, uint32_t> hiter(list.begin(),list.end());
printf("hybrid1: 0x%04x\n", *(hiter++));
printf("hybrid2: 0x%04x\n", *hiter);
}
void allocatingList() {
puts("** Allocating List **");
ArrayList<uint8_t> myList(3), myList2(2);
myList[0] = 0xab;
myList[1] = 0xcd;
myList.size = 2;
uint8_t buffer[100];
uint8_t *pointer = buffer;
uint32_t size = 0;
uint32_t maxSize = 100;
uint32_t i;
int32_t size2;
myList.print(&pointer, &size, 100, true);
pointer = buffer;
size2 = size;
printf("Read %x\n", myList2.read(&pointer, &size2, true));
printf("%x,%x\n", myList2[0], myList2[1]);
}
void linkedList() {
puts("** Linked List **");
uint8_t buffer[100];
uint8_t *pointer = buffer;
uint32_t size = 0;
uint32_t maxSize = 100;
uint32_t i;
int32_t size2;
Packet myPacket;
myPacket.element1.entry = 0x12345678;
myPacket.element2.entry = 0x9abcdef0;
pointer = buffer;
size = 0;
ReturnValue_t result = myPacket.print(&pointer, &size, 100, true);
printf("result %02x\n", result);
printf("printsize: %i\n", myPacket.getPrintSize());
printf("buffer(%i):", size);
for (i = 0; i < size; ++i) {
printf("%02x", buffer[i]);
}
printf("\n");
Packet3 myPacket3;
myPacket3.element1.entry = 0x12345678;
myPacket3.element2.entry = 0xabcdeff;
SinglyLinkedList::TypedIterator<uint32_t> titer(&myPacket3.element1);
printf("0x%04x\n", *titer);
HybridIterator<uint32_t, uint32_t> hiter(&myPacket3.element1);
printf("hybrid1: 0x%04x\n", *hiter);
hiter++;
printf("hybrid2: 0x%04x\n", *hiter);
}
void complex() {
puts("** complex **");
uint8_t buffer[100];
uint8_t *pointer = buffer;
uint32_t size = 0;
uint32_t maxSize = 100;
uint32_t i;
int32_t size2 = size;
Packet myPacket2;
size2 = size;
pointer = buffer;
myPacket2.read(&pointer, &size2, true);
printf("packet: 0x%04x, 0x%04x\n", myPacket2.element1.entry,
myPacket2.element2.entry);
buffer[0] = 0x12;
buffer[1] = 0x34;
buffer[2] = 0x56;
buffer[3] = 0x78;
buffer[4] = 0x2;
buffer[5] = 0x3;
buffer[6] = 0xab;
buffer[7] = 0xcd;
buffer[8] = 0xef;
buffer[9] = 0x2;
buffer[10] = 0x11;
buffer[11] = 0x22;
buffer[12] = 0xca;
buffer[13] = 0xfe;
buffer[14] = 0x5a;
buffer[15] = 0xfe;
pointer = buffer;
size2 = 23;
Packet2 p2;
ReturnValue_t result = p2.read(&pointer, &size2, true);
printf("result is %02x\n", result);
printf("%04x; %i: %i: %x %x %x; %i: %x %x;; %04x\n", p2.element1.entry,
p2.element2.entry.size, p2.element2.entry[0].size,
p2.element2.entry[0][0], p2.element2.entry[0][1],
p2.element2.entry[0][2], p2.element2.entry[1].size,
p2.element2.entry[1][0], p2.element2.entry[1][1],
p2.element3.entry);
}
*/
struct Test {
uint32_t a;
uint32_t b;
};
template<typename key_t, typename T>
void printMap(FixedMap<key_t, T> *map) {
typename FixedMap<key_t, T>::Iterator iter;
printf("Map (%i): ", map->getSize());
for (iter = map->begin(); iter != map->end(); ++iter) {
printf("%x:%08x,%08x ", iter.value->first, (*iter).a, (*iter).b);
}
printf("\n");
}
template<typename T>
void map() {
puts("** Map **");
typename FixedMap<T, Test>::Iterator iter;
ReturnValue_t result;
FixedMap<T, Test> myMap(5);
printMap<T, Test>(&myMap);
Test a;
a.a = 0x01234567;
a.b = 0xabcdef89;
myMap.insert(1, a);
printMap<T, Test>(&myMap);
a.a = 0;
myMap.insert(2, a);
printMap<T, Test>(&myMap);
printf("2 exists: %x\n", myMap.exists(0x02));
printf("ff exists: %x\n", myMap.exists(0xff));
a.a = 1;
printf("insert 0x2: %x\n", myMap.insert(2, a));
result = myMap.insert(0xff, a);
a.a = 0x44;
result = myMap.insert(0xab, a);
result = myMap.insert(0xa, a);
printMap<T, Test>(&myMap);
printf("insert 0x5: %x\n", myMap.insert(5, a));
printf("erase 0xfe: %x\n", myMap.erase(0xfe));
printf("erase 0x2: %x\n", myMap.erase(0x2));
printMap<T, Test>(&myMap);
printf("erase 0xab: %x\n", myMap.erase(0xab));
printMap<T, Test>(&myMap);
printf("insert 0x5: %x\n", myMap.insert(5, a));
printMap<T, Test>(&myMap);
iter = myMap.begin();
++iter;
++iter;
++iter;
printf("iter: %i: %x,%x\n",iter.value->first, iter->a, iter->b);
myMap.erase(&iter);
printf("iter: %i: %x,%x\n",iter.value->first, iter->a, iter->b);
printMap<T, Test>(&myMap);
}
/*
void mapPrint() {
puts("** Map Print **");
FixedMap<uint16_t, Packet2> myMap(5);
Packet2 myPacket;
myPacket.element1.entry = 0x12345678;
myPacket.element2.entry[0][0] = 0xab;
myPacket.element2.entry[0][1] = 0xcd;
myPacket.element2.entry[0].size = 2;
myPacket.element2.entry.size = 1;
myPacket.element3.entry = 0xabcdef90;
myMap.insert(0x1234, myPacket);
uint8_t buffer[100];
uint32_t size = 0, i;
uint8_t *pointer = buffer;
printf("printsize: %i\n", myMap.getPrintSize());
SerializeAdapter<FixedMap<uint16_t, Packet2>>::print(&myMap, &pointer,
&size, 100, false);
printf("buffer(%i):", size);
for (i = 0; i < size; ++i) {
printf("%02x", buffer[i]);
}
printf("\n");
int32_t size2 = size;
pointer = buffer;
FixedMap<uint16_t, Packet2> myMap2(5);
ReturnValue_t result = SerializeAdapter<FixedMap<uint16_t, Packet2>>::read(
&myMap2, &pointer, &size2, false);
Packet2 *myPacket2 = myMap2.find(0x1234);
printf("Map (%i): Packet2: %x, Array (%i): Array (%i): %x, %x; %x\n",
myMap2.getSize(), myPacket2->element1.entry,
myPacket2->element2.entry.size, myPacket2->element2.entry[0].size,
myPacket2->element2.entry[0][0], myPacket2->element2.entry[0][1],
myPacket2->element3.entry);
}
void empty() {
puts("** Empty **");
ArrayList<uint32_t> list(0);
printf("%p %p\n", list.front(), list.back());
}
*/
int main(void) {
// arrayList();
// linkedList();
// allocatingList();
// complex();
map<uint32_t>();
//
// mapPrint();
// empty();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,117 +1,117 @@
#ifndef _sgp4unit_
#define _sgp4unit_
/* ----------------------------------------------------------------
*
* sgp4unit.h
*
* this file contains the sgp4 procedures for analytical propagation
* of a satellite. the code was originally released in the 1980 and 1986
* spacetrack papers. a detailed discussion of the theory and history
* may be found in the 2006 aiaa paper by vallado, crawford, hujsak,
* and kelso.
*
* companion code for
* fundamentals of astrodynamics and applications
* 2007
* by david vallado
*
* (w) 719-573-2600, email dvallado@agi.com
*
* current :
* 20 apr 07 david vallado
* misc fixes for constants
* changes :
* 11 aug 06 david vallado
* chg lyddane choice back to strn3, constants, misc doc
* 15 dec 05 david vallado
* misc fixes
* 26 jul 05 david vallado
* fixes for paper
* note that each fix is preceded by a
* comment with "sgp4fix" and an explanation of
* what was changed
* 10 aug 04 david vallado
* 2nd printing baseline working
* 14 may 01 david vallado
* 2nd edition baseline
* 80 norad
* original baseline
* ---------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
// -------------------------- structure declarations ----------------------------
typedef enum
{
wgs72old,
wgs72,
wgs84
} gravconsttype;
typedef struct elsetrec
{
long int satnum;
int epochyr, epochtynumrev;
int error;
char init, method;
/* Near Earth */
int isimp;
double aycof , con41 , cc1 , cc4 , cc5 , d2 , d3 , d4 ,
delmo , eta , argpdot, omgcof , sinmao , t , t2cof, t3cof ,
t4cof , t5cof , x1mth2 , x7thm1 , mdot , nodedot, xlcof , xmcof ,
nodecf;
/* Deep Space */
int irez;
double d2201 , d2211 , d3210 , d3222 , d4410 , d4422 , d5220 , d5232 ,
d5421 , d5433 , dedt , del1 , del2 , del3 , didt , dmdt ,
dnodt , domdt , e3 , ee2 , peo , pgho , pho , pinco ,
plo , se2 , se3 , sgh2 , sgh3 , sgh4 , sh2 , sh3 ,
si2 , si3 , sl2 , sl3 , sl4 , gsto , xfact , xgh2 ,
xgh3 , xgh4 , xh2 , xh3 , xi2 , xi3 , xl2 , xl3 ,
xl4 , xlamo , zmol , zmos , atime , xli , xni;
double a , altp , alta , epochdays, jdsatepoch , nddot , ndot ,
bstar , rcse , inclo , nodeo , ecco , argpo , mo ,
no;
} elsetrec;
// --------------------------- function declarations ----------------------------
int sgp4init
(
gravconsttype whichconst, const int satn, const double epoch,
const double xbstar, const double xecco, const double xargpo,
const double xinclo, const double xmo, const double xno,
const double xnodeo,
elsetrec& satrec
);
int sgp4
(
gravconsttype whichconst,
elsetrec& satrec, double tsince,
double r[], double v[]
);
double gstime
(
double
);
void getgravconst
(
gravconsttype,
double&,
double&,
double&,
double&,
double&,
double&,
double&,
double&
);
#endif
#ifndef _sgp4unit_
#define _sgp4unit_
/* ----------------------------------------------------------------
*
* sgp4unit.h
*
* this file contains the sgp4 procedures for analytical propagation
* of a satellite. the code was originally released in the 1980 and 1986
* spacetrack papers. a detailed discussion of the theory and history
* may be found in the 2006 aiaa paper by vallado, crawford, hujsak,
* and kelso.
*
* companion code for
* fundamentals of astrodynamics and applications
* 2007
* by david vallado
*
* (w) 719-573-2600, email dvallado@agi.com
*
* current :
* 20 apr 07 david vallado
* misc fixes for constants
* changes :
* 11 aug 06 david vallado
* chg lyddane choice back to strn3, constants, misc doc
* 15 dec 05 david vallado
* misc fixes
* 26 jul 05 david vallado
* fixes for paper
* note that each fix is preceded by a
* comment with "sgp4fix" and an explanation of
* what was changed
* 10 aug 04 david vallado
* 2nd printing baseline working
* 14 may 01 david vallado
* 2nd edition baseline
* 80 norad
* original baseline
* ---------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
// -------------------------- structure declarations ----------------------------
typedef enum
{
wgs72old,
wgs72,
wgs84
} gravconsttype;
typedef struct elsetrec
{
long int satnum;
int epochyr, epochtynumrev;
int error;
char init, method;
/* Near Earth */
int isimp;
double aycof , con41 , cc1 , cc4 , cc5 , d2 , d3 , d4 ,
delmo , eta , argpdot, omgcof , sinmao , t , t2cof, t3cof ,
t4cof , t5cof , x1mth2 , x7thm1 , mdot , nodedot, xlcof , xmcof ,
nodecf;
/* Deep Space */
int irez;
double d2201 , d2211 , d3210 , d3222 , d4410 , d4422 , d5220 , d5232 ,
d5421 , d5433 , dedt , del1 , del2 , del3 , didt , dmdt ,
dnodt , domdt , e3 , ee2 , peo , pgho , pho , pinco ,
plo , se2 , se3 , sgh2 , sgh3 , sgh4 , sh2 , sh3 ,
si2 , si3 , sl2 , sl3 , sl4 , gsto , xfact , xgh2 ,
xgh3 , xgh4 , xh2 , xh3 , xi2 , xi3 , xl2 , xl3 ,
xl4 , xlamo , zmol , zmos , atime , xli , xni;
double a , altp , alta , epochdays, jdsatepoch , nddot , ndot ,
bstar , rcse , inclo , nodeo , ecco , argpo , mo ,
no;
} elsetrec;
// --------------------------- function declarations ----------------------------
int sgp4init
(
gravconsttype whichconst, const int satn, const double epoch,
const double xbstar, const double xecco, const double xargpo,
const double xinclo, const double xmo, const double xno,
const double xnodeo,
elsetrec& satrec
);
int sgp4
(
gravconsttype whichconst,
elsetrec& satrec, double tsince,
double r[], double v[]
);
double gstime
(
double
);
void getgravconst
(
gravconsttype,
double&,
double&,
double&,
double&,
double&,
double&,
double&,
double&
);
#endif

View File

@@ -18,7 +18,7 @@ MapPacketExtraction::MapPacketExtraction(uint8_t setMapId,
object_id_t setPacketDestination) :
lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), bufferPosition(
packetBuffer), packetDestination(setPacketDestination), packetStore(
NULL), tcQueueId(MessageQueueIF::NO_QUEUE) {
NULL), tcQueueId(MessageQueueSenderIF::NO_QUEUE) {
memset(packetBuffer, 0, sizeof(packetBuffer));
}

View File

@@ -61,7 +61,7 @@ ReturnValue_t DataPool::freeDataPoolLock() {
}
ReturnValue_t DataPool::lockDataPool() {
ReturnValue_t status = mutex->lockMutex(MutexIF::BLOCKING);
ReturnValue_t status = mutex->lockMutex(MutexIF::NO_TIMEOUT);
if ( status != RETURN_OK ) {
sif::error << "DataPool::DataPool: lock of mutex failed with error code: " << status << std::endl;
}

View File

@@ -1,6 +0,0 @@
# 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

@@ -1,55 +0,0 @@
#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

@@ -1,16 +0,0 @@
#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

@@ -1,9 +0,0 @@
#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

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

View File

@@ -1,18 +0,0 @@
#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

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

View File

@@ -1,12 +0,0 @@
#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

@@ -1,18 +0,0 @@
#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

@@ -1,15 +0,0 @@
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

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

View File

@@ -1,21 +0,0 @@
#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

@@ -1,54 +0,0 @@
#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

@@ -1,17 +0,0 @@
#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

@@ -1,16 +0,0 @@
#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

@@ -1,23 +0,0 @@
#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

@@ -1,32 +0,0 @@
#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

@@ -1,16 +0,0 @@
#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

@@ -1,18 +0,0 @@
#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

@@ -1,23 +0,0 @@
#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

@@ -1,19 +1,17 @@
#include "../subsystem/SubsystemBase.h"
#include "../devicehandlers/ChildHandlerBase.h"
#include "ChildHandlerBase.h"
#include "../subsystem/SubsystemBase.h"
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId,
object_id_t deviceCommunication, CookieIF * cookie,
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId,
object_id_t parent, FailureIsolationBase* customFdir,
size_t cmdQueueSize) :
DeviceHandlerBase(setObjectId, deviceCommunication, cookie,
(customFdir == nullptr? &childHandlerFdir : customFdir),
cmdQueueSize),
object_id_t deviceCommunication, CookieIF * comCookie,
uint8_t setDeviceSwitch, uint32_t thermalStatePoolId,
uint32_t thermalRequestPoolId, uint32_t parent,
FailureIsolationBase* customFdir, size_t cmdQueueSize) :
DeviceHandlerBase(setObjectId, deviceCommunication, comCookie,
setDeviceSwitch, thermalStatePoolId,thermalRequestPoolId,
(customFdir == nullptr? &childHandlerFdir : customFdir),
cmdQueueSize),
parentId(parent), childHandlerFdir(setObjectId) {
this->setThermalStateRequestPoolIds(thermalStatePoolId,
thermalRequestPoolId);
}
ChildHandlerBase::~ChildHandlerBase() {
@@ -27,7 +25,7 @@ ReturnValue_t ChildHandlerBase::initialize() {
MessageQueueId_t parentQueue = 0;
if (parentId != objects::NO_OBJECT) {
if (parentId != 0) {
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
if (parent == NULL) {
return RETURN_FAILED;

View File

@@ -1,15 +1,15 @@
#ifndef FSFW_DEVICES_CHILDHANDLERBASE_H_
#define FSFW_DEVICES_CHILDHANDLERBASE_H_
#ifndef PAYLOADHANDLERBASE_H_
#define PAYLOADHANDLERBASE_H_
#include "ChildHandlerFDIR.h"
#include "DeviceHandlerBase.h"
class ChildHandlerBase: public DeviceHandlerBase {
public:
ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
CookieIF * cookie, uint32_t thermalStatePoolId,
uint32_t thermalRequestPoolId,
object_id_t parent = objects::NO_OBJECT,
ChildHandlerBase(object_id_t setObjectId,
object_id_t deviceCommunication, CookieIF * comCookie,
uint8_t setDeviceSwitch, uint32_t thermalStatePoolId,
uint32_t thermalRequestPoolId, uint32_t parent,
FailureIsolationBase* customFdir = nullptr,
size_t cmdQueueSize = 20);
virtual ~ChildHandlerBase();
@@ -22,5 +22,4 @@ protected:
};
#endif /* FSFW_DEVICES_CHILDHANDLERBASE_H_ */
#endif /* PAYLOADHANDLERBASE_H_ */

View File

@@ -1,12 +1,12 @@
#include "DeviceHandlerBase.h"
#include "AcceptsDeviceResponsesIF.h"
#include "DeviceTmReportingWrapper.h"
#include "../objectmanager/ObjectManager.h"
#include "../storagemanager/StorageManagerIF.h"
#include "../thermal/ThermalComponentIF.h"
#include "AcceptsDeviceResponsesIF.h"
#include "../datapool/DataSet.h"
#include "../datapool/PoolVariable.h"
#include "DeviceTmReportingWrapper.h"
#include "../globalfunctions/CRC.h"
#include "../subsystem/SubsystemBase.h"
#include "../ipc/QueueFactory.h"
@@ -14,47 +14,45 @@
#include <iomanip>
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT;
object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT;
object_id_t DeviceHandlerBase::powerSwitcherId = 0;
object_id_t DeviceHandlerBase::rawDataReceiverId = 0;
object_id_t DeviceHandlerBase::defaultFDIRParentId = 0;
DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId,
object_id_t deviceCommunication, CookieIF * comCookie,
FailureIsolationBase* fdirInstance, size_t cmdQueueSize) :
uint8_t setDeviceSwitch, uint32_t thermalStatePoolId,
uint32_t thermalRequestPoolId, FailureIsolationBase* fdirInstance,
size_t cmdQueueSize) :
SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE),
wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS),
deviceCommunicationId(deviceCommunication), comCookie(comCookie),
deviceThermalStatePoolId(thermalStatePoolId),
deviceThermalRequestPoolId(thermalRequestPoolId),
healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this),
actionHelper(this, nullptr), childTransitionFailure(RETURN_OK),
fdirInstance(fdirInstance), hkSwitcher(this),
defaultFDIRUsed(fdirInstance == nullptr), switchOffWasReported(false),
childTransitionDelay(5000), transitionSourceMode(_MODE_POWER_DOWN),
transitionSourceSubMode(SUBMODE_NONE) {
childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance),
hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr),
switchOffWasReported(false), actionHelper(this, nullptr),
childTransitionDelay(5000),
transitionSourceMode(_MODE_POWER_DOWN), transitionSourceSubMode(
SUBMODE_NONE), deviceSwitch(setDeviceSwitch) {
commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize,
MessageQueueMessage::MAX_MESSAGE_SIZE);
CommandMessage::MAX_MESSAGE_SIZE);
insertInCommandMap(RAW_COMMAND_ID);
cookieInfo.state = COOKIE_UNUSED;
cookieInfo.pendingCommand = deviceCommandMap.end();
if (comCookie == nullptr) {
sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex
<< std::setw(8) << std::setfill('0') << this->getObjectId()
<< std::dec << ": Do not pass nullptr as a cookie, consider "
<< std::setfill(' ') << "passing a dummy cookie instead!"
<< std::endl;
sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex <<
std::setw(8) << std::setfill('0') << this->getObjectId() <<
std::dec << ": Do not pass nullptr as a cookie, consider "
<< std::setfill(' ') << "passing a dummy cookie instead!" <<
std::endl;
}
if (this->fdirInstance == nullptr) {
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId,
defaultFdirParentId);
defaultFDIRParentId);
}
}
void DeviceHandlerBase::setThermalStateRequestPoolIds(
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId) {
this->deviceThermalRequestPoolId = thermalStatePoolId;
this->deviceThermalRequestPoolId = thermalRequestPoolId;
}
DeviceHandlerBase::~DeviceHandlerBase() {
delete comCookie;
if (defaultFDIRUsed) {
@@ -110,12 +108,8 @@ ReturnValue_t DeviceHandlerBase::initialize() {
communicationInterface = objectManager->get<DeviceCommunicationIF>(
deviceCommunicationId);
if (communicationInterface == nullptr) {
sif::error << "DeviceHandlerBase::initialize: Communication interface "
"invalid." << std::endl;
sif::error << "Make sure it is set up properly and implements"
" DeviceCommunicationIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
if (communicationInterface == NULL) {
return RETURN_FAILED;
}
result = communicationInterface->initializeInterface(comCookie);
@@ -124,40 +118,27 @@ ReturnValue_t DeviceHandlerBase::initialize() {
}
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (IPCStore == nullptr) {
sif::error << "DeviceHandlerBase::initialize: IPC store not set up in "
"factory." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
if (IPCStore == NULL) {
return RETURN_FAILED;
}
if(rawDataReceiverId != objects::NO_OBJECT) {
AcceptsDeviceResponsesIF *rawReceiver = objectManager->get<
AcceptsDeviceResponsesIF>(rawDataReceiverId);
AcceptsDeviceResponsesIF *rawReceiver = objectManager->get<
AcceptsDeviceResponsesIF>(rawDataReceiverId);
if (rawReceiver == nullptr) {
sif::error << "DeviceHandlerBase::initialize: Raw receiver object "
"ID set but no valid object found." << std::endl;
sif::error << "Make sure the raw receiver object is set up properly"
" and implements AcceptsDeviceResponsesIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
defaultRawReceiver = rawReceiver->getDeviceQueue();
if (rawReceiver == NULL) {
return RETURN_FAILED;
}
if(powerSwitcherId != objects::NO_OBJECT) {
powerSwitcher = objectManager->get<PowerSwitchIF>(powerSwitcherId);
if (powerSwitcher == nullptr) {
sif::error << "DeviceHandlerBase::initialize: Power switcher "
<< "object ID set but no valid object found." << std::endl;
sif::error << "Make sure the raw receiver object is set up properly"
<< " and implements PowerSwitchIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
defaultRawReceiver = rawReceiver->getDeviceQueue();
powerSwitcher = objectManager->get<PowerSwitchIF>(powerSwitcherId);
if (powerSwitcher == NULL) {
return RETURN_FAILED;
}
result = healthHelper.initialize();
if (result != RETURN_OK) {
return result;
return result;
}
result = modeHelper.initialize();
@@ -187,7 +168,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
//Set temperature target state to NON_OP.
DataSet mySet;
db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariable<int8_t> thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariableIF::VAR_WRITE);
mySet.read();
thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
@@ -219,43 +200,38 @@ void DeviceHandlerBase::readCommandQueue() {
return;
}
CommandMessage command;
ReturnValue_t result = commandQueue->receiveMessage(&command);
CommandMessage message;
ReturnValue_t result = commandQueue->receiveMessage(&message);
if (result != RETURN_OK) {
return;
}
result = healthHelper.handleHealthCommand(&command);
if (result == RETURN_OK) {
return;
}
result = modeHelper.handleModeCommand(&command);
result = healthHelper.handleHealthCommand(&message);
if (result == RETURN_OK) {
return;
}
result = actionHelper.handleActionMessage(&command);
result = modeHelper.handleModeCommand(&message);
if (result == RETURN_OK) {
return;
}
result = parameterHelper.handleParameterMessage(&command);
result = actionHelper.handleActionMessage(&message);
if (result == RETURN_OK) {
return;
}
// result = hkManager.handleHousekeepingMessage(&command);
// if (result == RETURN_OK) {
// return;
// }
result = handleDeviceHandlerMessage(&command);
result = parameterHelper.handleParameterMessage(&message);
if (result == RETURN_OK) {
return;
}
result = letChildHandleMessage(&command);
result = handleDeviceHandlerMessage(&message);
if (result == RETURN_OK) {
return;
}
result = letChildHandleMessage(&message);
if (result == RETURN_OK) {
return;
}
@@ -297,8 +273,7 @@ void DeviceHandlerBase::doStateMachine() {
case _MODE_WAIT_ON: {
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
if (powerSwitcher != nullptr and currentUptime - timeoutStart >=
powerSwitcher->getSwitchDelayMs()) {
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT,
0);
setMode(_MODE_POWER_DOWN);
@@ -318,12 +293,6 @@ void DeviceHandlerBase::doStateMachine() {
case _MODE_WAIT_OFF: {
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
if(powerSwitcher == nullptr) {
setMode(MODE_OFF);
break;
}
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT,
0);
@@ -374,10 +343,9 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode,
}
}
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
size_t replyLen, bool periodic, bool hasDifferentReplyId,
DeviceCommandId_t replyId) {
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand,
uint16_t maxDelayCycles, size_t replyLen, bool periodic,
bool hasDifferentReplyId, DeviceCommandId_t replyId) {
//No need to check, as we may try to insert multiple times.
insertInCommandMap(deviceCommand);
if (hasDifferentReplyId) {
@@ -403,8 +371,7 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
}
}
ReturnValue_t DeviceHandlerBase::insertInCommandMap(
DeviceCommandId_t deviceCommand) {
ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand) {
DeviceCommandInfo info;
info.expectedReplies = 0;
info.isExecuting = false;
@@ -452,7 +419,7 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) {
transitionSourceSubMode = submode;
childTransitionFailure = CHILD_TIMEOUT;
// transitionTargetMode is set by setMode
//transitionTargetMode is set by setMode
setMode((modeTo | TRANSITION_MODE_CHILD_ACTION_MASK), submodeTo);
}
@@ -470,7 +437,7 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
if (mode == MODE_OFF) {
DataSet mySet;
db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariable<int8_t> thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariableIF::VAR_READ_WRITE);
mySet.read();
if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
@@ -611,8 +578,11 @@ void DeviceHandlerBase::doSendRead() {
}
void DeviceHandlerBase::doGetRead() {
size_t receivedDataLen = 0;
uint8_t *receivedData = nullptr;
size_t receivedDataLen;
uint8_t *receivedData;
DeviceCommandId_t foundId = 0xFFFFFFFF;
size_t foundLen = 0;
ReturnValue_t result;
if (cookieInfo.state != COOKIE_READ_SENT) {
cookieInfo.state = COOKIE_UNUSED;
@@ -621,8 +591,8 @@ void DeviceHandlerBase::doGetRead() {
cookieInfo.state = COOKIE_UNUSED;
ReturnValue_t result = communicationInterface->readReceivedMessage(
comCookie, &receivedData, &receivedDataLen);
result = communicationInterface->readReceivedMessage(comCookie,
&receivedData, &receivedDataLen);
if (result != RETURN_OK) {
triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result);
@@ -638,101 +608,51 @@ void DeviceHandlerBase::doGetRead() {
replyRawData(receivedData, receivedDataLen, requestedRawTraffic);
}
if (mode == MODE_RAW and defaultRawReceiver != MessageQueueIF::NO_QUEUE) {
if (mode == MODE_RAW) {
replyRawReplyIfnotWiretapped(receivedData, receivedDataLen);
}
else {
parseReply(receivedData, receivedDataLen);
}
}
void DeviceHandlerBase::parseReply(const uint8_t* receivedData,
size_t receivedDataLen) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
DeviceCommandId_t foundId = 0xFFFFFFFF;
size_t foundLen = 0;
// The loop may not execute more often than the number of received bytes
// (worst case). This approach avoids infinite loops due to buggy
// scanForReply routines.
uint32_t remainingLength = receivedDataLen;
for (uint32_t count = 0; count < receivedDataLen; count++) {
result = scanForReply(receivedData, remainingLength, &foundId,
&foundLen);
switch (result) {
case RETURN_OK:
handleReply(receivedData, foundId, foundLen);
break;
case APERIODIC_REPLY: {
result = interpretDeviceReply(foundId, receivedData);
if (result != RETURN_OK) {
} else {
//The loop may not execute more often than the number of received bytes (worst case).
//This approach avoids infinite loops due to buggy scanForReply routines (seen in bug 1077).
uint32_t remainingLength = receivedDataLen;
for (uint32_t count = 0; count < receivedDataLen; count++) {
result = scanForReply(receivedData, remainingLength, &foundId,
&foundLen);
switch (result) {
case RETURN_OK:
handleReply(receivedData, foundId, foundLen);
break;
case APERIODIC_REPLY: {
result = interpretDeviceReply(foundId, receivedData);
if (result != RETURN_OK) {
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result,
foundId);
}
}
break;
case IGNORE_REPLY_DATA:
break;
case IGNORE_FULL_PACKET:
return;
default:
//We need to wait for timeout.. don't know what command failed and who sent it.
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result,
foundId);
triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen);
break;
}
receivedData += foundLen;
if (remainingLength > foundLen) {
remainingLength -= foundLen;
} else {
return;
}
}
break;
case IGNORE_REPLY_DATA:
break;
case IGNORE_FULL_PACKET:
return;
default:
//We need to wait for timeout.. don't know what command failed and who sent it.
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen);
break;
}
receivedData += foundLen;
if (remainingLength > foundLen) {
remainingLength -= foundLen;
} else {
return;
}
}
}
void DeviceHandlerBase::handleReply(const uint8_t* receivedData,
DeviceCommandId_t foundId, uint32_t foundLen) {
ReturnValue_t result;
DeviceReplyMap::iterator iter = deviceReplyMap.find(foundId);
if (iter == deviceReplyMap.end()) {
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_UNKNOWN_REPLY, foundId);
return;
}
DeviceReplyInfo *info = &(iter->second);
if (info->delayCycles != 0) {
if (info->periodic != false) {
info->delayCycles = info->maxDelayCycles;
}
else {
info->delayCycles = 0;
}
result = interpretDeviceReply(foundId, receivedData);
if (result != RETURN_OK) {
// Report failed interpretation to FDIR.
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId);
}
replyToReply(iter, result);
}
else {
// Other completion failure messages are created by timeout.
// Powering down the device might take some time during which periodic
// replies may still come in.
if (mode != _MODE_WAIT_OFF) {
triggerEvent(DEVICE_UNREQUESTED_REPLY, foundId);
}
}
}
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress,
uint8_t** data, uint32_t * len) {
uint8_t * *data, uint32_t * len) {
size_t lenTmp;
if (IPCStore == nullptr) {
@@ -755,7 +675,7 @@ ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress,
void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len,
MessageQueueId_t sendTo, bool isCommand) {
if (IPCStore == nullptr or len == 0 or sendTo == MessageQueueIF::NO_QUEUE) {
if (IPCStore == NULL || len == 0) {
return;
}
store_address_t address;
@@ -766,17 +686,18 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len,
return;
}
CommandMessage command;
CommandMessage message;
DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&command,
DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&message,
getObjectId(), address, isCommand);
result = commandQueue->sendMessage(sendTo, &command);
// this->DeviceHandlerCommand = CommandMessage::CMD_NONE;
result = commandQueue->sendMessage(sendTo, &message);
if (result != RETURN_OK) {
IPCStore->deleteData(address);
// Silently discard data, this indicates heavy TM traffic which
// should not be increased by additional events.
//Silently discard data, this indicates heavy TM traffic which should not be increased by additional events.
}
}
@@ -805,6 +726,57 @@ MessageQueueId_t DeviceHandlerBase::getCommandQueue() const {
return commandQueue->getId();
}
void DeviceHandlerBase::handleReply(const uint8_t* receivedData,
DeviceCommandId_t foundId, uint32_t foundLen) {
ReturnValue_t result;
DeviceReplyMap::iterator iter = deviceReplyMap.find(foundId);
if (iter == deviceReplyMap.end()) {
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_UNKNOWN_REPLY, foundId);
return;
}
DeviceReplyInfo *info = &(iter->second);
if (info->delayCycles != 0) {
if (info->periodic) {
info->delayCycles = info->maxDelayCycles;
} else {
info->delayCycles = 0;
}
result = interpretDeviceReply(foundId, receivedData);
if (result != RETURN_OK) {
//Report failed interpretation to FDIR.
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId);
}
replyToReply(iter, result);
} else {
//Other completion failure messages are created by timeout.
//Powering down the device might take some time during which periodic replies may still come in.
if (mode != _MODE_WAIT_OFF) {
triggerEvent(DEVICE_UNREQUESTED_REPLY, foundId);
}
}
}
//ReturnValue_t DeviceHandlerBase::switchCookieChannel(object_id_t newChannelId) {
// DeviceCommunicationIF *newCommunication = objectManager->get<
// DeviceCommunicationIF>(newChannelId);
//
// if (newCommunication != NULL) {
// ReturnValue_t result = newCommunication->reOpen(cookie, ioBoardAddress,
// maxDeviceReplyLen);
// if (result != RETURN_OK) {
// return result;
// }
// return RETURN_OK;
// }
// return RETURN_FAILED;
//}
void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) {
storedRawData = DeviceHandlerMessage::getStoreAddress(commandMessage);
ReturnValue_t result = getStorageData(storedRawData, &rawPacket,
@@ -821,9 +793,6 @@ void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) {
}
void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) {
if(powerSwitcher == nullptr) {
return;
}
const uint8_t *switches;
uint8_t numberOfSwitches = 0;
ReturnValue_t result = getSwitches(&switches, &numberOfSwitches);
@@ -838,7 +807,9 @@ void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) {
ReturnValue_t DeviceHandlerBase::getSwitches(const uint8_t **switches,
uint8_t *numberOfSwitches) {
return DeviceHandlerBase::NO_SWITCH;
*switches = &deviceSwitch;
*numberOfSwitches = 1;
return RETURN_OK;
}
void DeviceHandlerBase::modeChanged(void) {
@@ -874,9 +845,6 @@ uint32_t DeviceHandlerBase::getTransitionDelayMs(Mode_t modeFrom,
}
ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) {
if(powerSwitcher == nullptr) {
return NO_SWITCH;
}
uint8_t numberOfSwitches = 0;
const uint8_t *switches;
@@ -927,9 +895,9 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode,
if ((commandedMode == MODE_ON) && (mode == MODE_OFF)
&& (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) {
DataSet mySet;
db_int8_t thermalState(deviceThermalStatePoolId, &mySet,
PoolVariable<int8_t> thermalState(deviceThermalStatePoolId, &mySet,
PoolVariableIF::VAR_READ);
db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariable<int8_t> thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariableIF::VAR_READ);
mySet.read();
if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
@@ -957,7 +925,7 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode,
MODE_ON);
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
DataSet mySet;
db_int8_t thermalRequest(deviceThermalRequestPoolId,
PoolVariable<int8_t> thermalRequest(deviceThermalRequestPoolId,
&mySet, PoolVariableIF::VAR_READ_WRITE);
mySet.read();
if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
@@ -1029,8 +997,8 @@ HasHealthIF::HealthState DeviceHandlerBase::getHealth() {
}
ReturnValue_t DeviceHandlerBase::setHealth(HealthState health) {
healthHelper.setHealth(health);
return HasReturnvaluesIF::RETURN_OK;
healthHelper.setHealth(health);
return HasReturnvaluesIF::RETURN_OK;
}
void DeviceHandlerBase::checkSwitchState() {
@@ -1143,47 +1111,35 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data,
return;
}
DeviceTmReportingWrapper wrapper(getObjectId(), replyId, data);
//replies to a command
if (iter->second.command != deviceCommandMap.end())
{
if (iter->second.command != deviceCommandMap.end()) {//replies to a command
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
if (queueId != NO_COMMANDER) {
//This may fail, but we'll ignore the fault.
actionHelper.reportData(queueId, replyId, data);
}
//This check should make sure we get any TM but don't get anything doubled.
if (wiretappingMode == TM && (requestedRawTraffic != queueId)) {
actionHelper.reportData(requestedRawTraffic, replyId, &wrapper);
}
else if (forceDirectTm and (defaultRawReceiver != queueId) and
(defaultRawReceiver != MessageQueueIF::NO_QUEUE))
{
// hiding of sender needed so the service will handle it as
// unexpected Data, no matter what state (progress or completed)
// it is in
} else if (forceDirectTm && (defaultRawReceiver != queueId)) {
// hiding of sender needed so the service will handle it as unexpected Data, no matter what state
//(progress or completed) it is in
actionHelper.reportData(defaultRawReceiver, replyId, &wrapper,
true);
true);
}
}
//unrequested/aperiodic replies
else
{
} else { //unrequested/aperiodic replies
if (wiretappingMode == TM) {
actionHelper.reportData(requestedRawTraffic, replyId, &wrapper);
}
else if (forceDirectTm and defaultRawReceiver !=
MessageQueueIF::NO_QUEUE)
{
// hiding of sender needed so the service will handle it as
// unexpected Data, no matter what state (progress or completed)
// it is in
} else if (forceDirectTm) {
// hiding of sender needed so the service will handle it as unexpected Data, no matter what state
//(progress or completed) it is in
actionHelper.reportData(defaultRawReceiver, replyId, &wrapper,
true);
true);
}
}
//Try to cast to GlobDataSet and commit data.
//Try to cast to DataSet and commit data.
if (!neverInDataPool) {
DataSet* dataSet = dynamic_cast<DataSet*>(data);
if (dataSet != NULL) {
@@ -1222,23 +1178,18 @@ void DeviceHandlerBase::buildInternalCommand(void) {
if (mode == MODE_NORMAL) {
result = buildNormalDeviceCommand(&deviceCommandId);
if (result == BUSY) {
//so we can track misconfigurations
sif::debug << std::hex << getObjectId()
<< ": DHB::buildInternalCommand: Busy" << std::dec << std::endl;
<< ": DHB::buildInternalCommand busy" << std::endl; //so we can track misconfigurations
result = NOTHING_TO_SEND; //no need to report this
}
}
else if (mode == MODE_RAW) {
} else if (mode == MODE_RAW) {
result = buildChildRawCommand();
deviceCommandId = RAW_COMMAND_ID;
}
else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) {
} else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) {
result = buildTransitionDeviceCommand(&deviceCommandId);
}
else {
} else {
return;
}
if (result == NOTHING_TO_SEND) {
return;
}
@@ -1330,22 +1281,11 @@ void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {
}
void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){
executingTask = task_;
executingTask = task_;
}
// Default implementations empty.
void DeviceHandlerBase::debugInterface(uint8_t positionTracker,
object_id_t objectId, uint32_t parameter) {}
void DeviceHandlerBase::performOperationHook() {
}
ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
// In this function, the task handle should be valid if the task
// was implemented correctly. We still check to be 1000 % sure :-)
if(executingTask != nullptr) {
pstIntervalMs = executingTask->getPeriodMs();
}
return HasReturnvaluesIF::RETURN_OK;
}
void DeviceHandlerBase::performOperationHook() {}

View File

@@ -1,23 +1,22 @@
#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
#include "DeviceHandlerIF.h"
#include "DeviceCommunicationIF.h"
#include "DeviceHandlerFailureIsolation.h"
#ifndef DEVICEHANDLERBASE_H_
#define DEVICEHANDLERBASE_H_
#include "../objectmanager/SystemObject.h"
#include "../tasks/PeriodicTaskIF.h"
#include "../tasks/ExecutableObjectIF.h"
#include "DeviceHandlerIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../action/HasActionsIF.h"
#include "../datapool/PoolVariableIF.h"
#include "DeviceCommunicationIF.h"
#include "../modes/HasModesIF.h"
#include "../power/PowerSwitchIF.h"
#include "../ipc/MessageQueueIF.h"
#include "../action/ActionHelper.h"
#include "../health/HealthHelper.h"
#include "../parameters/ParameterHelper.h"
#include "../datapool/HkSwitchHelper.h"
#include "DeviceHandlerFailureIsolation.h"
#include <map>
@@ -47,16 +46,14 @@ class StorageManagerIF;
* If data has been received (GET_READ), the data will be interpreted.
* The action for each step can be defined by the child class but as most
* device handlers share a 4-call (sendRead-getRead-sendWrite-getWrite) structure,
* a default implementation is provided.
* NOTE: RMAP is a standard which is used for FLP.
* a default implementation is provided. NOTE: RMAP is a standard which is used for FLP.
* RMAP communication is not mandatory for projects implementing the FSFW.
* However, the communication principles are similar to RMAP as there are
* two write and two send calls involved.
*
* Device handler instances should extend this class and implement the abstract
* functions. Components and drivers can send so called cookies which are used
* for communication and contain information about the communcation (e.g. slave
* address for I2C or RMAP structs).
* Device handler instances should extend this class and implement the abstract functions.
* Components and drivers can send so called cookies which are used for communication
* and contain information about the communcation (e.g. slave address for I2C or RMAP structs).
* The following abstract methods must be implemented by a device handler:
* 1. doStartUp()
* 2. doShutDown()
@@ -103,12 +100,12 @@ public:
* @param cmdQueueSize
*/
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
CookieIF * comCookie, FailureIsolationBase* fdirInstance = nullptr,
CookieIF * comCookie, uint8_t setDeviceSwitch,
uint32_t thermalStatePoolId = PoolVariableIF::NO_PARAMETER,
uint32_t thermalRequestPoolId = PoolVariableIF::NO_PARAMETER,
FailureIsolationBase* fdirInstance = nullptr,
size_t cmdQueueSize = 20);
void setThermalStateRequestPoolIds(uint32_t thermalStatePoolId,
uint32_t thermalRequestPoolId);
/**
* @brief This function is the device handler base core component and is
* called periodically.
@@ -153,9 +150,11 @@ public:
* @return
*/
virtual ReturnValue_t initialize();
/** Destructor. */
virtual ~DeviceHandlerBase();
/**
* Destructor.
*/
virtual ~DeviceHandlerBase();
protected:
/**
* @brief This is used to let the child class handle the transition from
@@ -233,9 +232,8 @@ protected:
* Build the device command to send for a transitional mode.
*
* This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW,
* @c _MODE_START_UP and @c _MODE_SHUT_DOWN. So it is used by doStartUp()
* and doShutDown() as well as doTransition(), by setting those
* modes in the respective functions.
* @c _MODE_START_UP and @c _MODE_TO_POWER_DOWN. So it is used by doStartUp()
* and doShutDown() as well as doTransition()
*
* A good idea is to implement a flag indicating a command has to be built
* and a variable containing the command number to be built
@@ -323,11 +321,12 @@ protected:
* - @c RETURN_FAILED when the reply could not be interpreted,
* e.g. logical errors or range violations occurred
*/
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id,
const uint8_t *packet) = 0;
/**
* @brief fill the #DeviceCommandMap and #DeviceReplyMap
* @brief fill the #deviceCommandMap
* called by the initialize() of the base class
* @details
* This is used to let the base class know which replies are expected.
@@ -471,18 +470,6 @@ protected:
virtual ReturnValue_t getSwitches(const uint8_t **switches,
uint8_t *numberOfSwitches);
/**
* This function is used to initialize the local housekeeping pool
* entries. The default implementation leaves the pool empty.
* @param localDataPoolMap
* @return
*/
//virtual ReturnValue_t initializePoolEntries(
// LocalDataPool& localDataPoolMap) override;
/** Get the HK manager object handle */
//virtual LocalDataPoolManager* getHkManagerHandle() override;
/**
* @brief Hook function for child handlers which is called once per
* performOperation(). Default implementation is empty.
@@ -506,7 +493,7 @@ public:
ReturnValue_t setHealth(HealthState health);
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex) override;
const ParameterWrapper *newValues, uint16_t startAtIndex);
/**
* Implementation of ExecutableObjectIF function
*
@@ -518,7 +505,7 @@ public:
protected:
/**
* The Returnvalues id of this class, required by HasReturnvaluesIF
* The Returnvalues ID of this class, required by HasReturnvaluesIF
*/
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
@@ -540,138 +527,114 @@ protected:
static const DeviceCommandId_t NO_COMMAND_ID = -2;
static const MessageQueueId_t NO_COMMANDER = 0;
/** Pointer to the raw packet that will be sent.*/
/**
* Pointer to the raw packet that will be sent.
*/
uint8_t *rawPacket = nullptr;
/** Size of the #rawPacket. */
/**
* Size of the #rawPacket.
*/
uint32_t rawPacketLen = 0;
/**
* The mode the device handler is currently in.
*
* This should never be changed directly but only with setMode()
*/
Mode_t mode;
/**
* The submode the device handler is currently in.
*
* This should never be changed directly but only with setMode()
*/
Submode_t submode;
/** This is the counter value from performOperation(). */
/**
* This is the counter value from performOperation().
*/
uint8_t pstStep = 0;
uint32_t pstIntervalMs = 0;
/**
* Wiretapping flag:
* wiretapping flag:
*
* indicates either that all raw messages to and from the device should be
* sent to #defaultRawReceiver
* or that all device TM should be downlinked to #defaultRawReceiver.
* indicates either that all raw messages to and from the device should be sent to #theOneWhoWantsToReadRawTraffic
* or that all device TM should be downlinked to #theOneWhoWantsToReadRawTraffic
*/
enum WiretappingMode {
OFF = 0, RAW = 1, TM = 2
} wiretappingMode;
/**
* @brief A message queue that accepts raw replies
* A message queue that accepts raw replies
*
* Statically initialized in initialize() to a configurable object.
* Used when there is no method of finding a recipient, ie raw mode and
* reporting erroneous replies
* Statically initialized in initialize() to a configurable object. Used when there is no method
* of finding a recipient, ie raw mode and reporting erreonous replies
*/
MessageQueueId_t defaultRawReceiver = MessageQueueIF::NO_QUEUE;
MessageQueueId_t defaultRawReceiver = 0;
store_address_t storedRawData;
/**
* @brief The message queue which wants to read all raw traffic
* If #isWiretappingActive all raw communication from and to the device
* will be sent to this queue
* the message queue which wants to read all raw traffic
*
* if #isWiretappingActive all raw communication from and to the device will be sent to this queue
*/
MessageQueueId_t requestedRawTraffic = 0;
/**
* the object used to set power switches
*/
PowerSwitchIF *powerSwitcher = nullptr;
/**
* Pointer to the IPCStore.
*
* This caches the pointer received from the objectManager in the constructor.
*/
StorageManagerIF *IPCStore = nullptr;
/** The comIF object ID is cached for the intialize() function */
/**
* cached for init
*/
object_id_t deviceCommunicationId;
/** Communication object used for device communication */
/**
* Communication object used for device communication
*/
DeviceCommunicationIF * communicationInterface = nullptr;
/** Cookie used for communication */
/**
* Cookie used for communication
*/
CookieIF * comCookie;
/** Health helper for HasHealthIF */
HealthHelper healthHelper;
/** Mode helper for HasModesIF */
ModeHelper modeHelper;
/** Parameter helper for ReceivesParameterMessagesIF */
ParameterHelper parameterHelper;
/** Action helper for HasActionsIF */
ActionHelper actionHelper;
/** Housekeeping Manager */
//LocalDataPoolManager hkManager;
/**
* @brief Information about commands
*/
struct DeviceCommandInfo {
//! Indicates if the command is already executing.
bool isExecuting;
//! Dynamic value to indicate how many replies are expected.
//! Inititated with 0.
uint8_t expectedReplies;
//! if this is != NO_COMMANDER, DHB was commanded externally and shall
//! report everything to commander.
MessageQueueId_t sendReplyTo;
bool isExecuting; //!< Indicates if the command is already executing.
uint8_t expectedReplies; //!< Dynamic value to indicate how many replies are expected. Inititated with 0.
MessageQueueId_t sendReplyTo; //!< if this is != NO_COMMANDER, DHB was commanded externally and shall report everything to commander.
};
using DeviceCommandMap = std::map<DeviceCommandId_t, DeviceCommandInfo> ;
/**
* Information about commands
*/
DeviceCommandMap deviceCommandMap;
/**
* @brief Information about expected replies
* This is used to keep track of pending replies.
*
* This is used to keep track of pending replies
*/
struct DeviceReplyInfo {
//! The maximum number of cycles the handler should wait for a reply
//! to this command.
uint16_t maxDelayCycles;
//! The currently remaining cycles the handler should wait for a reply,
//! 0 means there is no reply expected
uint16_t delayCycles;
uint16_t maxDelayCycles; //!< The maximum number of cycles the handler should wait for a reply to this command.
uint16_t delayCycles; //!< The currently remaining cycles the handler should wait for a reply, 0 means there is no reply expected
size_t replyLen = 0; //!< Expected size of the reply.
//! if this is !=0, the delayCycles will not be reset to 0 but to
//! maxDelayCycles
bool periodic = false;
//! The dataset used to access housekeeping data related to the
//! respective device reply. Will point to a dataset held by
//! the child handler (if one is specified)
// DataSetIF* dataSet = nullptr;
//! The command that expects this reply.
DeviceCommandMap::iterator command;
bool periodic; //!< if this is !=0, the delayCycles will not be reset to 0 but to maxDelayCycles
DeviceCommandMap::iterator command; //!< The command that expects this reply.
};
using DeviceReplyMap = std::map<DeviceCommandId_t, DeviceReplyInfo> ;
using DeviceReplyIter = DeviceReplyMap::iterator;
/**
* This map is used to check and track correct reception of all replies.
*
* It has multiple use:
* - It stores the information on pending replies. If a command is sent,
* the DeviceCommandInfo.count is incremented.
* - It is used to time-out missing replies. If a command is sent, the
* DeviceCommandInfo.DelayCycles is set to MaxDelayCycles.
* - It is queried to check if a reply from the device can be interpreted.
* scanForReply() returns the id of the command a reply was found for.
* The reply is ignored in the following cases:
* - No entry for the returned id was found
* - The deviceReplyInfo.delayCycles is == 0
*/
DeviceReplyMap deviceReplyMap;
//! The MessageQueue used to receive device handler commands
//! and to send replies.
/**
* The MessageQueue used to receive device handler commands and to send replies.
*/
MessageQueueIF* commandQueue = nullptr;
/**
@@ -679,14 +642,23 @@ protected:
*
* can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking
*/
uint32_t deviceThermalStatePoolId = PoolVariableIF::NO_PARAMETER;
uint32_t deviceThermalStatePoolId;
/**
* this is the datapool variable with the thermal request of the device
*
* can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking
*/
uint32_t deviceThermalRequestPoolId = PoolVariableIF::NO_PARAMETER;
uint32_t deviceThermalRequestPoolId;
/**
* Taking care of the health
*/
HealthHelper healthHelper;
ModeHelper modeHelper;
ParameterHelper parameterHelper;
/**
* Optional Error code
@@ -704,15 +676,13 @@ protected:
bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown.
//! Pointer to the task which executes this component, is invalid
//! before setTaskIF was called.
PeriodicTaskIF* executingTask = nullptr;
PeriodicTaskIF* executingTask = nullptr;//!< Pointer to the task which executes this component, is invalid before setTaskIF was called.
static object_id_t powerSwitcherId; //!< Object which switches power on and off.
static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default.
static object_id_t defaultFdirParentId; //!< Object which may be the root cause of an identified fault.
static object_id_t defaultFDIRParentId; //!< Object which may be the root cause of an identified fault.
/**
* Helper function to report a missed reply
*
@@ -760,40 +730,28 @@ protected:
/**
* Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW).
*
* If the transition is complete, the mode should be set to the target mode,
* which can be deduced from the current mode which is
* If the transition is complete, the mode should be set to the target mode, which can be deduced from the current mode which is
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]
*
* The intended target submode is already set.
* The origin submode can be read in subModeFrom.
* The intended target submode is already set. The origin submode can be read in subModeFrom.
*
* If the transition can not be completed, the child class can try to reach
* an working mode by setting the mode either directly
* or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW)
* if the device needs to be reconfigured.
* If the transition can not be completed, the child class can try to reach an working mode by setting the mode either directly
* or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW) if the device needs to be reconfigured.
*
* If nothing works, the child class can wait for the timeout and the base
* class will reset the mode to the mode where the transition
* If nothing works, the child class can wait for the timeout and the base class will reset the mode to the mode where the transition
* originated from (the child should report the reason for the failed transition).
*
* The intended way to send commands is to set a flag (enum) indicating
* which command is to be sent here and then to check in
* buildTransitionCommand() for the flag. This flag can also be used by
* doStartUp() and doShutDown() to get a nice and clean implementation of
* buildTransitionCommand() without switching through modes.
* The intended way to send commands is to set a flag (enum) indicating which command is to be sent here
* and then to check in buildTransitionCommand() for the flag. This flag can also be used by doStartUp() and
* doShutDown() to get a nice and clean implementation of buildTransitionCommand() without switching through modes.
*
* When the the condition for the completion of the transition is met, the
* mode can be set, for example in the scanForReply() function.
* When the the condition for the completion of the transition is met, the mode can be set, for example in the parseReply() function.
*
* The default implementation goes into the target mode directly.
* The default implementation goes into the target mode;
*
* #transitionFailure can be set to a failure code indicating the reason
* for a failed transition
* #transitionFailure can be set to a failure code indicating the reason for a failed transition
*
* @param modeFrom
* The mode the transition originated from:
* [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed
* from _MODE_START_UP to _MODE_TO_ON)]
* @param modeFrom the mode the transition originated from: [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed from _MODE_START_UP to _MODE_TO_ON)]
* @param subModeFrom the subMode of modeFrom
*/
virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom);
@@ -995,11 +953,24 @@ protected:
bool commandIsExecuting(DeviceCommandId_t commandId);
/**
* set all switches returned by getSwitches()
* This map is used to check and track correct reception of all replies.
*
* @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON
* It has multiple use:
* - it stores the information on pending replies. If a command is sent, the DeviceCommandInfo.count is incremented.
* - it is used to time-out missing replies. If a command is sent, the DeviceCommandInfo.DelayCycles is set to MaxDelayCycles.
* - it is queried to check if a reply from the device can be interpreted. scanForReply() returns the id of the command a reply was found for.
* The reply is ignored in the following cases:
* - No entry for the returned id was found
* - The deviceReplyInfo.delayCycles is == 0
*/
void commandSwitch(ReturnValue_t onOff);
DeviceReplyMap deviceReplyMap;
/**
* Information about commands
*/
DeviceCommandMap deviceCommandMap;
ActionHelper actionHelper;
private:
/**
@@ -1026,16 +997,15 @@ private:
};
/**
* @brief Info about the #cookie
* Info about the #cookie
*
* Used to track the state of the communication
*/
CookieInfo cookieInfo;
/** the object used to set power switches */
PowerSwitchIF *powerSwitcher = nullptr;
/**
* @brief Used for timing out mode transitions.
* Used for timing out mode transitions.
*
* Set when setMode() is called.
*/
uint32_t timeoutStart = 0;
@@ -1046,12 +1016,11 @@ private:
uint32_t childTransitionDelay;
/**
* @brief The mode the current transition originated from
* The mode the current transition originated from
*
* This is private so the child can not change it and fuck up the timeouts
*
* IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!!
* (it is _MODE_POWER_DOWN during this modes)
* IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!! (it is _MODE_POWER_DOWN during this modes)
*
* is element of [MODE_ON, MODE_NORMAL, MODE_RAW]
*/
@@ -1062,6 +1031,13 @@ private:
*/
Submode_t transitionSourceSubMode;
/**
* the switch of the device
*
* for devices using two switches override getSwitches()
*/
const uint8_t deviceSwitch;
/**
* read the command queue
*/
@@ -1159,6 +1135,12 @@ private:
ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data,
uint32_t *len);
/**
* set all switches returned by getSwitches()
*
* @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON
*/
void commandSwitch(ReturnValue_t onOff);
/**
* @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW NOTHING ELSE!!!
@@ -1183,12 +1165,7 @@ private:
ReturnValue_t switchCookieChannel(object_id_t newChannelId);
ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message);
virtual ReturnValue_t initializeAfterTaskCreation() override;
void parseReply(const uint8_t* receivedData,
size_t receivedDataLen);
};
#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
#endif /* DEVICEHANDLERBASE_H_ */

View File

@@ -1,27 +1,19 @@
#include "DeviceHandlerBase.h"
#include "DeviceHandlerFailureIsolation.h"
#include "../devicehandlers/DeviceHandlerIF.h"
#include "../modes/HasModesIF.h"
#include "../health/HealthTableIF.h"
#include "../power/Fuse.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../thermal/ThermalComponentIF.h"
object_id_t DeviceHandlerFailureIsolation::powerConfirmationId =
objects::NO_OBJECT;
object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = 0;
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner,
object_id_t parent) :
FailureIsolationBase(owner, parent),
strangeReplyCount(DEFAULT_MAX_STRANGE_REPLIES,
DEFAULT_STRANGE_REPLIES_TIME_MS,
parameterDomainBase++),
missedReplyCount( DEFAULT_MAX_MISSED_REPLY_COUNT,
DEFAULT_MISSED_REPLY_TIME_MS,
parameterDomainBase++),
recoveryCounter(DEFAULT_MAX_REBOOT, DEFAULT_REBOOT_TIME_MS,
parameterDomainBase++),
fdirState(NONE) {
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent) :
FailureIsolationBase(owner, parent), strangeReplyCount(MAX_STRANGE_REPLIES,
STRANGE_REPLIES_TIME_MS, parameterDomainBase++), missedReplyCount(
MAX_MISSED_REPLY_COUNT, MISSED_REPLY_TIME_MS,
parameterDomainBase++), recoveryCounter(MAX_REBOOT,
REBOOT_TIME_MS, parameterDomainBase++), fdirState(NONE), powerConfirmation(
0) {
}
DeviceHandlerFailureIsolation::~DeviceHandlerFailureIsolation() {
@@ -76,11 +68,9 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
break;
//****Power*****
case PowerSwitchIF::SWITCH_WENT_OFF:
if(powerConfirmation != MessageQueueIF::NO_QUEUE) {
result = sendConfirmationRequest(event, powerConfirmation);
if (result == RETURN_OK) {
setFdirState(DEVICE_MIGHT_BE_OFF);
}
result = sendConfirmationRequest(event, powerConfirmation);
if (result == RETURN_OK) {
setFdirState(DEVICE_MIGHT_BE_OFF);
}
break;
case Fuse::FUSE_WENT_OFF:
@@ -143,7 +133,7 @@ void DeviceHandlerFailureIsolation::decrementFaultCounters() {
void DeviceHandlerFailureIsolation::handleRecovery(Event reason) {
clearFaultCounters();
if (not recoveryCounter.incrementAndCheck()) {
if (!recoveryCounter.incrementAndCheck()) {
startRecovery(reason);
} else {
setFaulty(reason);
@@ -152,8 +142,7 @@ void DeviceHandlerFailureIsolation::handleRecovery(Event reason) {
void DeviceHandlerFailureIsolation::wasParentsFault(EventMessage* event) {
//We'll better ignore the SWITCH_WENT_OFF event and await a system-wide reset.
//This means, no fault message will come through until a MODE_ or
//HEALTH_INFO message comes through -> Is that ok?
//This means, no fault message will come through until a MODE_ or HEALTH_INFO message comes through -> Is that ok?
//Same issue in TxFailureIsolation!
// if ((event->getEvent() == PowerSwitchIF::SWITCH_WENT_OFF)
// && (fdirState != RECOVERY_ONGOING)) {
@@ -169,16 +158,14 @@ void DeviceHandlerFailureIsolation::clearFaultCounters() {
ReturnValue_t DeviceHandlerFailureIsolation::initialize() {
ReturnValue_t result = FailureIsolationBase::initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "DeviceHandlerFailureIsolation::initialize: Could not"
" initialize FailureIsolationBase." << std::endl;
return result;
}
ConfirmsFailuresIF* power = objectManager->get<ConfirmsFailuresIF>(
powerConfirmationId);
if (power != nullptr) {
powerConfirmation = power->getEventReceptionQueue();
if (power == NULL) {
return RETURN_FAILED;
}
powerConfirmation = power->getEventReceptionQueue();
return RETURN_OK;
}

View File

@@ -1,13 +1,13 @@
#ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_
#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_
#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_
#include "../fdir/FaultCounter.h"
#include "../fdir/FailureIsolationBase.h"
namespace Factory{
void setStaticFrameworkObjectIds();
}
class DeviceHandlerFailureIsolation: public FailureIsolationBase {
friend void (Factory::setStaticFrameworkObjectIds)();
friend class Heater;
@@ -20,27 +20,22 @@ public:
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex);
protected:
FaultCounter strangeReplyCount;
FaultCounter missedReplyCount;
FaultCounter recoveryCounter;
enum FDIRState {
NONE, RECOVERY_ONGOING, DEVICE_MIGHT_BE_OFF, AWAIT_SHUTDOWN
};
FDIRState fdirState;
MessageQueueId_t powerConfirmation = MessageQueueIF::NO_QUEUE;
MessageQueueId_t powerConfirmation;
static object_id_t powerConfirmationId;
static const uint32_t DEFAULT_MAX_REBOOT = 1;
static const uint32_t DEFAULT_REBOOT_TIME_MS = 180000;
static const uint32_t DEFAULT_MAX_STRANGE_REPLIES = 10;
static const uint32_t DEFAULT_STRANGE_REPLIES_TIME_MS = 10000;
static const uint32_t DEFAULT_MAX_MISSED_REPLY_COUNT = 5;
static const uint32_t DEFAULT_MISSED_REPLY_TIME_MS = 10000;
static const uint32_t MAX_REBOOT = 1;
static const uint32_t REBOOT_TIME_MS = 180000;
static const uint32_t MAX_STRANGE_REPLIES = 10;
static const uint32_t STRANGE_REPLIES_TIME_MS = 10000;
static const uint32_t MAX_MISSED_REPLY_COUNT = 5;
static const uint32_t MISSED_REPLY_TIME_MS = 10000;
virtual ReturnValue_t eventReceived(EventMessage* event);
virtual void eventConfirmed(EventMessage* event);
void wasParentsFault(EventMessage* event);
@@ -54,4 +49,4 @@ protected:
bool isFdirInActionOrAreWeFaulty(EventMessage* event);
};
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ */
#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ */

View File

@@ -25,7 +25,7 @@ public:
/**
* These are the commands that can be sent to a DeviceHandlerBase
*/
static const uint8_t MESSAGE_ID = messagetypes::DEVICE_HANDLER_COMMAND;
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::DEVICE_HANDLER_COMMAND;
static const Command_t CMD_RAW = MAKE_COMMAND_ID( 1 ); //!< Sends a raw command, setParameter is a ::store_id_t containing the raw packet to send
// static const Command_t CMD_DIRECT = MAKE_COMMAND_ID( 2 ); //!< Sends a direct command, setParameter is a ::DeviceCommandId_t, setParameter2 is a ::store_id_t containing the data needed for the command
static const Command_t CMD_SWITCH_IOBOARD = MAKE_COMMAND_ID( 3 ); //!< Requests a IO-Board switch, setParameter() is the IO-Board identifier

View File

@@ -0,0 +1,20 @@
/**
* @file PollingSlot.cpp
* @brief This file defines the PollingSlot class.
* @date 19.12.2012
* @author baetz
*/
#include "FixedSequenceSlot.h"
#include "../objectmanager/SystemObjectIF.h"
#include <cstddef>
FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime,
int8_t setSequenceId, PeriodicTaskIF* executingTask) :
handler(NULL), pollingTimeMs(setTime), opcode(setSequenceId) {
handler = objectManager->get<ExecutableObjectIF>(handlerId);
handler->setTaskIF(executingTask);
}
FixedSequenceSlot::~FixedSequenceSlot() {}

View File

@@ -1,41 +1,41 @@
#ifndef FSFW_TASKS_FIXEDSEQUENCESLOT_H_
#define FSFW_TASKS_FIXEDSEQUENCESLOT_H_
/**
* @file FixedSequenceSlot.h
* @brief This file defines the PollingSlot class.
* @date 19.12.2012
* @author baetz
*/
#ifndef FIXEDSEQUENCESLOT_H_
#define FIXEDSEQUENCESLOT_H_
#include "ExecutableObjectIF.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../tasks/ExecutableObjectIF.h"
class PeriodicTaskIF;
/**
* @brief This class is the representation of a single polling sequence
* table entry.
* @details
* The PollingSlot class is the representation of a single polling
* sequence table entry.
* @author baetz
* @brief This class is the representation of a single polling sequence table entry.
*
* @details The PollingSlot class is the representation of a single polling
* sequence table entry.
*/
class FixedSequenceSlot {
public:
FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs,
int8_t setSequenceId, ExecutableObjectIF* executableObject,
PeriodicTaskIF* executingTask);
int8_t setSequenceId, PeriodicTaskIF* executingTask );
virtual ~FixedSequenceSlot();
object_id_t handlerId;
/**
* @brief Handler identifies which object is executed in this slot.
* @brief Handler identifies which device handler object is executed in this slot.
*/
ExecutableObjectIF* executableObject = nullptr;
ExecutableObjectIF* handler;
/**
* @brief This attribute defines when a device handler object is executed.
* @details
* The pollingTime attribute identifies the time the handler is
* executed in ms. It must be smaller than the period length of the
* polling sequence.
*
* @details The pollingTime attribute identifies the time the handler is executed in ms.
* It must be smaller than the period length of the polling sequence.
*/
uint32_t pollingTimeMs;
uint32_t pollingTimeMs;
/**
* @brief This value defines the type of device communication.
@@ -43,7 +43,7 @@ public:
* @details The state of this value decides what communication routine is
* called in the PST executable or the device handler object.
*/
uint8_t opcode;
uint8_t opcode;
/**
* @brief Operator overload for the comparison operator to
@@ -57,4 +57,4 @@ public:
};
#endif /* FSFW_TASKS_FIXEDSEQUENCESLOT_H_ */
#endif /* FIXEDSEQUENCESLOT_H_ */

View File

@@ -1,6 +1,5 @@
#include "FixedSlotSequence.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include <cstdlib>
FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) :
lengthMs(setLengthMs) {
@@ -13,7 +12,7 @@ FixedSlotSequence::~FixedSlotSequence() {
}
void FixedSlotSequence::executeAndAdvance() {
current->executableObject->performOperation(current->opcode);
current->handler->performOperation(current->opcode);
// if (returnValue != RETURN_OK) {
// this->sendErrorMessage( returnValue );
// }
@@ -81,82 +80,44 @@ uint32_t FixedSlotSequence::getLengthMs() const {
return this->lengthMs;
}
void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep, ExecutableObjectIF* executableObject,
PeriodicTaskIF* executingTask) {
this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs,
executionStep, executableObject, executingTask));
this->current = slotList.begin();
}
ReturnValue_t FixedSlotSequence::checkSequence() const {
if(slotList.empty()) {
sif::error << "FixedSlotSequence::checkSequence:"
<< " Slot list is empty!" << std::endl;
sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(customCheckFunction != nullptr) {
ReturnValue_t result = customCheckFunction(slotList);
if(result != HasReturnvaluesIF::RETURN_OK) {
// Continue for now but print error output.
sif::error << "FixedSlotSequence::checkSequence:"
<< " Custom check failed!" << std::endl;
}
}
uint32_t errorCount = 0;
auto slotIt = slotList.begin();
uint32_t count = 0;
uint32_t time = 0;
for(const auto& slot: slotList) {
if (slot.executableObject == nullptr) {
errorCount++;
}
else if (slot.pollingTimeMs < time) {
sif::error << "FixedSlotSequence::checkSequence: Time: "
<< slot.pollingTimeMs << " is smaller than previous with "
<< time << std::endl;
errorCount++;
}
else {
while (slotIt != slotList.end()) {
if (slotIt->handler == nullptr) {
sif::error << "FixedSlotSequene::initialize: ObjectId does not exist!"
<< std::endl;
count++;
} else if (slotIt->pollingTimeMs < time) {
sif::error << "FixedSlotSequence::initialize: Time: "
<< slotIt->pollingTimeMs
<< " is smaller than previous with " << time << std::endl;
count++;
} else {
// All ok, print slot.
//sif::info << "Current slot polling time: " << std::endl;
//sif::info << std::dec << slotIt->pollingTimeMs << std::endl;
//info << "Current slot polling time: " << std::endl;
//info << std::dec << slotIt->pollingTimeMs << std::endl;
}
time = slot.pollingTimeMs;
time = slotIt->pollingTimeMs;
slotIt++;
}
//sif::info << "Number of elements in slot list: "
//info << "Number of elements in slot list: "
// << slotList.size() << std::endl;
if (errorCount > 0) {
if (count > 0) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const {
std::set<ExecutableObjectIF*> uniqueObjects;
uint32_t count = 0;
for(const auto& slot: slotList) {
// Ensure that each unique object is initialized once.
if(uniqueObjects.find(slot.executableObject) == uniqueObjects.end()) {
ReturnValue_t result =
slot.executableObject->initializeAfterTaskCreation();
if(result != HasReturnvaluesIF::RETURN_OK) {
count++;
}
uniqueObjects.emplace(slot.executableObject);
}
}
if (count > 0) {
sif::error << "FixedSlotSequence::intializeSequenceAfterTaskCreation:"
"Counted " << count << " failed initializations!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
void FixedSlotSequence::addCustomCheck(ReturnValue_t
(*customCheckFunction)(const SlotList&)) {
this->customCheckFunction = customCheckFunction;
void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep, PeriodicTaskIF* executingTask) {
this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, executionStep,
executingTask));
this->current = slotList.begin();
}

View File

@@ -1,30 +1,26 @@
#ifndef FSFW_TASKS_FIXEDSLOTSEQUENCE_H_
#define FSFW_TASKS_FIXEDSLOTSEQUENCE_H_
#ifndef FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_
#define FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_
#include "FixedSequenceSlot.h"
#include "../objectmanager/SystemObject.h"
#include <set>
/**
* @brief This class is the representation of a
* Polling Sequence Table in software.
* @brief This class is the representation of a Polling Sequence Table in software.
*
* @details
* The FixedSlotSequence object maintains the dynamic execution of
* objects with stricter timing requirements for the FixedTimeslotTask.
* device handler objects.
*
* The main idea is to create a list of executable objects (for example
* device handlers), to announce all handlers to the polling sequence and to
* maintain a list of polling slot objects.
* This slot list represents the Polling Sequence Table in software.
* The main idea is to create a list of device handlers, to announce all
* handlers to thepolling sequence and to maintain a list of
* polling slot objects. This slot list represents the Polling Sequence Table
* in software.
*
* Each polling slot contains information to indicate when and
* which executable object shall be executed within a given polling period.
* When adding a slot, a pointer to the executing task, a pointer to the
* executable object and a step number can be passed. The step number will be
* passed to the periodic handler.
* The sequence is executed by iterating through the slot sequence and
* executing the executable object in the correct timeslot.
* which device handler shall be executed within a given polling period.
* The sequence is then executed by iterating through this slot list.
* Handlers are invoking by calling a certain function stored in the handler list.
*/
class FixedSlotSequence {
public:
@@ -33,44 +29,41 @@ public:
/**
* @brief The constructor of the FixedSlotSequence object.
*
* @details The constructor takes two arguments, the period length and the init function.
*
* @param setLength The period length, expressed in ms.
*/
FixedSlotSequence(uint32_t setLengthMs);
/**
* @brief The destructor of the FixedSlotSequence object.
* @details
* The destructor frees all allocated memory by iterating through the
* slotList and deleting all allocated resources.
*
* @details The destructor frees all allocated memory by iterating through the slotList
* and deleting all allocated resources.
*/
virtual ~FixedSlotSequence();
/**
* @brief This is a method to add an PollingSlot object to slotList.
*
* @details
* Here, a polling slot object is added to the slot list. It is appended
* to the end of the list. The list is currently NOT reordered.
* Afterwards, the iterator current is set to the beginning of the list.
* @param handlerId ID of the object to add
* @param setTime
* Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask
* will be called inside the slot period.
* @param setSequenceId
* ID which can be used to distinguish different task operations. This
* value will be passed to the executable function.
* @details Here, a polling slot object is added to the slot list. It is appended
* to the end of the list. The list is currently NOT reordered.
* Afterwards, the iterator current is set to the beginning of the list.
* @param Object ID of the object to add
* @param setTime Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask
* will be called inside the slot period.
* @param setSequenceId ID which can be used to distinguish
* different task operations
* @param
* @param
*/
void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId,
ExecutableObjectIF* executableObject,
PeriodicTaskIF* executingTask);
/**
* @brief Checks if the current slot shall be executed immediately
* after the one before.
* @details
* This allows to distinguish between grouped and separated handlers.
* Checks if the current slot shall be executed immediately after the one before.
* This allows to distinguish between grouped and not grouped handlers.
* @return - @c true if the slot has the same polling time as the previous
* - @c false else
*/
@@ -132,32 +125,12 @@ public:
SlotListIter current;
/**
* @brief Check and initialize slot list.
* @details
* Iterate through slotList and check successful creation.
* Checks if timing is ok (must be ascending) and if all handlers were found.
* @return
*/
ReturnValue_t checkSequence() const;
/**
* @brief A custom check can be injected for the respective slot list.
* @details
* This can be used by the developer to check the validity of a certain
* sequence. The function will be run in the #checkSequence function.
* The general check will be continued for now if the custom check function
* fails but a diagnostic debug output will be given.
* @param customCheckFunction
*/
void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList &));
/**
* @brief Perform any initialization steps required after the executing
* task has been created. This function should be called from the
* executing task!
* @return
*/
ReturnValue_t intializeSequenceAfterTaskCreation() const;
protected:
/**
@@ -173,9 +146,7 @@ protected:
*/
SlotList slotList;
ReturnValue_t (*customCheckFunction)(const SlotList&) = nullptr;
uint32_t lengthMs;
};
#endif /* FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ */
#endif /* FIXEDSLOTSEQUENCE_H_ */

View File

@@ -5,7 +5,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId,
MessageQueueId_t parentQueue) :
SystemObject(setObjectId), lastHealth(HEALTHY), parentQueue(
parentQueue), commandQueue(), healthHelper(this, setObjectId) {
commandQueue = QueueFactory::instance()->createMessageQueue(3);
commandQueue = QueueFactory::instance()->createMessageQueue(3, CommandMessage::COMMAND_MESSAGE_SIZE);
}
HealthDevice::~HealthDevice() {

View File

@@ -4,7 +4,6 @@
#include <stdint.h>
#include "fwSubsystemIdRanges.h"
//could be move to more suitable location
#include <events/subsystemIdRanges.h>
typedef uint16_t EventId_t;
typedef uint8_t EventSeverity_t;

View File

@@ -1,7 +1,5 @@
#include "EventManager.h"
#include "EventMessage.h"
#include <FSFWConfig.h>
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../ipc/QueueFactory.h"
#include "../ipc/MutexFactory.h"
@@ -10,18 +8,13 @@
const uint16_t EventManager::POOL_SIZES[N_POOLS] = {
sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher),
sizeof(ReporterRangeMatcher) };
// If one checks registerListener calls, there are around 40 (to max 50)
// objects registering for certain events.
// 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.
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = {
fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES ,
fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS,
fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS };
//If one checks registerListener calls, there are around 40 (to max 50) objects registering for certain events.
//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.
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 };
EventManager::EventManager(object_id_t setObjectId) :
SystemObject(setObjectId),
factoryBackend(0, POOL_SIZES, N_ELEMENTS, false, true) {
SystemObject(setObjectId), eventReportQueue(NULL), mutex(NULL), factoryBackend(
0, POOL_SIZES, N_ELEMENTS, false, true) {
mutex = MutexFactory::instance()->createMutex();
eventReportQueue = QueueFactory::instance()->createMessageQueue(
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE);
@@ -115,50 +108,46 @@ ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener,
#ifdef DEBUG
//forward declaration, should be implemented by mission
const char* translateObject(object_id_t object);
const char * translateEvents(Event event);
void EventManager::printEvent(EventMessage* message) {
const char *string = 0;
switch (message->getSeverity()) {
case SEVERITY::INFO:
#ifdef DEBUG_INFO_EVENT
string = translateObject(message->getReporter());
sif::info << "EVENT: ";
if (string != 0) {
sif::info << string;
} else {
sif::info << "0x" << std::hex << message->getReporter() << std::dec;
}
sif::info << " reported " << translateEvents(message->getEvent()) << " ("
<< std::dec << message->getEventId() << std::hex << ") P1: 0x"
<< message->getParameter1() << " P2: 0x"
<< message->getParameter2() << std::dec << std::endl;
#endif
// string = translateObject(message->getReporter());
// sif::info << "EVENT: ";
// if (string != 0) {
// sif::info << string;
// } else {
// sif::info << "0x" << std::hex << message->getReporter() << std::dec;
// }
// sif::info << " reported " << translateEvents(message->getEvent()) << " ("
// << std::dec << message->getEventId() << std::hex << ") P1: 0x"
// << message->getParameter1() << " P2: 0x"
// << message->getParameter2() << std::dec << std::endl;
break;
default:
string = translateObject(message->getReporter());
sif::debug << "EventManager: ";
sif::error << "EVENT: ";
if (string != 0) {
sif::debug << string;
sif::error << string;
} else {
sif::error << "0x" << std::hex << message->getReporter() << std::dec;
}
else {
sif::debug << "0x" << std::hex << message->getReporter() << std::dec;
}
sif::debug << " reported " << translateEvents(message->getEvent())
<< " (" << std::dec << message->getEventId() << ") "
<< std::endl;
sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1()
<< ", P1 Dec: " << std::dec << message->getParameter1()
<< std::endl;
sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2()
<< ", P2 Dec: " << std::dec << message->getParameter2()
<< std::endl;
sif::error << " reported " << translateEvents(message->getEvent()) << " ("
<< std::dec << message->getEventId() << std::hex << ") P1: 0x"
<< message->getParameter1() << " P2: 0x"
<< message->getParameter2() << std::dec << std::endl;
break;
}
}
#endif
void EventManager::lockMutex() {
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
}
void EventManager::unlockMutex() {

View File

@@ -10,12 +10,6 @@
#include "../ipc/MutexIF.h"
#include <map>
#ifdef DEBUG
// forward declaration, should be implemented by mission
extern const char* translateObject(object_id_t object);
extern const char* translateEvents(Event event);
#endif
class EventManager: public EventManagerIF,
public ExecutableObjectIF,
public SystemObject {
@@ -42,11 +36,11 @@ public:
ReturnValue_t performOperation(uint8_t opCode);
protected:
MessageQueueIF* eventReportQueue = nullptr;
MessageQueueIF* eventReportQueue;
std::map<MessageQueueId_t, EventMatchTree> listenerList;
MutexIF* mutex = nullptr;
MutexIF* mutex;
static const uint8_t N_POOLS = 3;
LocalPool<N_POOLS> factoryBackend;

View File

@@ -1,5 +1,5 @@
#ifndef FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
#define FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
#ifndef FRAMEWORK_EVENTS_FWSUBSYSTEMIDRANGES_H_
#define FRAMEWORK_EVENTS_FWSUBSYSTEMIDRANGES_H_
namespace SUBSYSTEM_ID {
enum {
@@ -19,12 +19,10 @@ enum {
SYSTEM_MANAGER_1 = 75,
SYSTEM_1 = 79,
PUS_SERVICE_1 = 80,
PUS_SERVICE_9 = 89,
PUS_SERVICE_17 = 97,
FW_SUBSYSTEM_ID_RANGE
};
}
#endif /* FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ */
#endif /* FRAMEWORK_EVENTS_FWSUBSYSTEMIDRANGES_H_ */

View File

@@ -5,12 +5,10 @@
#include "../ipc/QueueFactory.h"
#include "../objectmanager/ObjectManagerIF.h"
FailureIsolationBase::FailureIsolationBase(object_id_t owner,
object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) :
ownerId(owner), faultTreeParent(parent),
parameterDomainBase(parameterDomainBase) {
eventQueue = QueueFactory::instance()->createMessageQueue(messageDepth,
EventMessage::EVENT_MESSAGE_SIZE);
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) :
eventQueue(NULL), ownerId(
owner), owner(NULL), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
eventQueue = QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
}
FailureIsolationBase::~FailureIsolationBase() {
@@ -20,36 +18,27 @@ FailureIsolationBase::~FailureIsolationBase() {
ReturnValue_t FailureIsolationBase::initialize() {
EventManagerIF* manager = objectManager->get<EventManagerIF>(
objects::EVENT_MANAGER);
if (manager == nullptr) {
sif::error << "FailureIsolationBase::initialize: Event Manager has not"
" been initialized!" << std::endl;
if (manager == NULL) {
return RETURN_FAILED;
}
ReturnValue_t result = manager->registerListener(eventQueue->getId());
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if (ownerId != objects::NO_OBJECT) {
if (ownerId != 0) {
result = manager->subscribeToAllEventsFrom(eventQueue->getId(), ownerId);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
owner = objectManager->get<HasHealthIF>(ownerId);
if (owner == nullptr) {
sif::error << "FailureIsolationBase::intialize: Owner object "
"invalid. Make sure it implements HasHealthIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
if (owner == NULL) {
return RETURN_FAILED;
}
}
if (faultTreeParent != objects::NO_OBJECT) {
if (faultTreeParent != 0) {
ConfirmsFailuresIF* parentIF = objectManager->get<ConfirmsFailuresIF>(
faultTreeParent);
if (parentIF == nullptr) {
sif::error << "FailureIsolationBase::intialize: Parent object"
<< "invalid." << std::endl;
sif::error << "Make sure it implements ConfirmsFailuresIF."
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
if (parentIF == NULL) {
return RETURN_FAILED;
}
eventQueue->setDefaultDestination(parentIF->getEventReceptionQueue());
@@ -104,9 +93,9 @@ MessageQueueId_t FailureIsolationBase::getEventReceptionQueue() {
ReturnValue_t FailureIsolationBase::sendConfirmationRequest(EventMessage* event,
MessageQueueId_t destination) {
event->setMessageId(EventMessage::CONFIRMATION_REQUEST);
if (destination != MessageQueueIF::NO_QUEUE) {
if (destination != 0) {
return eventQueue->sendMessage(destination, event);
} else if (faultTreeParent != objects::NO_OBJECT) {
} else if (faultTreeParent != 0) {
return eventQueue->sendToDefault(event);
}
return RETURN_FAILED;

View File

@@ -17,25 +17,18 @@ public:
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, SEVERITY::INFO); //!< FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, SEVERITY::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, SEVERITY::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
FailureIsolationBase(object_id_t owner,
object_id_t parent = objects::NO_OBJECT,
FailureIsolationBase(object_id_t owner, object_id_t parent = 0,
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
virtual ~FailureIsolationBase();
virtual ReturnValue_t initialize();
/**
* This is called by the DHB in performOperation()
*/
void checkForFailures();
MessageQueueId_t getEventReceptionQueue() override;
MessageQueueId_t getEventReceptionQueue();
virtual void triggerEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0);
protected:
MessageQueueIF* eventQueue = nullptr;
MessageQueueIF* eventQueue;
object_id_t ownerId;
HasHealthIF* owner = nullptr;
HasHealthIF* owner;
object_id_t faultTreeParent;
uint8_t parameterDomainBase;
void setOwnerHealth(HasHealthIF::HealthState health);
@@ -45,7 +38,7 @@ protected:
virtual ReturnValue_t confirmFault(EventMessage* event);
virtual void decrementFaultCounters() = 0;
ReturnValue_t sendConfirmationRequest(EventMessage* event,
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
MessageQueueId_t destination = 0);
void throwFdirEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0);
private:

View File

@@ -1,4 +1,3 @@
# This submake file needs to be included by the primary Makefile.
# This file needs FRAMEWORK_PATH and OS_FSFW set correctly by another Makefile.
# Valid API settings: rtems, linux, freeRTOS, host
@@ -28,25 +27,12 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/*.cpp)
# select the OS
ifeq ($(OS_FSFW),rtems)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/rtems/*.cpp)
else ifeq ($(OS_FSFW),linux)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/linux/*.cpp)
else ifeq ($(OS_FSFW),freeRTOS)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/FreeRTOS/*.cpp)
else ifeq ($(OS_FSFW),host)
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
$(error invalid OS_FSFW specified, valid OS_FSFW are rtems, linux, freeRTOS, host)
endif

View File

@@ -1,124 +1,95 @@
#include "../globalfunctions/DleEncoder.h"
#include "DleEncoder.h"
DleEncoder::DleEncoder() {}
DleEncoder::DleEncoder() {
}
DleEncoder::~DleEncoder() {}
ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream,
size_t sourceLen, uint8_t* destStream, size_t maxDestLen,
size_t* encodedLen, bool addStxEtx) {
if (maxDestLen < 2) {
return STREAM_TOO_SHORT;
}
size_t encodedIndex = 0, sourceIndex = 0;
uint8_t nextByte;
if (addStxEtx) {
destStream[0] = STX_CHAR;
++encodedIndex;
}
while (encodedIndex < maxDestLen and sourceIndex < sourceLen)
{
nextByte = sourceStream[sourceIndex];
// STX, ETX and CR characters in the stream need to be escaped with DLE
if (nextByte == STX_CHAR or nextByte == ETX_CHAR or nextByte == CARRIAGE_RETURN) {
if (encodedIndex + 1 >= maxDestLen) {
return STREAM_TOO_SHORT;
}
else {
destStream[encodedIndex] = DLE_CHAR;
++encodedIndex;
/* Escaped byte will be actual byte + 0x40. This prevents
* STX, ETX, and carriage return characters from appearing
* in the encoded data stream at all, so when polling an
* encoded stream, the transmission can be stopped at ETX.
* 0x40 was chosen at random with special requirements:
* - Prevent going from one control char to another
* - Prevent overflow for common characters */
destStream[encodedIndex] = nextByte + 0x40;
}
}
// DLE characters are simply escaped with DLE.
else if (nextByte == DLE_CHAR) {
if (encodedIndex + 1 >= maxDestLen) {
return STREAM_TOO_SHORT;
}
else {
destStream[encodedIndex] = DLE_CHAR;
++encodedIndex;
destStream[encodedIndex] = DLE_CHAR;
}
}
else {
destStream[encodedIndex] = nextByte;
}
++encodedIndex;
++sourceIndex;
}
if (sourceIndex == sourceLen and encodedIndex < maxDestLen) {
if (addStxEtx) {
destStream[encodedIndex] = ETX_CHAR;
++encodedIndex;
}
*encodedLen = encodedIndex;
return RETURN_OK;
}
else {
return STREAM_TOO_SHORT;
}
DleEncoder::~DleEncoder() {
}
ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream,
size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
size_t maxDestStreamlen, size_t *decodedLen) {
size_t encodedIndex = 0, decodedIndex = 0;
uint32_t sourceStreamLen, uint32_t *readLen, uint8_t *destStream,
uint32_t maxDestStreamlen, uint32_t *decodedLen) {
uint32_t encodedIndex = 0, decodedIndex = 0;
uint8_t nextByte;
if (*sourceStream != STX_CHAR) {
return DECODING_ERROR;
if (*sourceStream != STX) {
return RETURN_FAILED;
}
++encodedIndex;
while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen)
&& (sourceStream[encodedIndex] != ETX_CHAR)
&& (sourceStream[encodedIndex] != STX_CHAR)) {
if (sourceStream[encodedIndex] == DLE_CHAR) {
&& (sourceStream[encodedIndex] != ETX)
&& (sourceStream[encodedIndex] != STX)) {
if (sourceStream[encodedIndex] == DLE) {
nextByte = sourceStream[encodedIndex + 1];
// The next byte is a DLE character that was escaped by another
// DLE character, so we can write it to the destination stream.
if (nextByte == DLE_CHAR) {
if (nextByte == 0x10) {
destStream[decodedIndex] = nextByte;
}
else {
/* The next byte is a STX, DTX or 0x0D character which
* was escaped by a DLE character. The actual byte was
* also encoded by adding + 0x40 to prevent having control chars,
* in the stream at all, so we convert it back. */
if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) {
} else {
if ((nextByte == 0x42) || (nextByte == 0x43)
|| (nextByte == 0x4D)) {
destStream[decodedIndex] = nextByte - 0x40;
}
else {
return DECODING_ERROR;
} else {
return RETURN_FAILED;
}
}
++encodedIndex;
}
else {
} else {
destStream[decodedIndex] = sourceStream[encodedIndex];
}
++encodedIndex;
++decodedIndex;
}
if (sourceStream[encodedIndex] != ETX_CHAR) {
*readLen = ++encodedIndex;
return DECODING_ERROR;
}
else {
if (sourceStream[encodedIndex] != ETX) {
return RETURN_FAILED;
} else {
*readLen = ++encodedIndex;
*decodedLen = decodedIndex;
return RETURN_OK;
}
}
ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream,
uint32_t sourceLen, uint8_t* destStream, uint32_t maxDestLen,
uint32_t* encodedLen, bool addStxEtx) {
if (maxDestLen < 2) {
return RETURN_FAILED;
}
uint32_t encodedIndex = 0, sourceIndex = 0;
uint8_t nextByte;
if (addStxEtx) {
destStream[0] = STX;
++encodedIndex;
}
while ((encodedIndex < maxDestLen) && (sourceIndex < sourceLen)) {
nextByte = sourceStream[sourceIndex];
if ((nextByte == STX) || (nextByte == ETX) || (nextByte == 0x0D)) {
if (encodedIndex + 1 >= maxDestLen) {
return RETURN_FAILED;
} else {
destStream[encodedIndex] = DLE;
++encodedIndex;
destStream[encodedIndex] = nextByte + 0x40;
}
} else if (nextByte == DLE) {
if (encodedIndex + 1 >= maxDestLen) {
return RETURN_FAILED;
} else {
destStream[encodedIndex] = DLE;
++encodedIndex;
destStream[encodedIndex] = DLE;
}
} else {
destStream[encodedIndex] = nextByte;
}
++encodedIndex;
++sourceIndex;
}
if ((sourceIndex == sourceLen) && (encodedIndex < maxDestLen)) {
if (addStxEtx) {
destStream[encodedIndex] = ETX;
++encodedIndex;
}
*encodedLen = encodedIndex;
return RETURN_OK;
} else {
return RETURN_FAILED;
}
}

View File

@@ -1,79 +1,25 @@
#ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
#define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
#ifndef DLEENCODER_H_
#define DLEENCODER_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
/**
* @brief This DLE Encoder (Data Link Encoder) can be used to encode and
* decode arbitrary data with ASCII control characters
* @details
* List of control codes:
* https://en.wikipedia.org/wiki/C0_and_C1_control_codes
*
* This encoder can be used to achieve a basic transport layer when using
* char based transmission systems.
* The passed source strean is converted into a encoded stream by adding
* a STX marker at the start of the stream and an ETX marker at the end of
* the stream. Any STX, ETX, DLE and CR occurrences in the source stream are
* escaped by a DLE character. The encoder also replaces escaped control chars
* by another char, so STX, ETX and CR should not appear anywhere in the actual
* encoded data stream.
*
* When using a strictly char based reception of packets encoded with DLE,
* STX can be used to notify a reader that actual data will start to arrive
* while ETX can be used to notify the reader that the data has ended.
*/
class DleEncoder: public HasReturnvaluesIF {
private:
DleEncoder();
virtual ~DleEncoder();
public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER;
static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01);
static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02);
static const uint8_t STX = 0x02;
static const uint8_t ETX = 0x03;
static const uint8_t DLE = 0x10;
//! Start Of Text character. First character is encoded stream
static constexpr uint8_t STX_CHAR = 0x02;
//! End Of Text character. Last character in encoded stream
static constexpr uint8_t ETX_CHAR = 0x03;
//! Data Link Escape character. Used to escape STX, ETX and DLE occurrences
//! in the source stream.
static constexpr uint8_t DLE_CHAR = 0x10;
static constexpr uint8_t CARRIAGE_RETURN = 0x0D;
/**
* Encodes the give data stream by preceding it with the STX marker
* and ending it with an ETX marker. STX, ETX and DLE characters inside
* the stream are escaped by DLE characters and also replaced by adding
* 0x40 (which is reverted in the decoding process).
* @param sourceStream
* @param sourceLen
* @param destStream
* @param maxDestLen
* @param encodedLen
* @param addStxEtx
* Adding STX and ETX can be omitted, if they are added manually.
* @return
*/
static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen,
uint8_t *destStream, size_t maxDestLen, size_t *encodedLen,
bool addStxEtx = true);
/**
* Converts an encoded stream back.
* @param sourceStream
* @param sourceStreamLen
* @param readLen
* @param destStream
* @param maxDestStreamlen
* @param decodedLen
* @return
*/
static ReturnValue_t decode(const uint8_t *sourceStream,
size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
size_t maxDestStreamlen, size_t *decodedLen);
uint32_t sourceStreamLen, uint32_t *readLen, uint8_t *destStream,
uint32_t maxDestStreamlen, uint32_t *decodedLen);
static ReturnValue_t encode(const uint8_t *sourceStream, uint32_t sourceLen,
uint8_t *destStream, uint32_t maxDestLen, uint32_t *encodedLen,
bool addStxEtx = true);
};
#endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */
#endif /* DLEENCODER_H_ */

View File

@@ -1,34 +0,0 @@
#include "PeriodicOperationDivider.h"
PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider,
bool resetAutomatically): resetAutomatically(resetAutomatically),
counter(divider), divider(divider) {
}
bool PeriodicOperationDivider::checkAndIncrement() {
if(counter >= divider) {
if(resetAutomatically) {
counter = 0;
}
return true;
}
counter ++;
return false;
}
void PeriodicOperationDivider::resetCounter() {
counter = 0;
}
void PeriodicOperationDivider::setDivider(uint32_t newDivider) {
divider = newDivider;
}
uint32_t PeriodicOperationDivider::getCounter() const {
return counter;
}
uint32_t PeriodicOperationDivider::getDivider() const {
return divider;
}

View File

@@ -1,55 +0,0 @@
#ifndef FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_
#define FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_
#include <cstdint>
/**
* @brief Lightweight helper class to facilitate periodic operation with
* decreased frequencies.
* @details
* This class is useful to perform operations which have to be performed
* with a reduced frequency, like debugging printouts in high periodic tasks
* or low priority operations.
*/
class PeriodicOperationDivider {
public:
/**
* Initialize with the desired divider and specify whether the internal
* counter will be reset automatically.
* @param divider
* @param resetAutomatically
*/
PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true);
/**
* Check whether operation is necessary.
* If an operation is necessary and the class has been
* configured to be reset automatically, the counter will be reset.
* If not, the counter will be incremented.
* @return
* -@c true if the counter is larger or equal to the divider
* -@c false otherwise
*/
bool checkAndIncrement();
/**
* Can be used to reset the counter to 0 manually.
*/
void resetCounter();
uint32_t getCounter() const;
/**
* Can be used to set a new divider value.
* @param newDivider
*/
void setDivider(uint32_t newDivider);
uint32_t getDivider() const;
private:
bool resetAutomatically = true;
uint32_t counter = 0;
uint32_t divider = 0;
};
#endif /* FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_ */

View File

@@ -90,10 +90,3 @@ double timevalOperations::toDouble(const timeval timeval) {
double result = timeval.tv_sec * 1000000. + timeval.tv_usec;
return result / 1000000.;
}
timeval timevalOperations::toTimeval(const double seconds) {
timeval tval;
tval.tv_sec = seconds;
tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6);
return tval;
}

View File

@@ -41,7 +41,6 @@ namespace timevalOperations {
* @return seconds
*/
double toDouble(const timeval timeval);
timeval toTimeval(const double seconds);
}
#endif /* TIMEVALOPERATIONS_H_ */

View File

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

View File

@@ -1,8 +1,9 @@
#include "HealthHelper.h"
#include "../ipc/MessageQueueSenderIF.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) :
objectId(objectId), owner(owner) {
healthTable(NULL), eventSender(NULL), objectId(objectId), parentQueue(
0), owner(owner) {
}
HealthHelper::~HealthHelper() {
@@ -39,19 +40,9 @@ void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) {
ReturnValue_t HealthHelper::initialize() {
healthTable = objectManager->get<HealthTableIF>(objects::HEALTH_TABLE);
eventSender = objectManager->get<EventReportingProxyIF>(objectId);
if (healthTable == nullptr) {
sif::error << "HealthHelper::initialize: Health table object needs"
"to be created in factory." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
if ((healthTable == NULL) || eventSender == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
if(eventSender == nullptr) {
sif::error << "HealthHelper::initialize: Owner has to implement "
"ReportingProxyIF." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
ReturnValue_t result = healthTable->registerObject(objectId,
HasHealthIF::HEALTHY);
if (result != HasReturnvaluesIF::RETURN_OK) {
@@ -71,22 +62,22 @@ void HealthHelper::setHealth(HasHealthIF::HealthState health) {
void HealthHelper::informParent(HasHealthIF::HealthState health,
HasHealthIF::HealthState oldHealth) {
if (parentQueue == MessageQueueIF::NO_QUEUE) {
if (parentQueue == 0) {
return;
}
CommandMessage information;
HealthMessage::setHealthMessage(&information, HealthMessage::HEALTH_INFO,
CommandMessage message;
HealthMessage::setHealthMessage(&message, HealthMessage::HEALTH_INFO,
health, oldHealth);
if (MessageQueueSenderIF::sendMessage(parentQueue, &information,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
if (MessageQueueSenderIF::sendMessage(parentQueue, &message,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
sif::debug << "HealthHelper::informParent: sending health reply failed."
<< std::endl;
}
}
void HealthHelper::handleSetHealthCommand(CommandMessage* command) {
ReturnValue_t result = owner->setHealth(HealthMessage::getHealth(command));
if (command->getSender() == MessageQueueIF::NO_QUEUE) {
void HealthHelper::handleSetHealthCommand(CommandMessage* message) {
ReturnValue_t result = owner->setHealth(HealthMessage::getHealth(message));
if (message->getSender() == 0) {
return;
}
CommandMessage reply;
@@ -94,12 +85,12 @@ void HealthHelper::handleSetHealthCommand(CommandMessage* command) {
HealthMessage::setHealthMessage(&reply,
HealthMessage::REPLY_HEALTH_SET);
} else {
reply.setReplyRejected(result, command->getCommand());
reply.setReplyRejected(result, message->getCommand());
}
if (MessageQueueSenderIF::sendMessage(command->getSender(), &reply,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
sif::debug << "HealthHelper::handleHealthCommand: sending health "
"reply failed." << std::endl;
if (MessageQueueSenderIF::sendMessage(message->getSender(), &reply,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
sif::debug
<< "HealthHelper::handleHealthCommand: sending health reply failed."
<< std::endl;
}
}

View File

@@ -1,26 +1,22 @@
#ifndef FSFW_HEALTH_HEALTHHELPER_H_
#define FSFW_HEALTH_HEALTHHELPER_H_
#include "HasHealthIF.h"
#include "HealthMessage.h"
#include "HealthTableIF.h"
#ifndef HEALTHHELPER_H_
#define HEALTHHELPER_H_
#include "../events/EventManagerIF.h"
#include "../events/EventReportingProxyIF.h"
#include "../ipc/MessageQueueIF.h"
#include "HasHealthIF.h"
#include "HealthMessage.h"
#include "HealthTableIF.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
/**
* @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.
* Helper class for Objects that implement HasHealthIF
*
* 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
* 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.
*
* 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.
*
* It does NOT handle @c HEALTH_INFO messages
@@ -29,9 +25,10 @@ class HealthHelper {
public:
/**
* @param owner
* @param objectId The object Id to use when communication with
* the HealthTable
* ctor
*
* @param objectId the object Id to use when communication with the HealthTable
* @param useAsFrom id to use as from id when sending replies, can be set to 0
*/
HealthHelper(HasHealthIF* owner, object_id_t objectId);
@@ -42,12 +39,12 @@ public:
*
* only valid after initialize() has been called
*/
HealthTableIF *healthTable = nullptr;
HealthTableIF *healthTable;
/**
* Proxy to forward events.
*/
EventReportingProxyIF* eventSender = nullptr;
EventReportingProxyIF* eventSender;
/**
* Try to handle the message.
@@ -57,9 +54,8 @@ public:
*
* @param message
* @return
* -@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_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)
*/
ReturnValue_t handleHealthCommand(CommandMessage *message);
@@ -80,19 +76,16 @@ public:
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);
/**
*
* @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
* -@c RETURN_OK if the Health Table was found and the object
* could be registered
* -@c RETURN_FAILED else
* -@c RETURN_OK if the Health Table was found and the object could be registered
* -@c RETURN_FAILED else
*/
ReturnValue_t initialize(MessageQueueId_t parentQueue );
@@ -107,7 +100,7 @@ private:
/**
* The Queue of the parent
*/
MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE;
MessageQueueId_t parentQueue;
/**
* The one using the healthHelper.
@@ -115,17 +108,13 @@ private:
HasHealthIF* owner;
/**
* if the #parentQueue is not NULL, a @c HEALTH_INFO message
* 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
* if the #parentQueue is not NULL, a @c HEALTH_INFO message 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.
*/
void informParent(HasHealthIF::HealthState health,
HasHealthIF::HealthState oldHealth);
void informParent(HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth);
void handleSetHealthCommand(CommandMessage *message);
};
#endif /* FSFW_HEALTH_HEALTHHELPER_H_ */
#endif /* HEALTHHELPER_H_ */

View File

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

View File

@@ -1,26 +1,20 @@
#ifndef FSFW_HEALTH_HEALTHMESSAGE_H_
#define FSFW_HEALTH_HEALTHMESSAGE_H_
#ifndef HEALTHMESSAGE_H_
#define HEALTHMESSAGE_H_
#include "HasHealthIF.h"
#include "../ipc/CommandMessage.h"
class HealthMessage {
public:
static const uint8_t MESSAGE_ID = messagetypes::HEALTH_COMMAND;
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 uint8_t MESSAGE_ID = MESSAGE_TYPE::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_INFO = MAKE_COMMAND_ID(5);
static const Command_t REPLY_HEALTH_SET = MAKE_COMMAND_ID(6);
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 HasHealthIF::HealthState getHealth(const CommandMessage *message);
@@ -33,4 +27,4 @@ private:
HealthMessage();
};
#endif /* FSFW_HEALTH_HEALTHMESSAGE_H_ */
#endif /* HEALTHMESSAGE_H_ */

View File

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

View File

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

View File

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

View File

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

View File

@@ -54,7 +54,7 @@ void InternalErrorReporter::lostTm() {
uint32_t InternalErrorReporter::getAndResetQueueHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
value = queueHits;
queueHits = 0;
mutex->unlockMutex();
@@ -63,21 +63,21 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() {
uint32_t InternalErrorReporter::getQueueHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
value = queueHits;
mutex->unlockMutex();
return value;
}
void InternalErrorReporter::incrementQueueHits() {
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
queueHits++;
mutex->unlockMutex();
}
uint32_t InternalErrorReporter::getAndResetTmHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
value = tmHits;
tmHits = 0;
mutex->unlockMutex();
@@ -86,14 +86,14 @@ uint32_t InternalErrorReporter::getAndResetTmHits() {
uint32_t InternalErrorReporter::getTmHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
value = tmHits;
mutex->unlockMutex();
return value;
}
void InternalErrorReporter::incrementTmHits() {
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
tmHits++;
mutex->unlockMutex();
}
@@ -104,7 +104,7 @@ void InternalErrorReporter::storeFull() {
uint32_t InternalErrorReporter::getAndResetStoreHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
value = storeHits;
storeHits = 0;
mutex->unlockMutex();
@@ -113,14 +113,14 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() {
uint32_t InternalErrorReporter::getStoreHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
value = storeHits;
mutex->unlockMutex();
return value;
}
void InternalErrorReporter::incrementStoreHits() {
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::NO_TIMEOUT);
storeHits++;
mutex->unlockMutex();
}

View File

@@ -1,96 +1,124 @@
/**
* @file CommandMessage.cpp
* @brief This file defines the CommandMessage class.
* @date 20.06.2013
* @author baetz
*/
#include "../devicehandlers/DeviceHandlerMessage.h"
#include "../health/HealthMessage.h"
#include "CommandMessage.h"
#include "CommandMessageCleaner.h"
#include <cstring>
#include "../memory/MemoryMessage.h"
#include "../modes/ModeMessage.h"
#include "../monitoring/MonitoringMessage.h"
#include "../subsystem/modes/ModeSequenceMessage.h"
#include "../tmstorage/TmStoreMessage.h"
#include "../parameters/ParameterMessage.h"
namespace MESSAGE_TYPE {
void clearMissionMessage(CommandMessage* message);
}
CommandMessage::CommandMessage() {
MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE);
setCommand(CMD_NONE);
this->messageSize = COMMAND_MESSAGE_SIZE;
setCommand(CMD_NONE);
}
CommandMessage::CommandMessage(Command_t command, uint32_t parameter1,
uint32_t parameter2) {
MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE);
setCommand(command);
setParameter(parameter1);
setParameter2(parameter2);
uint32_t parameter2) {
this->messageSize = COMMAND_MESSAGE_SIZE;
setCommand(command);
setParameter(parameter1);
setParameter2(parameter2);
}
Command_t CommandMessage::getCommand() const {
Command_t command;
std::memcpy(&command, MessageQueueMessage::getData(), sizeof(Command_t));
return command;
Command_t command;
memcpy(&command, getData(), sizeof(Command_t));
return command;
}
void CommandMessage::setCommand(Command_t command) {
std::memcpy(MessageQueueMessage::getData(), &command, sizeof(Command_t));
}
uint8_t CommandMessage::getMessageType() const {
// first byte of command ID.
return getCommand() >> 8 & 0xff;
memcpy(getData(), &command, sizeof(command));
}
uint32_t CommandMessage::getParameter() const {
uint32_t parameter1;
std::memcpy(&parameter1, this->getData(), sizeof(parameter1));
return parameter1;
uint32_t parameter1;
memcpy(&parameter1, getData() + sizeof(Command_t), sizeof(parameter1));
return parameter1;
}
void CommandMessage::setParameter(uint32_t parameter1) {
std::memcpy(this->getData(), &parameter1, sizeof(parameter1));
memcpy(getData() + sizeof(Command_t), &parameter1, sizeof(parameter1));
}
uint32_t CommandMessage::getParameter2() const {
uint32_t parameter2;
std::memcpy(&parameter2, this->getData() + sizeof(uint32_t),
sizeof(parameter2));
return parameter2;
uint32_t parameter2;
memcpy(&parameter2, getData() + sizeof(Command_t) + sizeof(uint32_t),
sizeof(parameter2));
return parameter2;
}
void CommandMessage::setParameter2(uint32_t parameter2) {
std::memcpy(this->getData() + sizeof(uint32_t), &parameter2,
sizeof(parameter2));
}
uint32_t CommandMessage::getParameter3() const {
uint32_t parameter3;
std::memcpy(&parameter3, this->getData() + 2 * sizeof(uint32_t),
sizeof(parameter3));
return parameter3;
}
void CommandMessage::setParameter3(uint32_t parameter3) {
std::memcpy(this->getData() + 2 * sizeof(uint32_t), &parameter3,
sizeof(parameter3));
}
size_t CommandMessage::getMinimumMessageSize() const {
return MINIMUM_COMMAND_MESSAGE_SIZE;
memcpy(getData() + sizeof(Command_t) + sizeof(uint32_t), &parameter2,
sizeof(parameter2));
}
void CommandMessage::clearCommandMessage() {
clear();
}
void CommandMessage::clear() {
CommandMessageCleaner::clearCommandMessage(this);
switch((getCommand()>>8) & 0xff){
case MESSAGE_TYPE::MODE_COMMAND:
ModeMessage::clear(this);
break;
case MESSAGE_TYPE::HEALTH_COMMAND:
HealthMessage::clear(this);
break;
case MESSAGE_TYPE::MODE_SEQUENCE:
ModeSequenceMessage::clear(this);
break;
case MESSAGE_TYPE::ACTION:
ActionMessage::clear(this);
break;
case MESSAGE_TYPE::DEVICE_HANDLER_COMMAND:
DeviceHandlerMessage::clear(this);
break;
case MESSAGE_TYPE::MEMORY:
MemoryMessage::clear(this);
break;
case MESSAGE_TYPE::MONITORING:
MonitoringMessage::clear(this);
break;
case MESSAGE_TYPE::TM_STORE:
TmStoreMessage::clear(this);
break;
case MESSAGE_TYPE::PARAMETER:
ParameterMessage::clear(this);
break;
default:
MESSAGE_TYPE::clearMissionMessage(this);
break;
}
}
bool CommandMessage::isClearedCommandMessage() {
return getCommand() == CMD_NONE;
return getCommand() == CMD_NONE;
}
size_t CommandMessage::getMinimumMessageSize() const {
return COMMAND_MESSAGE_SIZE;
}
void CommandMessage::setToUnknownCommand() {
Command_t initialCommand = getCommand();
this->clear();
setReplyRejected(UNKNOWN_COMMAND, initialCommand);
Command_t initialCommand = getCommand();
clearCommandMessage();
setReplyRejected(UNKNOWN_COMMAND, initialCommand);
}
void CommandMessage::setReplyRejected(ReturnValue_t reason,
Command_t initialCommand) {
Command_t initialCommand) {
setCommand(REPLY_REJECTED);
setParameter(reason);
setParameter2(initialCommand);
setParameter(reason);
setParameter2(initialCommand);
}
ReturnValue_t CommandMessage::getReplyRejectedReason(
@@ -101,11 +129,3 @@ ReturnValue_t CommandMessage::getReplyRejectedReason(
}
return reason;
}
uint8_t* CommandMessage::getData() {
return MessageQueueMessage::getData() + sizeof(Command_t);
}
const uint8_t* CommandMessage::getData() const {
return MessageQueueMessage::getData() + sizeof(Command_t);
}

View File

@@ -1,88 +1,114 @@
#ifndef FSFW_IPC_COMMANDMESSAGE_H_
#define FSFW_IPC_COMMANDMESSAGE_H_
/**
* @file CommandMessage.h
* @brief This file defines the CommandMessage class.
* @date 20.06.2013
* @author baetz
*/
#include "CommandMessageIF.h"
#ifndef COMMANDMESSAGE_H_
#define COMMANDMESSAGE_H_
#include "FwMessageTypes.h"
#include <config/ipc/MissionMessageTypes.h>
#include "MessageQueueMessage.h"
#include "FwMessageTypes.h"
/**
* @brief Default command message used to pass command messages between tasks.
* Primary message type for IPC. Contains sender, 2-byte command ID
* field, and 3 4-byte parameter
* @details
* It operates on an external memory which is contained inside a
* class implementing MessageQueueMessageIF by taking its address.
* This allows for a more flexible designs of message implementations.
* The pointer can be passed to different message implementations without
* the need of unnecessary copying.
*
* The command message is based of the generic MessageQueueMessage which
* currently has an internal message size of 28 bytes.
* @author Bastian Baetz
*/
class CommandMessage: public MessageQueueMessage, public CommandMessageIF {
#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number))
typedef ReturnValue_t Command_t;
class CommandMessage : public MessageQueueMessage {
public:
/**
* Default size can accomodate 3 4-byte parameters.
*/
static constexpr size_t DEFAULT_COMMAND_MESSAGE_SIZE =
CommandMessageIF::MINIMUM_COMMAND_MESSAGE_SIZE +
3 * sizeof(uint32_t);
static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE;
static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01);
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::COMMAND;
static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 );//!< Used internally, will be ignored
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 3 );
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 0xD1 );//!< Reply indicating that the current command was rejected, par1 should contain the error code
/**
* @brief Default Constructor, does not initialize anything.
* @details
* This constructor should be used when receiving a Message, as the
* content is filled by the MessageQueue.
* This is the size of a message as it is seen by the MessageQueue
*/
static const size_t COMMAND_MESSAGE_SIZE = HEADER_SIZE
+ sizeof(Command_t) + 2 * sizeof(uint32_t);
/**
* Default Constructor, does not initialize anything.
*
* This constructor should be used when receiving a Message, as the content is filled by the MessageQueue.
*/
CommandMessage();
/**
* This constructor creates a new message with all message content
* initialized
* This constructor creates a new message with all message content initialized
*
* @param command The DeviceHandlerCommand_t that will be sent
* @param parameter1 The first parameter
* @param parameter2 The second parameter
*/
CommandMessage(Command_t command, uint32_t parameter1, uint32_t parameter2);
CommandMessage(Command_t command,
uint32_t parameter1, uint32_t parameter2);
/**
* @brief Default Destructor
* Default Destructor
*/
virtual ~CommandMessage() {}
virtual ~CommandMessage() {
}
/**
* Read the DeviceHandlerCommand_t that is stored in the message,
* usually used after receiving.
*
* @return the Command stored in the Message
*/
virtual Command_t getCommand() const override;
/**
* Set the command type of the message. Default implementation also
* sets the message type, which will be the first byte of the command ID.
* @param the Command to be sent
*/
virtual void setCommand(Command_t command);
/**
* Read the DeviceHandlerCommand_t that is stored in the message, usually used after receiving
*
* @return the Command stored in the Message
*/
Command_t getCommand() const;
virtual uint8_t* getData() override;
virtual const uint8_t* getData() const override;
/**
* Set the DeviceHandlerCOmmand_t of the message
*
* @param the Command to be sent
*/
void setCommand(Command_t command);
/**
* Get the first parameter of the message
*
* @return the first Parameter of the message
*/
uint32_t getParameter() const;
/**
* Set the first parameter of the message
*
* @param the first parameter of the message
*/
void setParameter(uint32_t parameter1);
/**
* Get the second parameter of the message
*
* @return the second Parameter of the message
*/
uint32_t getParameter2() const;
/**
* Set the second parameter of the message
*
* @param the second parameter of the message
*/
void setParameter2(uint32_t parameter2);
uint32_t getParameter3() const;
void setParameter3(uint32_t parameter3);
/**
* Set the command to CMD_NONE and try to find
* the correct class to handle a more detailed
* clear.
* Also, calls a mission-specific clearMissionMessage
* function to separate between framework and mission
* messages. Not optimal, may be replaced by totally
* different auto-delete solution (e.g. smart pointers).
*
*/
void clearCommandMessage();
/**
* check if a message was cleared
@@ -91,41 +117,18 @@ public:
*/
bool isClearedCommandMessage();
/**
* Sets the command to REPLY_REJECTED with parameter UNKNOWN_COMMAND.
* Is needed quite often, so we better code it once only.
*/
void setToUnknownCommand() override;
void setToUnknownCommand();
void setReplyRejected(ReturnValue_t reason, Command_t initialCommand = CMD_NONE);
ReturnValue_t getReplyRejectedReason(
Command_t *initialCommand = nullptr) const;
/**
* A command message can be rejected and needs to offer a function
* to set a rejected reply
* @param reason
* @param initialCommand
*/
void setReplyRejected(ReturnValue_t reason,
Command_t initialCommand) override;
/**
* Corrensonding getter function.
* @param initialCommand
* @return
*/
ReturnValue_t getReplyRejectedReason(
Command_t* initialCommand = nullptr) const override;
virtual void clear() override;
void clearCommandMessage();
/**
* Extract message ID, which is the first byte of the command ID for the
* default implementation.
* @return
*/
virtual uint8_t getMessageType() const override;
/** MessageQueueMessageIF functions used for minimum size check. */
size_t getMinimumMessageSize() const override;
size_t getMinimumMessageSize() const;
};
#endif /* FSFW_IPC_COMMANDMESSAGE_H_ */
#endif /* COMMANDMESSAGE_H_ */

View File

@@ -1,45 +0,0 @@
#include "../ipc/CommandMessageCleaner.h"
#include "../devicehandlers/DeviceHandlerMessage.h"
#include "../health/HealthMessage.h"
#include "../memory/MemoryMessage.h"
#include "../modes/ModeMessage.h"
#include "../monitoring/MonitoringMessage.h"
#include "../subsystem/modes/ModeSequenceMessage.h"
#include "../tmstorage/TmStoreMessage.h"
#include "../parameters/ParameterMessage.h"
void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) {
switch(message->getMessageType()){
case messagetypes::MODE_COMMAND:
ModeMessage::clear(message);
break;
case messagetypes::HEALTH_COMMAND:
HealthMessage::clear(message);
break;
case messagetypes::MODE_SEQUENCE:
ModeSequenceMessage::clear(message);
break;
case messagetypes::ACTION:
ActionMessage::clear(message);
break;
case messagetypes::DEVICE_HANDLER_COMMAND:
DeviceHandlerMessage::clear(message);
break;
case messagetypes::MEMORY:
MemoryMessage::clear(message);
break;
case messagetypes::MONITORING:
MonitoringMessage::clear(message);
break;
case messagetypes::TM_STORE:
TmStoreMessage::clear(message);
break;
case messagetypes::PARAMETER:
ParameterMessage::clear(message);
break;
default:
messagetypes::clearMissionMessage(message);
break;
}
}

View File

@@ -1,16 +0,0 @@
#ifndef FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_
#define FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_
#include "../ipc/CommandMessage.h"
namespace messagetypes {
// Implemented in config.
void clearMissionMessage(CommandMessage* message);
}
class CommandMessageCleaner {
public:
static void clearCommandMessage(CommandMessage* message);
};
#endif /* FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ */

View File

@@ -1,73 +0,0 @@
#ifndef FSFW_IPC_COMMANDMESSAGEIF_H_
#define FSFW_IPC_COMMANDMESSAGEIF_H_
#include "MessageQueueMessageIF.h"
#include "FwMessageTypes.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number))
typedef uint16_t Command_t;
class CommandMessageIF {
public:
/**
* Header consists of sender ID and command ID.
*/
static constexpr size_t HEADER_SIZE = MessageQueueMessageIF::HEADER_SIZE +
sizeof(Command_t);
/**
* This minimum size is derived from the interface requirement to be able
* to set a rejected reply, which contains a returnvalue and the initial
* command.
*/
static constexpr size_t MINIMUM_COMMAND_MESSAGE_SIZE =
CommandMessageIF::HEADER_SIZE + sizeof(ReturnValue_t) +
sizeof(Command_t);
static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE;
static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01);
static const uint8_t MESSAGE_ID = messagetypes::COMMAND;
//! Used internally, shall be ignored
static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 );
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 1 );
//! Reply indicating that the current command was rejected,
//! par1 should contain the error code
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 2 );
virtual ~CommandMessageIF() {};
/**
* A command message shall have a uint16_t command ID field.
* @return
*/
virtual Command_t getCommand() const = 0;
/**
* A command message shall have a uint8_t message type ID field.
* @return
*/
virtual uint8_t getMessageType() const = 0;
/**
* A command message can be rejected and needs to offer a function
* to set a rejected reply
* @param reason
* @param initialCommand
*/
virtual void setReplyRejected(ReturnValue_t reason,
Command_t initialCommand) = 0;
/**
* Corrensonding getter function.
* @param initialCommand
* @return
*/
virtual ReturnValue_t getReplyRejectedReason(
Command_t* initialCommand = nullptr) const = 0;
virtual void setToUnknownCommand() = 0;
virtual void clear() = 0;
};
#endif /* FSFW_IPC_COMMANDMESSAGEIF_H_ */

View File

@@ -1,7 +1,7 @@
#ifndef FRAMEWORK_IPC_FWMESSAGETYPES_H_
#define FRAMEWORK_IPC_FWMESSAGETYPES_H_
namespace messagetypes {
namespace MESSAGE_TYPE {
//Remember to add new Message Types to the clearCommandMessage function!
enum FW_MESSAGE_TYPE {
COMMAND = 0,

View File

@@ -1,77 +1,61 @@
#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_
#define FSFW_IPC_MESSAGEQUEUEIF_H_
#include "messageQueueDefinitions.h"
#include "MessageQueueMessageIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstdint>
#ifndef FRAMEWORK_IPC_MESSAGEQUEUEIF_H_
#define FRAMEWORK_IPC_MESSAGEQUEUEIF_H_
// 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
*/
#include "MessageQueueMessage.h"
#include "MessageQueueSenderIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
class MessageQueueIF {
public:
static const MessageQueueId_t NO_QUEUE = 0;
static const MessageQueueId_t NO_QUEUE = MessageQueueSenderIF::NO_QUEUE; //!< Ugly hack.
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);
//! No space left for more messages
/**
* No space left for more messages
*/
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);
//! Returned if the target destination is invalid.
static constexpr ReturnValue_t DESTINVATION_INVALID = MAKE_RETURN_CODE(4);
virtual ~MessageQueueIF() {}
/**
* @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.
* @return
* -@c RETURN_OK if ok
* -@c NO_REPLY_PARTNER Should return NO_REPLY_PARTNER if partner was found.
* @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.
* \return RETURN_OK if ok
* \return NO_REPLY_PARTNER Should return NO_REPLY_PARTNER if partner was found
*/
virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0;
virtual ReturnValue_t reply( MessageQueueMessage* message ) = 0;
/**
* @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.
* @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.
*/
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
virtual ReturnValue_t receiveMessage(MessageQueueMessage* message,
MessageQueueId_t *receivedFrom) = 0;
/**
* @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 original content is overwritten and the sendFrom
* information is stored in theblastPartner attribute. Else, the lastPartner
* 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
* @details If data is available it is stored in the passed message pointer. The message's
* original content is overwritten and the sendFrom information is stored in the
* lastPartner attribute. Else, the lastPartner 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.
*/
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0;
virtual ReturnValue_t receiveMessage(MessageQueueMessage* message) = 0;
/**
* Deletes all pending messages in the queue.
* @param count The number of flushed messages.
@@ -79,89 +63,57 @@ public:
*/
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;
/**
* @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;
/**
* @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 it on to the destination provided with an operating system
* call. The OS's returnvalue 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 (if implemented).
* @return -@c RETURN_OK on success
* -@c MessageQueueIF::FULL if queue is full
* \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
* 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 (if implemented).
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault = false ) = 0;
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0;
/**
* @brief This operation sends a message to the given destination.
* @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 This operation sends a message to the given destination.
* @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.
* \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.
*/
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;
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0;
/**
* @brief This operation sends a message to the default destination.
* @details
* As in the sendMessage method, this function uses the sendToDefault
* call of the Implementation class and adds its queue id as
* "sentFrom" information.
* @details 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.
* @return -@c RETURN_OK on success
* -@c MessageQueueIF::FULL if queue is full
*/
virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ) = 0;
virtual ReturnValue_t sendToDefault( MessageQueueMessage* 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;
/**
* @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;
@@ -170,4 +122,4 @@ public:
#endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */
#endif /* FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ */

View File

@@ -1,27 +1,13 @@
#include "MessageQueueMessage.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../globalfunctions/arrayprinter.h"
#include <cstring>
#include <string.h>
MessageQueueMessage::MessageQueueMessage() :
messageSize(getMinimumMessageSize()) {
messageSize(this->HEADER_SIZE) {
memset(this->internalBuffer, 0, sizeof(this->internalBuffer));
}
MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) :
messageSize(this->HEADER_SIZE + size) {
if (size <= this->MAX_DATA_SIZE) {
memcpy(this->getData(), data, size);
this->messageSize = this->HEADER_SIZE + size;
}
else {
sif::warning << "MessageQueueMessage: Passed size larger than maximum"
"allowed size! Setting content to 0" << std::endl;
memset(this->internalBuffer, 0, sizeof(this->internalBuffer));
this->messageSize = this->HEADER_SIZE;
}
}
MessageQueueMessage::~MessageQueueMessage() {
}
@@ -51,34 +37,29 @@ void MessageQueueMessage::setSender(MessageQueueId_t setId) {
memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t));
}
void MessageQueueMessage::print(bool printWholeMessage) {
sif::debug << "MessageQueueMessage content: " << std::endl;
if(printWholeMessage) {
arrayprinter::print(getData(), getMaximumMessageSize());
}
else {
arrayprinter::print(getData(), getMessageSize());
MessageQueueMessage::MessageQueueMessage(uint8_t* data, uint32_t size) :
messageSize(this->HEADER_SIZE + size) {
if (size <= this->MAX_DATA_SIZE) {
memcpy(this->getData(), data, size);
} else {
memset(this->internalBuffer, 0, sizeof(this->internalBuffer));
this->messageSize = this->HEADER_SIZE;
}
}
size_t MessageQueueMessage::getMinimumMessageSize() {
return this->HEADER_SIZE;
}
void MessageQueueMessage::print() {
sif::debug << "MessageQueueMessage has size: " << this->messageSize << std::hex
<< std::endl;
for (uint8_t count = 0; count < this->messageSize; count++) {
sif::debug << (uint32_t) this->internalBuffer[count] << ":";
}
sif::debug << std::dec << std::endl;
}
void MessageQueueMessage::clear() {
memset(this->getBuffer(), 0, this->MAX_MESSAGE_SIZE);
}
size_t MessageQueueMessage::getMessageSize() const {
return this->messageSize;
}
void MessageQueueMessage::setMessageSize(size_t messageSize) {
this->messageSize = messageSize;
}
size_t MessageQueueMessage::getMinimumMessageSize() const {
return this->MIN_MESSAGE_SIZE;
}
size_t MessageQueueMessage::getMaximumMessageSize() const {
return this->MAX_MESSAGE_SIZE;
}

View File

@@ -1,149 +1,118 @@
#ifndef FSFW_IPC_MESSAGEQUEUEMESSAGE_H_
#define FSFW_IPC_MESSAGEQUEUEMESSAGE_H_
#ifndef MESSAGEQUEUEMESSAGE_H_
#define MESSAGEQUEUEMESSAGE_H_
#include "../ipc/MessageQueueMessageIF.h"
#include <cstddef>
#include "MessageQueueSenderIF.h"
#include <stddef.h>
/**
* @brief This class is the representation and data organizer
* for interprocess messages.
* @details
* To facilitate and standardize interprocess communication, this class was
* created to handle a lightweight "interprocess message protocol".
* \brief This class is the representation and data organizer for interprocess messages.
*
* It adds a header with the sender's queue id to every sent message and
* defines the maximum total message size. Specialized messages, such as
* device commanding messages, can be created by inheriting from this class
* and filling the buffer provided by getData with additional content.
*
* If larger amounts of data must be sent between processes, the data shall
* be stored in the IPC Store object and only the storage id is passed in a
* queue message.The class is used both to generate and send messages and to
* receive messages from other tasks.
* @ingroup message_queue
* \details To facilitate and standardize interprocess communication, this class was created
* to handle a lightweight "interprocess message protocol". It adds a header with the
* sender's queue id to every sent message and defines the maximum total message size.
* Specialized messages, such as device commanding messages, can be created by inheriting
* from this class and filling the buffer provided by getData with additional content.
* If larger amounts of data must be sent between processes, the data shall be stored in
* the IPC Store object and only the storage id is passed in a queue message.
* The class is used both to generate and send messages and to receive messages from
* other tasks.
* \ingroup message_queue
*/
class MessageQueueMessage: public MessageQueueMessageIF {
class MessageQueueMessage {
public:
/**
* @brief The class is initialized empty with this constructor.
* @details
* The messageSize attribute is set to the header's size and the whole
* content is set to zero.
*/
MessageQueueMessage();
/**
* @brief With this constructor the class is initialized with
* the given content.
* @details
* If the passed message size fits into the buffer, the passed data is
* copied to the internal buffer and the messageSize information is set.
* Otherwise, messageSize is set to the header's size and the whole
* content is set to zero.
* @param data The data to be put in the message.
* @param size Size of the data to be copied. Must be smaller than
* MAX_MESSAGE_SIZE and larger than MIN_MESSAGE_SIZE.
*/
MessageQueueMessage(uint8_t* data, size_t size);
/**
* @brief As no memory is allocated in this class,
* the destructor is empty.
*/
virtual ~MessageQueueMessage();
/**
* @brief The size information of each message is stored in
* this attribute.
* @details
* It is public to simplify usage and to allow for passing the size
* address as a pointer. Care must be taken when inheriting from this class,
* as every child class is responsible for managing the size information by
* itself. When using the class to receive a message, the size information
* is updated automatically.
*
* Please note that the minimum size is limited by the size of the header
* while the maximum size is limited by the maximum allowed message size.
*/
size_t messageSize;
/**
* @brief This constant defines the maximum size of the data content,
* excluding the header.
* @details
* It may be changed if necessary, but in general should be kept
* as small as possible.
* \brief This constant defines the maximum size of the data content, excluding the header.
* \details It may be changed if necessary, but in general should be kept as small as possible.
*/
static const size_t MAX_DATA_SIZE = 24;
/**
* @brief This constant defines the maximum total size in bytes
* of a sent message.
* @details
* It is the sum of the maximum data and the header size. Be aware that
* this constant is used to define the buffer sizes for every message
* queue in the system. So, a change here may have significant impact on
* the required resources.
* \brief This constants defines the size of the header, which is added to every message.
*/
static constexpr size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE;
static const size_t HEADER_SIZE = sizeof(MessageQueueId_t);
/**
* @brief Defines the minimum size of a message where only the
* header is included
* \brief This constant defines the maximum total size in bytes of a sent message.
* \details It is the sum of the maximum data and the header size. Be aware that this constant
* is used to define the buffer sizes for every message queue in the system. So, a change
* here may have significant impact on the required resources.
*/
static constexpr size_t MIN_MESSAGE_SIZE = HEADER_SIZE;
static const size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE;
private:
/**
* @brief This is the internal buffer that contains the
* actual message data.
* \brief This is the internal buffer that contains the actual message data.
*/
uint8_t internalBuffer[MAX_MESSAGE_SIZE];
public:
/**
* @brief This method is used to get the complete data of the message.
* \brief The size information of each message is stored in this attribute.
* \details It is public to simplify usage and to allow for passing the variable's address as a
* pointer. Care must be taken when inheriting from this class, as every child class is
* responsible for managing the size information by itself. When using the class to
* receive a message, the size information is updated automatically.
*/
const uint8_t* getBuffer() const override;
size_t messageSize;
/**
* @brief This method is used to get the complete data of the message.
* \brief The class is initialized empty with this constructor.
* \details The messageSize attribute is set to the header's size and the whole content is set to
* zero.
*/
uint8_t* getBuffer() override;
MessageQueueMessage();
/**
* @brief This method is used to fetch the data content of the message.
* @details
* It shall be used by child classes to add data at the right position.
* \brief With this constructor the class is initialized with the given content.
* \details If the passed message size fits into the buffer, the passed data is copied to the
* internal buffer and the messageSize information is set. Otherwise, messageSize
* is set to the header's size and the whole content is set to zero.
* \param data The data to be put in the message.
* \param size Size of the data to be copied. Must be smaller than MAX_MESSAGE_SIZE.
*/
const uint8_t* getData() const override;
MessageQueueMessage(uint8_t* data, uint32_t size);
/**
* @brief This method is used to fetch the data content of the message.
* @details
* It shall be used by child classes to add data at the right position.
* \brief As no memory is allocated in this class, the destructor is empty.
*/
uint8_t* getData() override;
virtual ~MessageQueueMessage();
/**
* @brief This method is used to extract the sender's message
* queue id information from a received message.
* \brief This method is used to get the complete data of the message.
*/
MessageQueueId_t getSender() const override;
const uint8_t* getBuffer() const;
/**
* @brief With this method, the whole content
* and the message size is set to zero.
* \brief This method is used to get the complete data of the message.
*/
void clear() override;
uint8_t* getBuffer();
/**
* @brief This method is used to set the sender's message queue id
* information prior to ing the message.
* @param setId
* The message queue id that identifies the sending message queue.
* \brief This method is used to fetch the data content of the message.
* \details It shall be used by child classes to add data at the right position.
*/
void setSender(MessageQueueId_t setId) override;
virtual size_t getMessageSize() const override;
virtual void setMessageSize(size_t messageSize) override;
virtual size_t getMinimumMessageSize() const override;
virtual size_t getMaximumMessageSize() const override;
const uint8_t* getData() const;
/**
* @brief This is a debug method that prints the content.
* \brief This method is used to fetch the data content of the message.
* \details It shall be used by child classes to add data at the right position.
*/
void print(bool printWholeMessage);
uint8_t* getData();
/**
* \brief This method is used to extract the sender's message queue id information from a
* received message.
*/
MessageQueueId_t getSender() const;
/**
* \brief With this method, the whole content and the message size is set to zero.
*/
void clear();
/**
* \brief This is a debug method that prints the content (till messageSize) to the debug output.
*/
void print();
/**
* \brief This method is used to set the sender's message queue id information prior to
* sending the message.
* \param setId The message queue id that identifies the sending message queue.
*/
void setSender(MessageQueueId_t setId);
/**
* \brief This helper function is used by the MessageQueue class to check the size of an
* incoming message.
* \details The method must be overwritten by child classes if size checks shall be more strict.
* @return The default implementation returns HEADER_SIZE.
*/
virtual size_t getMinimumMessageSize();
};
#endif /* FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ */
#endif /* MESSAGEQUEUEMESSAGE_H_ */

View File

@@ -1,80 +0,0 @@
#ifndef FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_
#define FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_
#include <fsfw/ipc/messageQueueDefinitions.h>
#include <cstddef>
#include <cstdint>
class MessageQueueMessageIF {
public:
/**
* @brief This constants defines the size of the header,
* which is added to every message.
*/
static const size_t HEADER_SIZE = sizeof(MessageQueueId_t);
virtual ~MessageQueueMessageIF() {};
/**
* @brief With this method, the whole content and the message
* size is set to zero.
* @details
* Implementations should also take care to clear data which is stored
* indirectly (e.g. storage data).
*/
virtual void clear() = 0;
/**
* @brief Get read-only pointer to the complete data of the message.
* @return
*/
virtual const uint8_t* getBuffer() const = 0;
/**
* @brief This method is used to get the complete data of the message.
*/
virtual uint8_t* getBuffer() = 0;
/**
* @brief This method is used to set the sender's message queue id
* information prior to sending the message.
* @param setId
* The message queue id that identifies the sending message queue.
*/
virtual void setSender(MessageQueueId_t setId) = 0;
/**
* @brief This method is used to extract the sender's message queue id
* information from a received message.
*/
virtual MessageQueueId_t getSender() const = 0;
/**
* @brief This method is used to fetch the data content of the message.
* @details
* It shall be used by child classes to add data at the right position.
*/
virtual const uint8_t* getData() const = 0;
/**
* @brief This method is used to fetch the data content of the message.
* @details
* It shall be used by child classes to add data at the right position.
*/
virtual uint8_t* getData() = 0;
/**
* Get constant message size of current message implementation.
* @return
*/
virtual size_t getMessageSize() const = 0;
virtual void setMessageSize(size_t messageSize) = 0;
virtual size_t getMinimumMessageSize() const = 0;
virtual size_t getMaximumMessageSize() const = 0;
};
#endif /* FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ */

View File

@@ -1,26 +1,37 @@
#ifndef FSFW_IPC_MESSAGEQUEUESENDERIF_H_
#define FSFW_IPC_MESSAGEQUEUESENDERIF_H_
#ifndef FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_
#define FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_
#include "MessageQueueIF.h"
#include "MessageQueueMessageIF.h"
#include "../objectmanager/ObjectManagerIF.h"
class MessageQueueMessage;
//TODO: Actually, the definition of this ID to be a uint32_t is not ideal and breaks layering.
//However, it is difficult to keep layering, as the ID is stored in many places and sent around in
//MessageQueueMessage.
//Ideally, one would use the (current) object_id_t only, however, doing a lookup of queueIDs for every
//call does not sound ideal.
//In a first step, I'll circumvent the issue by not touching it, maybe in a second step.
//This also influences Interface design (getCommandQueue) and some other issues..
typedef uint32_t MessageQueueId_t;
class MessageQueueSenderIF {
public:
static const MessageQueueId_t NO_QUEUE = 0;
virtual ~MessageQueueSenderIF() {}
/**
* Allows sending messages without actually "owning" a message queue.
* Allows sending messages without actually "owing" a message queue.
* Not sure whether this is actually a good idea.
* Must be implemented by a subclass.
*/
static ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = MessageQueueIF::NO_QUEUE,
bool ignoreFault = false);
MessageQueueMessage* message, MessageQueueId_t sentFrom =
MessageQueueSenderIF::NO_QUEUE, bool ignoreFault=false);
private:
MessageQueueSenderIF() {}
};
#endif /* FSFW_IPC_MESSAGEQUEUESENDERIF_H_ */
#endif /* FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ */

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