Merge branch 'master' into mueller/enhanced-controller
This commit is contained in:
commit
3920fd89bd
0
.gitmodules
vendored
Normal file
0
.gitmodules
vendored
Normal file
11
FSFWVersion.h
Normal file
11
FSFWVersion.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef FSFW_DEFAULTCFG_VERSION_H_
|
||||
#define FSFW_DEFAULTCFG_VERSION_H_
|
||||
|
||||
const char* const FSFW_VERSION_NAME = "fsfw";
|
||||
|
||||
#define FSFW_VERSION 0
|
||||
#define FSFW_SUBVERSION 0
|
||||
|
||||
|
||||
|
||||
#endif /* FSFW_DEFAULTCFG_VERSION_H_ */
|
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
||||
Flight Software Framework (FSFW)
|
||||
======
|
||||
|
||||
I want to be written!
|
@ -3,8 +3,9 @@
|
||||
#include "../ipc/MessageQueueSenderIF.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
|
||||
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) :
|
||||
owner(setOwner), queueToUse(useThisQueue), ipcStore(nullptr) {
|
||||
ActionHelper::ActionHelper(HasActionsIF* setOwner,
|
||||
MessageQueueIF* useThisQueue) :
|
||||
owner(setOwner), queueToUse(useThisQueue) {
|
||||
}
|
||||
|
||||
ActionHelper::~ActionHelper() {
|
||||
@ -33,13 +34,15 @@ 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);
|
||||
@ -49,8 +52,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);
|
||||
@ -62,6 +65,11 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t act
|
||||
}
|
||||
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);
|
||||
@ -86,22 +94,28 @@ 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);
|
||||
|
||||
//TODO Service Implementation sucks at the moment
|
||||
if (hideSender){
|
||||
// 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 {
|
||||
}
|
||||
else {
|
||||
result = queueToUse->sendMessage(reportTo, &reply);
|
||||
}
|
||||
if ( result != HasReturnvaluesIF::RETURN_OK){
|
||||
|
||||
if (result != HasReturnvaluesIF::RETURN_OK){
|
||||
ipcStore->deleteData(storeAddress);
|
||||
}
|
||||
return result;
|
||||
@ -109,3 +123,39 @@ 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;
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
#ifndef ACTIONHELPER_H_
|
||||
#define ACTIONHELPER_H_
|
||||
#ifndef FSFW_ACTION_ACTIONHELPER_H_
|
||||
#define FSFW_ACTION_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 it 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 needs a
|
||||
* valid MessageQueueIF pointer!
|
||||
*/
|
||||
class HasActionsIF;
|
||||
|
||||
@ -18,7 +21,8 @@ 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);
|
||||
|
||||
@ -26,28 +30,36 @@ 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
|
||||
*
|
||||
@ -55,39 +67,59 @@ 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
|
||||
*
|
||||
* @param reportTo MessageQueueId_t to report the action completion message to
|
||||
* Function to be called by the owner if an action does report data.
|
||||
* Takes a SerializeIF* pointer and serializes it into the IPC store.
|
||||
* @param reportTo MessageQueueId_t to report the action completion
|
||||
* message to
|
||||
* @param 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);
|
||||
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);
|
||||
/**
|
||||
* 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:
|
||||
static const uint8_t STEP_OFFSET = 1;//!< Increase of value of this per step
|
||||
//!< Increase of value of this per step
|
||||
static const uint8_t STEP_OFFSET = 1;
|
||||
HasActionsIF* owner;//!< Pointer to the owner
|
||||
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)
|
||||
//! 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;
|
||||
|
||||
/**
|
||||
*Internal function called by handleActionMessage(CommandMessage* command)
|
||||
*
|
||||
* Internal function called by handleActionMessage
|
||||
* @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 /* ACTIONHELPER_H_ */
|
||||
#endif /* FSFW_ACTION_ACTIONHELPER_H_ */
|
||||
|
@ -1,11 +1,12 @@
|
||||
#ifndef FRAMEWORK_ACTION_HASACTIONSIF_H_
|
||||
#define FRAMEWORK_ACTION_HASACTIONSIF_H_
|
||||
#ifndef FSFW_ACTION_HASACTIONSIF_H_
|
||||
#define FSFW_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
|
||||
@ -47,14 +48,16 @@ public:
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
/**
|
||||
* Execute or initialize the execution of a certain function.
|
||||
* 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!
|
||||
* 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
|
||||
*/
|
||||
virtual ReturnValue_t executeAction(ActionId_t actionId,
|
||||
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif /* FRAMEWORK_ACTION_HASACTIONSIF_H_ */
|
||||
#endif /* FSFW_ACTION_HASACTIONSIF_H_ */
|
||||
|
@ -1,16 +1,17 @@
|
||||
#include "HasActionsIF.h"
|
||||
#include "SimpleActionHelper.h"
|
||||
|
||||
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner,
|
||||
MessageQueueIF* useThisQueue) :
|
||||
ActionHelper(setOwner, useThisQueue), isExecuting(false), lastCommander(
|
||||
0), lastAction(0), stepCount(0) {
|
||||
ActionHelper(setOwner, useThisQueue), isExecuting(false) {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -1,8 +1,13 @@
|
||||
#ifndef SIMPLEACTIONHELPER_H_
|
||||
#define SIMPLEACTIONHELPER_H_
|
||||
#ifndef FSFW_ACTION_SIMPLEACTIONHELPER_H_
|
||||
#define FSFW_ACTION_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);
|
||||
@ -12,13 +17,14 @@ 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;
|
||||
ActionId_t lastAction;
|
||||
uint8_t stepCount;
|
||||
MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE;
|
||||
ActionId_t lastAction = 0;
|
||||
uint8_t stepCount = 0;
|
||||
};
|
||||
|
||||
#endif /* SIMPLEACTIONHELPER_H_ */
|
||||
|
6
defaultcfg/README.md
Normal file
6
defaultcfg/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
# How to setup configuration folder for FSFW
|
||||
|
||||
It is recommended to copy the content of the defaultcfg folder
|
||||
into a config folder which is in the same directory as the Flight
|
||||
Software Framework submodule. After that, the config.mk folder should be
|
||||
included by the primary Makefile with CURRENTPATH set correctly.
|
54
defaultcfg/config/FSFWConfig.h
Normal file
54
defaultcfg/config/FSFWConfig.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef CONFIG_FSFWCONFIG_H_
|
||||
#define CONFIG_FSFWCONFIG_H_
|
||||
|
||||
#include <FSFWVersion.h>
|
||||
#include <cstddef>
|
||||
|
||||
//! 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_ */
|
16
defaultcfg/config/OBSWConfig.h
Normal file
16
defaultcfg/config/OBSWConfig.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef CONFIG_OBSWCONFIG_H_
|
||||
#define CONFIG_OBSWCONFIG_H_
|
||||
|
||||
#include "OBSWVersion.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace config {
|
||||
#endif
|
||||
|
||||
/* Add mission configuration flags here */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_OBSWCONFIG_H_ */
|
9
defaultcfg/config/OBSWVersion.h
Normal file
9
defaultcfg/config/OBSWVersion.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef CONFIG_VERSION_H_
|
||||
#define CONFIG_VERSION_H_
|
||||
|
||||
/* OBSW versioning can be specified in this file */
|
||||
|
||||
#define OBSW_VERSION 0
|
||||
#define OBSW_SUBVERSION 0
|
||||
|
||||
#endif /* CONFIG_VERSION_H_ */
|
15
defaultcfg/config/config.mk
Normal file
15
defaultcfg/config/config.mk
Normal file
@ -0,0 +1,15 @@
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/tmtc/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/devices/*.cpp)
|
||||
|
||||
INCLUDES += $(CURRENTPATH)
|
||||
INCLUDES += $(CURRENTPATH)/objects
|
||||
INCLUDES += $(CURRENTPATH)/returnvalues
|
||||
INCLUDES += $(CURRENTPATH)/tmtc
|
||||
INCLUDES += $(CURRENTPATH)/events
|
||||
INCLUDES += $(CURRENTPATH)/devices
|
||||
INCLUDES += $(CURRENTPATH)/pollingsequence
|
||||
INCLUDES += $(CURRENTPATH)/ipc
|
5
defaultcfg/config/devices/logicalAddresses.cpp
Normal file
5
defaultcfg/config/devices/logicalAddresses.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "logicalAddresses.h"
|
||||
|
||||
|
||||
|
||||
|
18
defaultcfg/config/devices/logicalAddresses.h
Normal file
18
defaultcfg/config/devices/logicalAddresses.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||
#define CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||
|
||||
#include <config/objects/systemObjectList.h>
|
||||
#include <fsfw/devicehandlers/CookieIF.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_ */
|
4
defaultcfg/config/devices/powerSwitcherList.cpp
Normal file
4
defaultcfg/config/devices/powerSwitcherList.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#include "powerSwitcherList.h"
|
||||
|
||||
|
||||
|
12
defaultcfg/config/devices/powerSwitcherList.h
Normal file
12
defaultcfg/config/devices/powerSwitcherList.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||
#define CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||
|
||||
namespace switches {
|
||||
/* Switches are uint8_t datatype and go from 0 to 255 */
|
||||
enum switcherList {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_DEVICES_POWERSWITCHERLIST_H_ */
|
18
defaultcfg/config/events/subsystemIdRanges.h
Normal file
18
defaultcfg/config/events/subsystemIdRanges.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
|
||||
#define CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <fsfw/events/fwSubsystemIdRanges.h>
|
||||
|
||||
/**
|
||||
* @brief Custom subsystem IDs can be added here
|
||||
* @details
|
||||
* Subsystem IDs are used to create unique events.
|
||||
*/
|
||||
namespace SUBSYSTEM_ID {
|
||||
enum: uint8_t {
|
||||
SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE,
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ */
|
11
defaultcfg/config/ipc/missionMessageTypes.cpp
Normal file
11
defaultcfg/config/ipc/missionMessageTypes.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include <config/ipc/MissionMessageTypes.h>
|
||||
#include <fsfw/ipc/CommandMessageIF.h>
|
||||
|
||||
void messagetypes::clearMissionMessage(CommandMessage* message) {
|
||||
switch(message->getMessageType()) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
21
defaultcfg/config/ipc/missionMessageTypes.h
Normal file
21
defaultcfg/config/ipc/missionMessageTypes.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||
#define CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||
|
||||
#include <fsfw/ipc/CommandMessage.h>
|
||||
#include <fsfw/ipc/FwMessageTypes.h>
|
||||
|
||||
/**
|
||||
* Custom command messages are specified here.
|
||||
* Most messages needed to use FSFW are already located in
|
||||
* <fsfw/ipc/FwMessageTypes.h>
|
||||
* @param message Generic Command Message
|
||||
*/
|
||||
namespace messagetypes {
|
||||
enum CustomMessageTypes {
|
||||
MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT
|
||||
};
|
||||
|
||||
void clearMissionMessage(CommandMessage* message);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IPC_MISSIONMESSAGETYPES_H_ */
|
54
defaultcfg/config/objects/Factory.cpp
Normal file
54
defaultcfg/config/objects/Factory.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "Factory.h"
|
||||
#include "../tmtc/apid.h"
|
||||
#include "../tmtc/pusIds.h"
|
||||
#include "../objects/systemObjectList.h"
|
||||
#include "../devices/logicalAddresses.h"
|
||||
#include "../devices/powerSwitcherList.h"
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
|
||||
#include <fsfw/events/EventManager.h>
|
||||
#include <fsfw/health/HealthTable.h>
|
||||
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
|
||||
#include <fsfw/tmtcservices/CommandingServiceBase.h>
|
||||
#include <fsfw/tmtcservices/PusServiceBase.h>
|
||||
|
||||
#include <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::PUS_PACKET_DISTRIBUTOR;
|
||||
PusServiceBase::packetDestination = objects::TM_FUNNEL;
|
||||
|
||||
CommandingServiceBase::defaultPacketSource = objects::PUS_PACKET_DISTRIBUTOR;
|
||||
CommandingServiceBase::defaultPacketDestination = objects::TM_FUNNEL;
|
||||
|
||||
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::PUS_TIME;
|
||||
//TmFunnel::downlinkDestination = objects::NO_OBJECT;
|
||||
}
|
||||
|
17
defaultcfg/config/objects/Factory.h
Normal file
17
defaultcfg/config/objects/Factory.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef FACTORY_H_
|
||||
#define FACTORY_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
#include <cstddef>
|
||||
|
||||
namespace Factory {
|
||||
/**
|
||||
* @brief Creates all SystemObject elements which are persistent
|
||||
* during execution.
|
||||
*/
|
||||
void produce();
|
||||
void setStaticFrameworkObjectIds();
|
||||
}
|
||||
|
||||
|
||||
#endif /* FACTORY_H_ */
|
16
defaultcfg/config/objects/systemObjectList.h
Normal file
16
defaultcfg/config/objects/systemObjectList.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||
#define CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||
|
||||
// The objects will be instantiated in the ID order
|
||||
namespace objects {
|
||||
enum sourceObjects: uint32_t {
|
||||
/* All addresses between start and end are reserved for the FSFW */
|
||||
FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION,
|
||||
FSFW_CONFIG_RESERVED_END = TM_STORE
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */
|
23
defaultcfg/config/pollingsequence/PollingSequenceFactory.cpp
Normal file
23
defaultcfg/config/pollingsequence/PollingSequenceFactory.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "PollingSequenceFactory.h"
|
||||
|
||||
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
|
||||
|
||||
ReturnValue_t pst::pollingSequenceInitDefault(
|
||||
FixedTimeslotTaskIF *thisSequence) {
|
||||
/* Length of a communication cycle */
|
||||
uint32_t length = thisSequence->getPeriodMs();
|
||||
|
||||
/* Add polling sequence table here */
|
||||
|
||||
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
else {
|
||||
sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!"
|
||||
<< std::endl;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
32
defaultcfg/config/pollingsequence/PollingSequenceFactory.h
Normal file
32
defaultcfg/config/pollingsequence/PollingSequenceFactory.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef POLLINGSEQUENCEFACTORY_H_
|
||||
#define POLLINGSEQUENCEFACTORY_H_
|
||||
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
class FixedTimeslotTaskIF;
|
||||
|
||||
/**
|
||||
* All device handlers are scheduled by adding them into Polling Sequence Tables (PST)
|
||||
* to satisfy stricter timing requirements of device communication,
|
||||
* A device handler has four different communication steps:
|
||||
* 1. DeviceHandlerIF::SEND_WRITE -> Send write via interface
|
||||
* 2. DeviceHandlerIF::GET_WRITE -> Get confirmation for write
|
||||
* 3. DeviceHandlerIF::SEND_READ -> Send read request
|
||||
* 4. DeviceHandlerIF::GET_READ -> Read from interface
|
||||
* The PST specifies precisely when the respective ComIF functions are called
|
||||
* during the communication cycle time.
|
||||
* The task is created using the FixedTimeslotTaskIF,
|
||||
* which utilises the underlying Operating System Abstraction Layer (OSAL)
|
||||
*
|
||||
* @param thisSequence FixedTimeslotTaskIF * object is passed inside the Factory class when creating the PST
|
||||
* @return
|
||||
*/
|
||||
namespace pst {
|
||||
|
||||
/* Default PST */
|
||||
ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif /* POLLINGSEQUENCEINIT_H_ */
|
16
defaultcfg/config/returnvalues/classIds.h
Normal file
16
defaultcfg/config/returnvalues/classIds.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||
#define CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||
|
||||
#include <fsfw/returnvalues/FwClassIds.h>
|
||||
|
||||
/**
|
||||
* @brief CLASS_ID defintions which are required for custom returnvalues.
|
||||
*/
|
||||
namespace CLASS_ID {
|
||||
enum {
|
||||
MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_RETURNVALUES_CLASSIDS_H_ */
|
18
defaultcfg/config/tmtc/apid.h
Normal file
18
defaultcfg/config/tmtc/apid.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef CONFIG_TMTC_APID_H_
|
||||
#define CONFIG_TMTC_APID_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* Application Process Definition: entity, uniquely identified by an
|
||||
* application process ID (APID), capable of generating telemetry source
|
||||
* packets and receiving telecommand packets.
|
||||
*
|
||||
* Chose APID(s) for mission and define it here.
|
||||
*/
|
||||
namespace apid {
|
||||
static const uint16_t DEFAULT_APID = 0x00;
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_TMTC_APID_H_ */
|
23
defaultcfg/config/tmtc/pusIds.h
Normal file
23
defaultcfg/config/tmtc/pusIds.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef CONFIG_TMTC_PUSIDS_HPP_
|
||||
#define CONFIG_TMTC_PUSIDS_HPP_
|
||||
|
||||
namespace pus {
|
||||
enum Ids: uint8_t {
|
||||
PUS_SERVICE_1 = 1,
|
||||
PUS_SERVICE_2 = 2,
|
||||
PUS_SERVICE_3 = 3,
|
||||
PUS_SERVICE_5 = 5,
|
||||
PUS_SERVICE_6 = 6,
|
||||
PUS_SERVICE_8 = 8,
|
||||
PUS_SERVICE_9 = 9,
|
||||
PUS_SERVICE_11 = 11,
|
||||
PUS_SERVICE_17 = 17,
|
||||
PUS_SERVICE_19 = 19,
|
||||
PUS_SERVICE_20 = 20,
|
||||
PUS_SERVICE_23 = 23,
|
||||
PUS_SERVICE_200 = 200,
|
||||
PUS_SERVICE_201 = 201,
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* CONFIG_TMTC_PUSIDS_HPP_ */
|
@ -1224,7 +1224,7 @@ void DeviceHandlerBase::buildInternalCommand(void) {
|
||||
if (result == BUSY) {
|
||||
//so we can track misconfigurations
|
||||
sif::debug << std::hex << getObjectId()
|
||||
<< ": DHB::buildInternalCommand: Busy" << std::endl;
|
||||
<< ": DHB::buildInternalCommand: Busy" << std::dec << std::endl;
|
||||
result = NOTHING_TO_SEND; //no need to report this
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <stdint.h>
|
||||
#include "fwSubsystemIdRanges.h"
|
||||
//could be move to more suitable location
|
||||
#include <config/tmtc/subsystemIdRanges.h>
|
||||
#include <subsystemIdRanges.h>
|
||||
|
||||
typedef uint16_t EventId_t;
|
||||
typedef uint8_t EventSeverity_t;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "EventManager.h"
|
||||
#include "EventMessage.h"
|
||||
#include <FSFWConfig.h>
|
||||
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../ipc/QueueFactory.h"
|
||||
#include "../ipc/MutexFactory.h"
|
||||
@ -12,8 +14,10 @@ const uint16_t EventManager::POOL_SIZES[N_POOLS] = {
|
||||
// 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.
|
||||
// SHOULDDO: Shouldn't this be in the config folder and passed via ctor?
|
||||
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 };
|
||||
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = {
|
||||
fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES ,
|
||||
fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS,
|
||||
fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS };
|
||||
|
||||
EventManager::EventManager(object_id_t setObjectId) :
|
||||
SystemObject(setObjectId),
|
||||
|
13
fsfw.mk
13
fsfw.mk
@ -28,12 +28,25 @@ 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
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef HASHEALTHIF_H_
|
||||
#define HASHEALTHIF_H_
|
||||
#ifndef FSFW_HEALTH_HASHEALTHIF_H_
|
||||
#define FSFW_HEALTH_HASHEALTHIF_H_
|
||||
|
||||
#include "../events/Event.h"
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
@ -8,9 +8,13 @@
|
||||
class HasHealthIF {
|
||||
public:
|
||||
|
||||
typedef enum {
|
||||
HEALTHY = 1, FAULTY = 0, EXTERNAL_CONTROL = 2, NEEDS_RECOVERY = 3, PERMANENT_FAULTY = 4
|
||||
} HealthState;
|
||||
enum HealthState: uint8_t {
|
||||
HEALTHY = 1,
|
||||
FAULTY = 0,
|
||||
EXTERNAL_CONTROL = 2,
|
||||
NEEDS_RECOVERY = 3,
|
||||
PERMANENT_FAULTY = 4
|
||||
};
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
||||
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
|
||||
@ -31,20 +35,17 @@ public:
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
||||
/**
|
||||
* set the Health State
|
||||
*
|
||||
* @brief Set the Health State
|
||||
* The parent will be informed, if the Health changes
|
||||
*
|
||||
* @param health
|
||||
*/
|
||||
virtual ReturnValue_t setHealth(HealthState health) = 0;
|
||||
|
||||
/**
|
||||
* get Health State
|
||||
*
|
||||
* @return Health State of the object
|
||||
* @brief Get Health State
|
||||
* @return Health State of the object
|
||||
*/
|
||||
virtual HasHealthIF::HealthState getHealth() = 0;
|
||||
};
|
||||
|
||||
#endif /* HASHEALTHIF_H_ */
|
||||
#endif /* FSFW_HEALTH_HASHEALTHIF_H_ */
|
||||
|
@ -12,13 +12,15 @@
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
|
||||
/**
|
||||
* Helper class for Objects that implement HasHealthIF
|
||||
* @brief Helper class for Objects that implement HasHealthIF
|
||||
* @details
|
||||
* It takes care of registering with the Health Table as well as handling
|
||||
* health commands (including replying to the sender) and updating
|
||||
* the Health Table.
|
||||
*
|
||||
* It takes care of registering with the Health Table as well as handling health commands
|
||||
* (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
|
||||
* 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
|
||||
@ -27,10 +29,9 @@ class HealthHelper {
|
||||
public:
|
||||
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @param owner
|
||||
* @param objectId the object Id to use when communication with the HealthTable
|
||||
* @param objectId The object Id to use when communication with
|
||||
* the HealthTable
|
||||
*/
|
||||
HealthHelper(HasHealthIF* owner, object_id_t objectId);
|
||||
|
||||
@ -56,8 +57,9 @@ 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);
|
||||
|
||||
@ -78,16 +80,19 @@ 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 );
|
||||
|
||||
@ -110,11 +115,15 @@ 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);
|
||||
};
|
||||
|
@ -7,11 +7,13 @@ 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();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef HEALTHMESSAGE_H_
|
||||
#define HEALTHMESSAGE_H_
|
||||
#ifndef FSFW_HEALTH_HEALTHMESSAGE_H_
|
||||
#define FSFW_HEALTH_HEALTHMESSAGE_H_
|
||||
|
||||
#include "HasHealthIF.h"
|
||||
#include "../ipc/CommandMessage.h"
|
||||
@ -7,14 +7,20 @@
|
||||
class HealthMessage {
|
||||
public:
|
||||
static const uint8_t MESSAGE_ID = messagetypes::HEALTH_COMMAND;
|
||||
static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);//REPLY_COMMAND_OK/REPLY_REJECTED
|
||||
static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(3); //NO REPLY!
|
||||
|
||||
static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);
|
||||
// No reply expected, health will be announced as event!
|
||||
static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(2);
|
||||
// Same as before, but all objects in health table will
|
||||
// announce their health as events.
|
||||
static const Command_t HEALTH_ANNOUNCE_ALL = MAKE_COMMAND_ID(3);
|
||||
|
||||
static const Command_t HEALTH_INFO = MAKE_COMMAND_ID(5);
|
||||
static const Command_t 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);
|
||||
@ -27,4 +33,4 @@ private:
|
||||
HealthMessage();
|
||||
};
|
||||
|
||||
#endif /* HEALTHMESSAGE_H_ */
|
||||
#endif /* FSFW_HEALTH_HEALTHMESSAGE_H_ */
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "HealthTable.h"
|
||||
#include "../serialize/SerializeAdapter.h"
|
||||
#include "../ipc/MutexHelper.h"
|
||||
#include "../ipc/MutexFactory.h"
|
||||
#include "../serialize/SerializeAdapter.h"
|
||||
|
||||
HealthTable::HealthTable(object_id_t objectid) :
|
||||
SystemObject(objectid) {
|
||||
@ -9,6 +10,12 @@ 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);
|
||||
}
|
||||
@ -18,74 +25,63 @@ ReturnValue_t HealthTable::registerObject(object_id_t object,
|
||||
if (healthMap.count(object) != 0) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
healthMap.insert(
|
||||
std::pair<object_id_t, HasHealthIF::HealthState>(object,
|
||||
initilialState));
|
||||
healthMap.emplace(object, initilialState);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void HealthTable::setHealth(object_id_t object,
|
||||
HasHealthIF::HealthState newState) {
|
||||
mutex->lockMutex(MutexIF::BLOCKING);
|
||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||
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;
|
||||
mutex->lockMutex(MutexIF::BLOCKING);
|
||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||
HealthMap::iterator iter = healthMap.find(object);
|
||||
if (iter != healthMap.end()) {
|
||||
state = iter->second;
|
||||
}
|
||||
mutex->unlockMutex();
|
||||
return state;
|
||||
}
|
||||
|
||||
uint32_t HealthTable::getPrintSize() {
|
||||
mutex->lockMutex(MutexIF::BLOCKING);
|
||||
uint32_t size = healthMap.size() * 5 + 2;
|
||||
mutex->unlockMutex();
|
||||
return size;
|
||||
}
|
||||
|
||||
bool HealthTable::hasHealth(object_id_t object) {
|
||||
bool exits = false;
|
||||
mutex->lockMutex(MutexIF::BLOCKING);
|
||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||
HealthMap::iterator iter = healthMap.find(object);
|
||||
if (iter != healthMap.end()) {
|
||||
exits = true;
|
||||
return true;
|
||||
}
|
||||
mutex->unlockMutex();
|
||||
return exits;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t HealthTable::getPrintSize() {
|
||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||
uint32_t size = healthMap.size() * sizeof(object_id_t) +
|
||||
sizeof(HasHealthIF::HealthState) + sizeof(uint16_t);
|
||||
return size;
|
||||
}
|
||||
|
||||
void HealthTable::printAll(uint8_t* pointer, size_t maxSize) {
|
||||
mutex->lockMutex(MutexIF::BLOCKING);
|
||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||
size_t size = 0;
|
||||
uint16_t count = healthMap.size();
|
||||
ReturnValue_t result = SerializeAdapter::serialize(&count,
|
||||
SerializeAdapter::serialize(&count,
|
||||
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||
HealthMap::iterator iter;
|
||||
for (iter = healthMap.begin();
|
||||
iter != healthMap.end() && result == HasReturnvaluesIF::RETURN_OK;
|
||||
++iter) {
|
||||
result = SerializeAdapter::serialize(&iter->first,
|
||||
for (const auto& health: healthMap) {
|
||||
SerializeAdapter::serialize(&health.first,
|
||||
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||
uint8_t health = iter->second;
|
||||
result = SerializeAdapter::serialize(&health, &pointer, &size,
|
||||
uint8_t healthValue = health.second;
|
||||
SerializeAdapter::serialize(&healthValue, &pointer, &size,
|
||||
maxSize, SerializeIF::Endianness::BIG);
|
||||
}
|
||||
mutex->unlockMutex();
|
||||
}
|
||||
|
||||
ReturnValue_t HealthTable::iterate(
|
||||
std::pair<object_id_t, HasHealthIF::HealthState> *value, bool reset) {
|
||||
ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) {
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
mutex->lockMutex(MutexIF::BLOCKING);
|
||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||
if (reset) {
|
||||
mapIterator = healthMap.begin();
|
||||
}
|
||||
@ -94,7 +90,5 @@ ReturnValue_t HealthTable::iterate(
|
||||
}
|
||||
*value = *mapIterator;
|
||||
mapIterator++;
|
||||
mutex->unlockMutex();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1,35 +1,47 @@
|
||||
#ifndef HEALTHTABLE_H_
|
||||
#define HEALTHTABLE_H_
|
||||
#ifndef FSFW_HEALTH_HEALTHTABLE_H_
|
||||
#define FSFW_HEALTH_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();
|
||||
|
||||
virtual ReturnValue_t registerObject(object_id_t object,
|
||||
HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY);
|
||||
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
||||
|
||||
virtual bool hasHealth(object_id_t object);
|
||||
virtual void setHealth(object_id_t object, HasHealthIF::HealthState newState);
|
||||
virtual HasHealthIF::HealthState getHealth(object_id_t);
|
||||
/** 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 uint32_t getPrintSize();
|
||||
virtual void printAll(uint8_t *pointer, size_t maxSize);
|
||||
/** 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;
|
||||
|
||||
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(std::pair<object_id_t,HasHealthIF::HealthState> *value, bool reset = false);
|
||||
virtual ReturnValue_t iterate(
|
||||
HealthEntry* value,
|
||||
bool reset = false) override;
|
||||
};
|
||||
|
||||
#endif /* HEALTHTABLE_H_ */
|
||||
#endif /* FSFW_HEALTH_HEALTHTABLE_H_ */
|
||||
|
@ -1,26 +1,24 @@
|
||||
#ifndef HEALTHTABLEIF_H_
|
||||
#define HEALTHTABLEIF_H_
|
||||
#ifndef FSFW_HEALTH_HEALTHTABLEIF_H_
|
||||
#define FSFW_HEALTH_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 uint32_t getPrintSize() = 0;
|
||||
virtual size_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 /* HEALTHTABLEIF_H_ */
|
||||
#endif /* FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ */
|
||||
|
@ -1,8 +1,9 @@
|
||||
#ifndef FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_
|
||||
#define FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_
|
||||
#ifndef FSFW_HEALTH_MANAGESHEALTHIF_H_
|
||||
#define FSFW_HEALTH_MANAGESHEALTHIF_H_
|
||||
|
||||
#include "HasHealthIF.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
|
||||
class ManagesHealthIF {
|
||||
public:
|
||||
virtual ~ManagesHealthIF() {
|
||||
@ -49,4 +50,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ */
|
||||
#endif /* FSFW_HEALTH_MANAGESHEALTHIF_H_ */
|
||||
|
@ -1,6 +1,11 @@
|
||||
|
||||
#include "MessageQueue.h"
|
||||
|
||||
#include "../../ipc/MessageQueueSenderIF.h"
|
||||
#include "../../ipc/MessageQueueMessageIF.h"
|
||||
#include "../../ipc/QueueFactory.h"
|
||||
#include "../../osal/host/MessageQueue.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
QueueFactory* QueueFactory::factoryInstance = nullptr;
|
||||
|
148
osal/windows/TcWinUdpPollingTask.cpp
Normal file
148
osal/windows/TcWinUdpPollingTask.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
#include "TcWinUdpPollingTask.h"
|
||||
#include "../../globalfunctions/arrayprinter.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
TcWinUdpPollingTask::TcWinUdpPollingTask(object_id_t objectId,
|
||||
object_id_t tmtcUnixUdpBridge, size_t frameSize,
|
||||
double timeoutSeconds): SystemObject(objectId),
|
||||
tmtcBridgeId(tmtcUnixUdpBridge) {
|
||||
if(frameSize > 0) {
|
||||
this->frameSize = frameSize;
|
||||
}
|
||||
else {
|
||||
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
|
||||
}
|
||||
|
||||
// Set up reception buffer with specified frame size.
|
||||
// For now, it is assumed that only one frame is held in the buffer!
|
||||
receptionBuffer.reserve(this->frameSize);
|
||||
receptionBuffer.resize(this->frameSize);
|
||||
|
||||
if(timeoutSeconds == -1) {
|
||||
receptionTimeout = DEFAULT_TIMEOUT;
|
||||
}
|
||||
else {
|
||||
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
TcWinUdpPollingTask::~TcWinUdpPollingTask() {}
|
||||
|
||||
ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) {
|
||||
// Poll for new UDP datagrams in permanent loop.
|
||||
while(true) {
|
||||
//! Sender Address is cached here.
|
||||
struct sockaddr_in senderAddress;
|
||||
int senderAddressSize = sizeof(senderAddress);
|
||||
ssize_t bytesReceived = recvfrom(serverUdpSocket,
|
||||
reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
|
||||
receptionFlags, reinterpret_cast<sockaddr*>(&senderAddress),
|
||||
&senderAddressSize);
|
||||
if(bytesReceived == SOCKET_ERROR) {
|
||||
// handle error
|
||||
sif::error << "TcWinUdpPollingTask::performOperation: Reception"
|
||||
" error." << std::endl;
|
||||
handleReadError();
|
||||
continue;
|
||||
}
|
||||
//sif::debug << "TcWinUdpPollingTask::performOperation: " << bytesReceived
|
||||
// << " bytes received" << std::endl;
|
||||
|
||||
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
|
||||
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
||||
|
||||
}
|
||||
tmtcBridge->registerCommConnect();
|
||||
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
||||
store_address_t storeId;
|
||||
ReturnValue_t result = tcStore->addData(&storeId,
|
||||
receptionBuffer.data(), bytesRead);
|
||||
// arrayprinter::print(receptionBuffer.data(), bytesRead);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
|
||||
"storage failed" << std::endl;
|
||||
sif::error << "Packet size: " << bytesRead << std::endl;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
TmTcMessage message(storeId);
|
||||
|
||||
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
sif::error << "Serial Polling: Sending message to queue failed"
|
||||
<< std::endl;
|
||||
tcStore->deleteData(storeId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t TcWinUdpPollingTask::initialize() {
|
||||
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (tcStore == nullptr) {
|
||||
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
|
||||
<< std::endl;
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
tmtcBridge = objectManager->get<TmTcWinUdpBridge>(tmtcBridgeId);
|
||||
if(tmtcBridge == nullptr) {
|
||||
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
|
||||
" TMTC bridge object!" << std::endl;
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
serverUdpSocket = tmtcBridge->serverSocket;
|
||||
//sif::info << "TcWinUdpPollingTask::initialize: Server UDP socket "
|
||||
// << serverUdpSocket << std::endl;
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TcWinUdpPollingTask::initializeAfterTaskCreation() {
|
||||
// Initialize the destination after task creation. This ensures
|
||||
// that the destination has already been set in the TMTC bridge.
|
||||
targetTcDestination = tmtcBridge->getRequestQueue();
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void TcWinUdpPollingTask::setTimeout(double timeoutSeconds) {
|
||||
DWORD timeoutMs = timeoutSeconds * 1000.0;
|
||||
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
|
||||
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
|
||||
if(result == -1) {
|
||||
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
|
||||
"receive timeout failed with " << strerror(errno) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void TcWinUdpPollingTask::handleReadError() {
|
||||
int error = WSAGetLastError();
|
||||
switch(error) {
|
||||
case(WSANOTINITIALISED): {
|
||||
sif::info << "TmTcWinUdpBridge::handleReadError: WSANOTINITIALISED: "
|
||||
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(WSAEFAULT): {
|
||||
sif::info << "TmTcWinUdpBridge::handleReadError: WSADEFAULT: "
|
||||
<< "Bad address " << std::endl;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
sif::info << "TmTcWinUdpBridge::handleReadError: Error code: "
|
||||
<< error << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// to prevent spam.
|
||||
Sleep(1000);
|
||||
}
|
67
osal/windows/TcWinUdpPollingTask.h
Normal file
67
osal/windows/TcWinUdpPollingTask.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
||||
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
||||
|
||||
#include "TmTcWinUdpBridge.h"
|
||||
#include "../../objectmanager/SystemObject.h"
|
||||
#include "../../tasks/ExecutableObjectIF.h"
|
||||
#include "../../storagemanager/StorageManagerIF.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief This class can be used to implement the polling of a Unix socket,
|
||||
* using UDP for now.
|
||||
* @details
|
||||
* The task will be blocked while the specified number of bytes has not been
|
||||
* received, so TC reception is handled inside a separate task.
|
||||
* This class caches the IP address of the sender. It is assumed there
|
||||
* is only one sender for now.
|
||||
*/
|
||||
class TcWinUdpPollingTask: public SystemObject,
|
||||
public ExecutableObjectIF {
|
||||
friend class TmTcWinUdpBridge;
|
||||
public:
|
||||
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
|
||||
//! 0.5 default milliseconds timeout for now.
|
||||
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
|
||||
|
||||
TcWinUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
||||
size_t frameSize = 0, double timeoutSeconds = -1);
|
||||
virtual~ TcWinUdpPollingTask();
|
||||
|
||||
/**
|
||||
* Turn on optional timeout for UDP polling. In the default mode,
|
||||
* the receive function will block until a packet is received.
|
||||
* @param timeoutSeconds
|
||||
*/
|
||||
void setTimeout(double timeoutSeconds);
|
||||
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
virtual ReturnValue_t initialize() override;
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
protected:
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
|
||||
private:
|
||||
//! TMTC bridge is cached.
|
||||
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
||||
TmTcWinUdpBridge* tmtcBridge = nullptr;
|
||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||
//! Reception flags: https://linux.die.net/man/2/recvfrom.
|
||||
int receptionFlags = 0;
|
||||
|
||||
//! Server socket, which is member of TMTC bridge and is assigned in
|
||||
//! constructor
|
||||
SOCKET serverUdpSocket = 0;
|
||||
|
||||
std::vector<uint8_t> receptionBuffer;
|
||||
|
||||
size_t frameSize = 0;
|
||||
timeval receptionTimeout;
|
||||
|
||||
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
||||
void handleReadError();
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
176
osal/windows/TmTcWinUdpBridge.cpp
Normal file
176
osal/windows/TmTcWinUdpBridge.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
#include <fsfw/ipc/MutexHelper.h>
|
||||
#include "TmTcWinUdpBridge.h"
|
||||
|
||||
TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId,
|
||||
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
|
||||
uint16_t serverPort, uint16_t clientPort):
|
||||
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
|
||||
// Initiates Winsock DLL.
|
||||
WSAData wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
int err = WSAStartup(wVersionRequested, &wsaData);
|
||||
if (err != 0) {
|
||||
/* Tell the user that we could not find a usable */
|
||||
/* Winsock DLL. */
|
||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge:"
|
||||
"WSAStartup failed with error: " << err << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
|
||||
if(serverPort != 0xFFFF) {
|
||||
setServerPort = serverPort;
|
||||
}
|
||||
|
||||
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
|
||||
if(clientPort != 0xFFFF) {
|
||||
setClientPort = clientPort;
|
||||
}
|
||||
|
||||
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
|
||||
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if(serverSocket == INVALID_SOCKET) {
|
||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not open"
|
||||
" UDP socket!" << std::endl;
|
||||
handleSocketError();
|
||||
return;
|
||||
}
|
||||
|
||||
serverAddress.sin_family = AF_INET;
|
||||
|
||||
// Accept packets from any interface. (potentially insecure).
|
||||
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
serverAddress.sin_port = htons(setServerPort);
|
||||
serverAddressLen = sizeof(serverAddress);
|
||||
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,
|
||||
reinterpret_cast<const char*>(&serverSocketOptions),
|
||||
sizeof(serverSocketOptions));
|
||||
|
||||
clientAddress.sin_family = AF_INET;
|
||||
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
clientAddress.sin_port = htons(setClientPort);
|
||||
clientAddressLen = sizeof(clientAddress);
|
||||
|
||||
int result = bind(serverSocket,
|
||||
reinterpret_cast<struct sockaddr*>(&serverAddress),
|
||||
serverAddressLen);
|
||||
if(result != 0) {
|
||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind "
|
||||
"local port " << setServerPort << " to server socket!"
|
||||
<< std::endl;
|
||||
handleBindError();
|
||||
}
|
||||
}
|
||||
|
||||
TmTcWinUdpBridge::~TmTcWinUdpBridge() {
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||
int flags = 0;
|
||||
|
||||
//clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
|
||||
//clientAddressLen = sizeof(serverAddress);
|
||||
|
||||
// char ipAddress [15];
|
||||
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
||||
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||
|
||||
ssize_t bytesSent = sendto(serverSocket,
|
||||
reinterpret_cast<const char*>(data), dataLen, flags,
|
||||
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
|
||||
if(bytesSent == SOCKET_ERROR) {
|
||||
sif::error << "TmTcWinUdpBridge::sendTm: Send operation failed."
|
||||
<< std::endl;
|
||||
handleSendError();
|
||||
}
|
||||
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
|
||||
// " sent." << std::endl;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
|
||||
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
|
||||
|
||||
// char ipAddress [15];
|
||||
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
||||
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
|
||||
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||
|
||||
// Set new IP address if it has changed.
|
||||
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
|
||||
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
|
||||
clientAddressLen = sizeof(clientAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void TmTcWinUdpBridge::handleSocketError() {
|
||||
int errCode = WSAGetLastError();
|
||||
switch(errCode) {
|
||||
case(WSANOTINITIALISED): {
|
||||
sif::info << "TmTcWinUdpBridge::handleSocketError: WSANOTINITIALISED: "
|
||||
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/*
|
||||
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
||||
windows-sockets-error-codes-2
|
||||
*/
|
||||
sif::info << "TmTcWinUdpBridge::handleSocketError: Error code: "
|
||||
<< errCode << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TmTcWinUdpBridge::handleBindError() {
|
||||
int errCode = WSAGetLastError();
|
||||
switch(errCode) {
|
||||
case(WSANOTINITIALISED): {
|
||||
sif::info << "TmTcWinUdpBridge::handleBindError: WSANOTINITIALISED: "
|
||||
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/*
|
||||
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
||||
windows-sockets-error-codes-2
|
||||
*/
|
||||
sif::info << "TmTcWinUdpBridge::handleBindError: Error code: "
|
||||
<< errCode << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TmTcWinUdpBridge::handleSendError() {
|
||||
int errCode = WSAGetLastError();
|
||||
switch(errCode) {
|
||||
case(WSANOTINITIALISED): {
|
||||
sif::info << "TmTcWinUdpBridge::handleSendError: WSANOTINITIALISED: "
|
||||
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
||||
break;
|
||||
}
|
||||
case(WSAEADDRNOTAVAIL): {
|
||||
sif::info << "TmTcWinUdpBridge::handleReadError: WSAEADDRNOTAVAIL: "
|
||||
<< "Check target address. " << std::endl;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/*
|
||||
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
||||
windows-sockets-error-codes-2
|
||||
*/
|
||||
sif::info << "TmTcWinUdpBridge::handleSendError: Error code: "
|
||||
<< errCode << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
49
osal/windows/TmTcWinUdpBridge.h
Normal file
49
osal/windows/TmTcWinUdpBridge.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
|
||||
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
|
||||
|
||||
#include "../../tmtcservices/TmTcBridge.h"
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
class TmTcWinUdpBridge: public TmTcBridge {
|
||||
friend class TcWinUdpPollingTask;
|
||||
public:
|
||||
// The ports chosen here should not be used by any other process.
|
||||
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
|
||||
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
|
||||
|
||||
TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
object_id_t tmStoreId, object_id_t tcStoreId,
|
||||
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
|
||||
virtual~ TmTcWinUdpBridge();
|
||||
|
||||
void checkAndSetClientAddress(sockaddr_in clientAddress);
|
||||
|
||||
protected:
|
||||
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
||||
|
||||
private:
|
||||
SOCKET serverSocket = 0;
|
||||
|
||||
const int serverSocketOptions = 0;
|
||||
|
||||
struct sockaddr_in clientAddress;
|
||||
int clientAddressLen = 0;
|
||||
|
||||
struct sockaddr_in serverAddress;
|
||||
int serverAddressLen = 0;
|
||||
|
||||
//! Access to the client address is mutex protected as it is set
|
||||
//! by another task.
|
||||
MutexIF* mutex;
|
||||
|
||||
void handleSocketError();
|
||||
void handleBindError();
|
||||
void handleSendError();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */
|
||||
|
@ -1,8 +1,8 @@
|
||||
#ifndef FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_
|
||||
#define FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_
|
||||
#ifndef FSFW_RETURNVALUES_HASRETURNVALUESIF_H_
|
||||
#define FSFW_RETURNVALUES_HASRETURNVALUESIF_H_
|
||||
|
||||
#include "FwClassIds.h"
|
||||
#include <config/returnvalues/classIds.h>
|
||||
#include <returnvalues/classIds.h>
|
||||
#include <cstdint>
|
||||
|
||||
#define MAKE_RETURN_CODE( number ) ((INTERFACE_ID << 8) + (number))
|
||||
@ -15,9 +15,17 @@ public:
|
||||
static const ReturnValue_t RETURN_FAILED = 1;
|
||||
virtual ~HasReturnvaluesIF() {}
|
||||
|
||||
static ReturnValue_t makeReturnCode(uint8_t interfaceId, uint8_t number) {
|
||||
return (interfaceId << 8) + number;
|
||||
/**
|
||||
* It is discouraged to use the input parameters 0,0 and 0,1 as this
|
||||
* will generate the RETURN_OK and RETURN_FAILED returnvalues.
|
||||
* @param interfaceId
|
||||
* @param number
|
||||
* @return
|
||||
*/
|
||||
static constexpr ReturnValue_t makeReturnCode(uint8_t interfaceId,
|
||||
uint8_t number) {
|
||||
return (static_cast<ReturnValue_t>(interfaceId) << 8) + number;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ */
|
||||
#endif /* FSFW_RETURNVALUES_HASRETURNVALUESIF_H_ */
|
||||
|
@ -1,8 +1,9 @@
|
||||
#include "../timemanager/CCSDSTime.h"
|
||||
#include "CCSDSTime.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
|
||||
#include <FSFWConfig.h>
|
||||
|
||||
CCSDSTime::CCSDSTime() {
|
||||
}
|
||||
@ -158,15 +159,16 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
||||
}
|
||||
// Newlib nano can't parse uint8, see SCNu8 documentation and https://sourceware.org/newlib/README
|
||||
// Suggestion: use uint16 all the time. This should work on all systems.
|
||||
#ifdef NEWLIB_NANO_NO_C99_IO
|
||||
#if FSFW_NO_C99_IO == 1
|
||||
uint16_t year;
|
||||
uint16_t month;
|
||||
uint16_t day;
|
||||
uint16_t hour;
|
||||
uint16_t minute;
|
||||
float second;
|
||||
int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year,
|
||||
&month, &day, &hour, &minute, &second);
|
||||
int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%"
|
||||
"2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &month, &day, &hour,
|
||||
&minute, &second);
|
||||
if (count == 6) {
|
||||
to->year = year;
|
||||
to->month = month;
|
||||
@ -179,12 +181,13 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
||||
}
|
||||
|
||||
// try Code B (yyyy-ddd)
|
||||
count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &day,
|
||||
&hour, &minute, &second);
|
||||
count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%"
|
||||
"2" SCNu16 ":%fZ", &year, &day, &hour, &minute, &second);
|
||||
if (count == 5) {
|
||||
uint8_t tempDay;
|
||||
ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year,
|
||||
reinterpret_cast<uint8_t *>(&month), reinterpret_cast<uint8_t *>(&tempDay));
|
||||
reinterpret_cast<uint8_t *>(&month),
|
||||
reinterpret_cast<uint8_t *>(&tempDay));
|
||||
if (result != RETURN_OK) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
@ -14,8 +14,12 @@ public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::TIME_STAMPER_IF;
|
||||
static const ReturnValue_t BAD_TIMESTAMP = MAKE_RETURN_CODE(1);
|
||||
|
||||
static const uint8_t MISSION_TIMESTAMP_SIZE = 8; //!< This is a mission-specific constant and determines the total size reserved for timestamps.
|
||||
virtual ReturnValue_t addTimeStamp(uint8_t* buffer, const uint8_t maxSize) = 0;
|
||||
//! This is a mission-specific constant and determines the total
|
||||
//! size reserved for timestamps.
|
||||
//! TODO: Default define in FSFWConfig ?
|
||||
static const uint8_t MISSION_TIMESTAMP_SIZE = 8;
|
||||
virtual ReturnValue_t addTimeStamp(uint8_t* buffer,
|
||||
const uint8_t maxSize) = 0;
|
||||
virtual ~TimeStamperIF() {}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "SpacePacketBase.h"
|
||||
#include <string.h>
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include <cstring>
|
||||
|
||||
SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) {
|
||||
this->data = (SpacePacketPointer*) set_address;
|
||||
@ -14,7 +14,8 @@ uint8_t SpacePacketBase::getPacketVersionNumber( void ) {
|
||||
return (this->data->header.packet_id_h & 0b11100000) >> 5;
|
||||
}
|
||||
|
||||
void SpacePacketBase::initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) {
|
||||
void SpacePacketBase::initSpacePacketHeader(bool isTelecommand,
|
||||
bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) {
|
||||
//reset header to zero:
|
||||
memset(data,0, sizeof(this->data->header) );
|
||||
//Set TC/TM bit.
|
||||
@ -81,7 +82,7 @@ void SpacePacketBase::setPacketDataLength( uint16_t new_length) {
|
||||
this->data->header.packet_length_l = ( new_length & 0x00FF );
|
||||
}
|
||||
|
||||
uint32_t SpacePacketBase::getFullSize() {
|
||||
size_t SpacePacketBase::getFullSize() {
|
||||
//+1 is done because size in packet data length field is: size of data field -1
|
||||
return this->getPacketDataLength() + sizeof(this->data->header) + 1;
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
#ifndef SPACEPACKETBASE_H_
|
||||
#define SPACEPACKETBASE_H_
|
||||
#ifndef FSFW_TMTCPACKET_SPACEPACKETBASE_H_
|
||||
#define FSFW_TMTCPACKET_SPACEPACKETBASE_H_
|
||||
|
||||
#include "ccsds_header.h"
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* \defgroup tmtcpackets Space Packets
|
||||
* @defgroup tmtcpackets Space Packets
|
||||
* This is the group, where all classes associated with Telecommand and
|
||||
* Telemetry packets belong to.
|
||||
* The class hierarchy resembles the dependency between the different standards
|
||||
@ -81,7 +82,8 @@ public:
|
||||
*/
|
||||
bool isTelecommand( void );
|
||||
|
||||
void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount = 0);
|
||||
void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader,
|
||||
uint16_t apid, uint16_t sequenceCount = 0);
|
||||
/**
|
||||
* The CCSDS header provides a secondary header flag (the fifth-highest bit),
|
||||
* which is checked with this method.
|
||||
@ -167,10 +169,10 @@ public:
|
||||
* This method returns the full raw packet size.
|
||||
* @return The full size of the packet in bytes.
|
||||
*/
|
||||
uint32_t getFullSize();
|
||||
size_t getFullSize();
|
||||
|
||||
uint32_t getApidAndSequenceCount() const;
|
||||
|
||||
};
|
||||
|
||||
#endif /* SPACEPACKETBASE_H_ */
|
||||
#endif /* FSFW_TMTCPACKET_SPACEPACKETBASE_H_ */
|
||||
|
@ -7,7 +7,8 @@ class TmPacketMinimal;
|
||||
class PacketTimestampInterpreterIF {
|
||||
public:
|
||||
virtual ~PacketTimestampInterpreterIF() {}
|
||||
virtual ReturnValue_t getPacketTime(TmPacketMinimal* packet, timeval* timestamp) const = 0;
|
||||
virtual ReturnValue_t getPacketTime(TmPacketMinimal* packet,
|
||||
timeval* timestamp) const = 0;
|
||||
virtual ReturnValue_t getPacketTimeRaw(TmPacketMinimal* packet, const uint8_t** timePtr, uint32_t* size) const = 0;
|
||||
};
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
#include "../../globalfunctions/CRC.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "TcPacketBase.h"
|
||||
#include <string.h>
|
||||
|
||||
TcPacketBase::TcPacketBase(const uint8_t* set_data) :
|
||||
SpacePacketBase(set_data) {
|
||||
tcData = (TcPacketPointer*) set_data;
|
||||
#include "../../globalfunctions/CRC.h"
|
||||
#include "../../globalfunctions/arrayprinter.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
TcPacketBase::TcPacketBase(const uint8_t* setData) :
|
||||
SpacePacketBase(setData) {
|
||||
tcData = reinterpret_cast<TcPacketPointer*>(const_cast<uint8_t*>(setData));
|
||||
}
|
||||
|
||||
TcPacketBase::~TcPacketBase() {
|
||||
@ -13,28 +16,28 @@ TcPacketBase::~TcPacketBase() {
|
||||
}
|
||||
|
||||
uint8_t TcPacketBase::getService() {
|
||||
return tcData->data_field.service_type;
|
||||
return tcData->dataField.service_type;
|
||||
}
|
||||
|
||||
uint8_t TcPacketBase::getSubService() {
|
||||
return tcData->data_field.service_subtype;
|
||||
return tcData->dataField.service_subtype;
|
||||
}
|
||||
|
||||
uint8_t TcPacketBase::getAcknowledgeFlags() {
|
||||
return tcData->data_field.version_type_ack & 0b00001111;
|
||||
return tcData->dataField.version_type_ack & 0b00001111;
|
||||
}
|
||||
|
||||
const uint8_t* TcPacketBase::getApplicationData() const {
|
||||
return &tcData->data;
|
||||
return &tcData->appData;
|
||||
}
|
||||
|
||||
uint16_t TcPacketBase::getApplicationDataSize() {
|
||||
return getPacketDataLength() - sizeof(tcData->data_field) - CRC_SIZE + 1;
|
||||
return getPacketDataLength() - sizeof(tcData->dataField) - CRC_SIZE + 1;
|
||||
}
|
||||
|
||||
uint16_t TcPacketBase::getErrorControl() {
|
||||
uint16_t size = getApplicationDataSize() + CRC_SIZE;
|
||||
uint8_t* p_to_buffer = &tcData->data;
|
||||
uint8_t* p_to_buffer = &tcData->appData;
|
||||
return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1];
|
||||
}
|
||||
|
||||
@ -42,41 +45,42 @@ void TcPacketBase::setErrorControl() {
|
||||
uint32_t full_size = getFullSize();
|
||||
uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE);
|
||||
uint32_t size = getApplicationDataSize();
|
||||
(&tcData->data)[size] = (crc & 0XFF00) >> 8; // CRCH
|
||||
(&tcData->data)[size + 1] = (crc) & 0X00FF; // CRCL
|
||||
(&tcData->appData)[size] = (crc & 0XFF00) >> 8; // CRCH
|
||||
(&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL
|
||||
}
|
||||
|
||||
void TcPacketBase::setData(const uint8_t* p_Data) {
|
||||
SpacePacketBase::setData(p_Data);
|
||||
tcData = (TcPacketPointer*) p_Data;
|
||||
void TcPacketBase::setData(const uint8_t* pData) {
|
||||
SpacePacketBase::setData(pData);
|
||||
tcData = (TcPacketPointer*) pData;
|
||||
}
|
||||
|
||||
uint8_t TcPacketBase::getSecondaryHeaderFlag() {
|
||||
return (tcData->data_field.version_type_ack & 0b10000000) >> 7;
|
||||
return (tcData->dataField.version_type_ack & 0b10000000) >> 7;
|
||||
}
|
||||
|
||||
uint8_t TcPacketBase::getPusVersionNumber() {
|
||||
return (tcData->data_field.version_type_ack & 0b01110000) >> 4;
|
||||
return (tcData->dataField.version_type_ack & 0b01110000) >> 4;
|
||||
}
|
||||
|
||||
void TcPacketBase::print() {
|
||||
uint8_t * wholeData = getWholeData();
|
||||
sif::debug << "TcPacket contains: " << std::endl;
|
||||
for (uint8_t count = 0; count < getFullSize(); ++count) {
|
||||
sif::debug << std::hex << (uint16_t) wholeData[count] << " ";
|
||||
}
|
||||
sif::debug << std::dec << std::endl;
|
||||
sif::debug << "TcPacketBase::print: " << std::endl;
|
||||
arrayprinter::print(getWholeData(), getFullSize());
|
||||
}
|
||||
|
||||
void TcPacketBase::initializeTcPacket(uint16_t apid, uint16_t sequenceCount,
|
||||
uint8_t ack, uint8_t service, uint8_t subservice) {
|
||||
uint8_t ack, uint8_t service, uint8_t subservice) {
|
||||
initSpacePacketHeader(true, true, apid, sequenceCount);
|
||||
memset(&tcData->data_field, 0, sizeof(tcData->data_field));
|
||||
setPacketDataLength(sizeof(tcData->data_field) + CRC_SIZE);
|
||||
std::memset(&tcData->dataField, 0, sizeof(tcData->dataField));
|
||||
setPacketDataLength(sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1);
|
||||
//Data Field Header:
|
||||
//Set CCSDS_secondary_header_flag to 0, version number to 001 and ack to 0000
|
||||
tcData->data_field.version_type_ack = 0b00010000;
|
||||
tcData->data_field.version_type_ack |= (ack & 0x0F);
|
||||
tcData->data_field.service_type = service;
|
||||
tcData->data_field.service_subtype = subservice;
|
||||
//Set CCSDS_secondary_header_flag to 0 and version number to 001
|
||||
tcData->dataField.version_type_ack = 0b00010000;
|
||||
tcData->dataField.version_type_ack |= (ack & 0x0F);
|
||||
tcData->dataField.service_type = service;
|
||||
tcData->dataField.service_subtype = subservice;
|
||||
}
|
||||
|
||||
size_t TcPacketBase::calculateFullPacketLength(size_t appDataLen) {
|
||||
return sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) +
|
||||
appDataLen + TcPacketBase::CRC_SIZE;
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
#ifndef TCPACKETBASE_H_
|
||||
#define TCPACKETBASE_H_
|
||||
#ifndef TMTCPACKET_PUS_TCPACKETBASE_H_
|
||||
#define TMTCPACKET_PUS_TCPACKETBASE_H_
|
||||
|
||||
#include "../../tmtcpacket/SpacePacketBase.h"
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
/**
|
||||
* This struct defines a byte-wise structured PUS TC Data Field Header.
|
||||
@ -23,14 +25,14 @@ struct PUSTcDataFieldHeader {
|
||||
*/
|
||||
struct TcPacketPointer {
|
||||
CCSDSPrimaryHeader primary;
|
||||
PUSTcDataFieldHeader data_field;
|
||||
uint8_t data;
|
||||
PUSTcDataFieldHeader dataField;
|
||||
uint8_t appData;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class is the basic data handler for any ECSS PUS Telecommand packet.
|
||||
*
|
||||
* In addition to \SpacePacketBase, the class provides methods to handle
|
||||
* In addition to #SpacePacketBase, the class provides methods to handle
|
||||
* the standardized entries of the PUS TC Packet Data Field Header.
|
||||
* It does not contain the packet data itself but a pointer to the
|
||||
* data must be set on instantiation. An invalid pointer may cause
|
||||
@ -39,67 +41,38 @@ struct TcPacketPointer {
|
||||
* @ingroup tmtcpackets
|
||||
*/
|
||||
class TcPacketBase : public SpacePacketBase {
|
||||
protected:
|
||||
/**
|
||||
* A pointer to a structure which defines the data structure of
|
||||
* the packet's data.
|
||||
*
|
||||
* To be hardware-safe, all elements are of byte size.
|
||||
*/
|
||||
TcPacketPointer* tcData;
|
||||
public:
|
||||
static const uint16_t TC_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + 2);
|
||||
/**
|
||||
* With this constant for the acknowledge field responses on all levels are expected.
|
||||
*/
|
||||
static const uint8_t ACK_ALL = 0b1111;
|
||||
/**
|
||||
* With this constant for the acknowledge field a response on acceptance is expected.
|
||||
*/
|
||||
static const uint8_t ACK_ACCEPTANCE = 0b0001;
|
||||
/**
|
||||
* With this constant for the acknowledge field a response on start of execution is expected.
|
||||
*/
|
||||
static const uint8_t ACK_START = 0b0010;
|
||||
/**
|
||||
* With this constant for the acknowledge field responses on execution steps are expected.
|
||||
*/
|
||||
static const uint8_t ACK_STEP = 0b0100;
|
||||
/**
|
||||
* With this constant for the acknowledge field a response on completion is expected.
|
||||
*/
|
||||
static const uint8_t ACK_COMPLETION = 0b1000;
|
||||
/**
|
||||
* With this constant for the acknowledge field no responses are expected.
|
||||
*/
|
||||
static const uint8_t ACK_NONE = 0b000;
|
||||
static const uint16_t TC_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) +
|
||||
sizeof(PUSTcDataFieldHeader) + 2);
|
||||
|
||||
enum AckField {
|
||||
//! No acknowledgements are expected.
|
||||
ACK_NONE = 0b0000,
|
||||
//! Acknowledgements on acceptance are expected.
|
||||
ACK_ACCEPTANCE = 0b0001,
|
||||
//! Acknowledgements on start are expected.
|
||||
ACK_START = 0b0010,
|
||||
//! Acknowledgements on step are expected.
|
||||
ACK_STEP = 0b0100,
|
||||
//! Acknowledfgement on completion are expected.
|
||||
ACK_COMPLETION = 0b1000
|
||||
};
|
||||
|
||||
static constexpr uint8_t ACK_ALL = ACK_ACCEPTANCE | ACK_START | ACK_STEP |
|
||||
ACK_COMPLETION;
|
||||
|
||||
/**
|
||||
* This is the default constructor.
|
||||
* It sets its internal data pointer to the address passed and also
|
||||
* forwards the data pointer to the parent SpacePacketBase class.
|
||||
* @param set_address The position where the packet data lies.
|
||||
* @param setData The position where the packet data lies.
|
||||
*/
|
||||
TcPacketBase( const uint8_t* set_data );
|
||||
TcPacketBase( const uint8_t* setData );
|
||||
/**
|
||||
* This is the empty default destructor.
|
||||
*/
|
||||
virtual ~TcPacketBase();
|
||||
/**
|
||||
* Initializes the Tc Packet header.
|
||||
* @param apid APID used.
|
||||
* @param service PUS Service
|
||||
* @param subservice PUS Subservice
|
||||
* @param packetSubcounter Additional subcounter used.
|
||||
*/
|
||||
/**
|
||||
* Initializes the Tc Packet header.
|
||||
* @param apid APID used.
|
||||
* @param sequenceCount Sequence Count in the primary header.
|
||||
* @param ack Which acknowledeges are expected from the receiver.
|
||||
* @param service PUS Service
|
||||
* @param subservice PUS Subservice
|
||||
*/
|
||||
void initializeTcPacket(uint16_t apid, uint16_t sequenceCount, uint8_t ack, uint8_t service, uint8_t subservice);
|
||||
|
||||
/**
|
||||
* This command returns the CCSDS Secondary Header Flag.
|
||||
* It shall always be zero for PUS Packets. This is the
|
||||
@ -166,22 +139,49 @@ public:
|
||||
* current content of the packet.
|
||||
*/
|
||||
void setErrorControl();
|
||||
/**
|
||||
* With this method, the packet data pointer can be redirected to another
|
||||
* location.
|
||||
*
|
||||
* This call overwrites the parent's setData method to set both its
|
||||
* \c tc_data pointer and the parent's \c data pointer.
|
||||
*
|
||||
* @param p_data A pointer to another PUS Telecommand Packet.
|
||||
*/
|
||||
void setData( const uint8_t* p_data );
|
||||
|
||||
/**
|
||||
* This is a debugging helper method that prints the whole packet content
|
||||
* to the screen.
|
||||
*/
|
||||
void print();
|
||||
/**
|
||||
* Calculate full packet length from application data length.
|
||||
* @param appDataLen
|
||||
* @return
|
||||
*/
|
||||
static size_t calculateFullPacketLength(size_t appDataLen);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* A pointer to a structure which defines the data structure of
|
||||
* the packet's data.
|
||||
*
|
||||
* To be hardware-safe, all elements are of byte size.
|
||||
*/
|
||||
TcPacketPointer* tcData;
|
||||
|
||||
/**
|
||||
* Initializes the Tc Packet header.
|
||||
* @param apid APID used.
|
||||
* @param sequenceCount Sequence Count in the primary header.
|
||||
* @param ack Which acknowledeges are expected from the receiver.
|
||||
* @param service PUS Service
|
||||
* @param subservice PUS Subservice
|
||||
*/
|
||||
void initializeTcPacket(uint16_t apid, uint16_t sequenceCount, uint8_t ack,
|
||||
uint8_t service, uint8_t subservice);
|
||||
|
||||
/**
|
||||
* With this method, the packet data pointer can be redirected to another
|
||||
* location.
|
||||
* This call overwrites the parent's setData method to set both its
|
||||
* @c tc_data pointer and the parent's @c data pointer.
|
||||
*
|
||||
* @param p_data A pointer to another PUS Telecommand Packet.
|
||||
*/
|
||||
void setData( const uint8_t* pData );
|
||||
};
|
||||
|
||||
|
||||
#endif /* TCPACKETBASE_H_ */
|
||||
#endif /* TMTCPACKET_PUS_TCPACKETBASE_H_ */
|
||||
|
@ -1,37 +1,50 @@
|
||||
#include "TcPacketStored.h"
|
||||
#include "../../objectmanager/ObjectManagerIF.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "TcPacketStored.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
StorageManagerIF* TcPacketStored::store = nullptr;
|
||||
|
||||
TcPacketStored::TcPacketStored(store_address_t setAddress) :
|
||||
TcPacketBase(NULL), storeAddress(setAddress) {
|
||||
this->setStoreAddress(this->storeAddress);
|
||||
TcPacketBase(nullptr), storeAddress(setAddress) {
|
||||
setStoreAddress(storeAddress);
|
||||
}
|
||||
|
||||
TcPacketStored::TcPacketStored(uint16_t apid, uint8_t ack, uint8_t service,
|
||||
uint8_t subservice, uint8_t sequence_count, const uint8_t* data,
|
||||
uint32_t size) :
|
||||
TcPacketBase(NULL) {
|
||||
TcPacketStored::TcPacketStored(uint16_t apid, uint8_t service,
|
||||
uint8_t subservice, uint8_t sequenceCount, const uint8_t* data,
|
||||
size_t size, uint8_t ack) :
|
||||
TcPacketBase(nullptr) {
|
||||
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||
if (!this->checkAndSetStore()) {
|
||||
if (not this->checkAndSetStore()) {
|
||||
return;
|
||||
}
|
||||
uint8_t* p_data = NULL;
|
||||
uint8_t* pData = nullptr;
|
||||
ReturnValue_t returnValue = this->store->getFreeElement(&this->storeAddress,
|
||||
(TC_PACKET_MIN_SIZE + size), &p_data);
|
||||
(TC_PACKET_MIN_SIZE + size), &pData);
|
||||
if (returnValue != this->store->RETURN_OK) {
|
||||
sif::warning << "TcPacketStored: Could not get free element from store!"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
this->setData(p_data);
|
||||
initializeTcPacket(apid, sequence_count, ack, service, subservice);
|
||||
memcpy(&tcData->data, data, size);
|
||||
this->setData(pData);
|
||||
initializeTcPacket(apid, sequenceCount, ack, service, subservice);
|
||||
memcpy(&tcData->appData, data, size);
|
||||
this->setPacketDataLength(
|
||||
size + sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1);
|
||||
this->setErrorControl();
|
||||
}
|
||||
|
||||
TcPacketStored::TcPacketStored() :
|
||||
TcPacketBase(NULL) {
|
||||
ReturnValue_t TcPacketStored::getData(const uint8_t ** dataPtr,
|
||||
size_t* dataSize) {
|
||||
auto result = this->store->getData(storeAddress, dataPtr, dataSize);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
sif::warning << "TcPacketStored: Could not get data!" << std::endl;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TcPacketStored::TcPacketStored(): TcPacketBase(nullptr) {
|
||||
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||
this->checkAndSetStore();
|
||||
|
||||
@ -40,14 +53,14 @@ TcPacketStored::TcPacketStored() :
|
||||
ReturnValue_t TcPacketStored::deletePacket() {
|
||||
ReturnValue_t result = this->store->deleteData(this->storeAddress);
|
||||
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||
this->setData( NULL);
|
||||
this->setData(nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TcPacketStored::checkAndSetStore() {
|
||||
if (this->store == NULL) {
|
||||
if (this->store == nullptr) {
|
||||
this->store = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (this->store == NULL) {
|
||||
if (this->store == nullptr) {
|
||||
sif::error << "TcPacketStored::TcPacketStored: TC Store not found!"
|
||||
<< std::endl;
|
||||
return false;
|
||||
@ -58,17 +71,17 @@ bool TcPacketStored::checkAndSetStore() {
|
||||
|
||||
void TcPacketStored::setStoreAddress(store_address_t setAddress) {
|
||||
this->storeAddress = setAddress;
|
||||
const uint8_t* temp_data = NULL;
|
||||
const uint8_t* tempData = nullptr;
|
||||
size_t temp_size;
|
||||
ReturnValue_t status = StorageManagerIF::RETURN_FAILED;
|
||||
if (this->checkAndSetStore()) {
|
||||
status = this->store->getData(this->storeAddress, &temp_data,
|
||||
status = this->store->getData(this->storeAddress, &tempData,
|
||||
&temp_size);
|
||||
}
|
||||
if (status == StorageManagerIF::RETURN_OK) {
|
||||
this->setData(temp_data);
|
||||
this->setData(tempData);
|
||||
} else {
|
||||
this->setData(NULL);
|
||||
this->setData(nullptr);
|
||||
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
@ -78,7 +91,7 @@ store_address_t TcPacketStored::getStoreAddress() {
|
||||
}
|
||||
|
||||
bool TcPacketStored::isSizeCorrect() {
|
||||
const uint8_t* temp_data = NULL;
|
||||
const uint8_t* temp_data = nullptr;
|
||||
size_t temp_size;
|
||||
ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data,
|
||||
&temp_size);
|
||||
@ -90,8 +103,6 @@ bool TcPacketStored::isSizeCorrect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
StorageManagerIF* TcPacketStored::store = NULL;
|
||||
|
||||
TcPacketStored::TcPacketStored(const uint8_t* data, uint32_t size) :
|
||||
TcPacketBase(data) {
|
||||
if (getFullSize() != size) {
|
||||
@ -100,7 +111,7 @@ TcPacketStored::TcPacketStored(const uint8_t* data, uint32_t size) :
|
||||
if (this->checkAndSetStore()) {
|
||||
ReturnValue_t status = store->addData(&storeAddress, data, size);
|
||||
if (status != HasReturnvaluesIF::RETURN_OK) {
|
||||
this->setData(NULL);
|
||||
this->setData(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#ifndef TCPACKETSTORED_H_
|
||||
#define TCPACKETSTORED_H_
|
||||
#ifndef TMTCPACKET_PUS_TCPACKETSTORED_H_
|
||||
#define TMTCPACKET_PUS_TCPACKETSTORED_H_
|
||||
|
||||
#include "../../storagemanager/StorageManagerIF.h"
|
||||
#include "TcPacketBase.h"
|
||||
#include "../../storagemanager/StorageManagerIF.h"
|
||||
|
||||
/**
|
||||
* This class generates a ECSS PUS Telecommand packet within a given
|
||||
@ -15,26 +15,6 @@
|
||||
* @ingroup tmtcpackets
|
||||
*/
|
||||
class TcPacketStored : public TcPacketBase {
|
||||
private:
|
||||
/**
|
||||
* This is a pointer to the store all instances of the class use.
|
||||
* If the store is not yet set (i.e. \c store is NULL), every constructor
|
||||
* call tries to set it and throws an error message in case of failures.
|
||||
* The default store is objects::TC_STORE.
|
||||
*/
|
||||
static StorageManagerIF* store;
|
||||
/**
|
||||
* The address where the packet data of the object instance is stored.
|
||||
*/
|
||||
store_address_t storeAddress;
|
||||
/**
|
||||
* A helper method to check if a store is assigned to the class.
|
||||
* If not, the method tries to retrieve the store from the global
|
||||
* ObjectManager.
|
||||
* @return @li \c true if the store is linked or could be created.
|
||||
* @li \c false otherwise.
|
||||
*/
|
||||
bool checkAndSetStore();
|
||||
public:
|
||||
/**
|
||||
* This is a default constructor which does not set the data pointer.
|
||||
@ -53,18 +33,20 @@ public:
|
||||
* a new PUS Telecommand Packet is created there.
|
||||
* Packet Application Data passed in data is copied into the packet.
|
||||
* @param apid Sets the packet's APID field.
|
||||
* @param ack Set's the packet's Ack field,
|
||||
* which specifies number and size of verification packets returned
|
||||
* for this command.
|
||||
* @param service Sets the packet's Service ID field.
|
||||
* This specifies the destination service.
|
||||
* This specifies the destination service.
|
||||
* @param subservice Sets the packet's Service Subtype field.
|
||||
* This specifies the destination sub-service.
|
||||
* @param sequence_count Sets the packet's Source Sequence Count field.
|
||||
* This specifies the destination sub-service.
|
||||
* @param sequence_count Sets the packet's Source Sequence Count field.
|
||||
* @param data The data to be copied to the Application Data Field.
|
||||
* @param size The amount of data to be copied.
|
||||
* @param ack Set's the packet's Ack field, which specifies
|
||||
* number of verification packets returned
|
||||
* for this command.
|
||||
*/
|
||||
TcPacketStored( uint16_t apid, uint8_t ack, uint8_t service, uint8_t subservice, uint8_t sequence_count = 0, const uint8_t* data = NULL, uint32_t size = 0 );
|
||||
TcPacketStored(uint16_t apid, uint8_t service, uint8_t subservice,
|
||||
uint8_t sequence_count = 0, const uint8_t* data = nullptr,
|
||||
size_t size = 0, uint8_t ack = TcPacketBase::ACK_ALL);
|
||||
/**
|
||||
* Another constructor to create a TcPacket from a raw packet stream.
|
||||
* Takes the data and adds it unchecked to the TcStore.
|
||||
@ -72,10 +54,19 @@ public:
|
||||
* @param Size size of the packet.
|
||||
*/
|
||||
TcPacketStored( const uint8_t* data, uint32_t size);
|
||||
|
||||
/**
|
||||
* Getter function for the raw data.
|
||||
* @param dataPtr [out] Pointer to the data pointer to set
|
||||
* @param dataSize [out] Address of size to set.
|
||||
* @return -@c RETURN_OK if data was retrieved successfully.
|
||||
*/
|
||||
ReturnValue_t getData(const uint8_t ** dataPtr,
|
||||
size_t* dataSize);
|
||||
/**
|
||||
* This is a getter for the current store address of the packet.
|
||||
* @return The current store address. The (raw) value is \c StorageManagerIF::INVALID_ADDRESS if
|
||||
* the packet is not linked.
|
||||
* @return The current store address. The (raw) value is
|
||||
* @c StorageManagerIF::INVALID_ADDRESS if the packet is not linked.
|
||||
*/
|
||||
store_address_t getStoreAddress();
|
||||
/**
|
||||
@ -99,7 +90,28 @@ public:
|
||||
* store or size is incorrect.
|
||||
*/
|
||||
bool isSizeCorrect();
|
||||
|
||||
private:
|
||||
/**
|
||||
* This is a pointer to the store all instances of the class use.
|
||||
* If the store is not yet set (i.e. @c store is NULL), every constructor
|
||||
* call tries to set it and throws an error message in case of failures.
|
||||
* The default store is objects::TC_STORE.
|
||||
*/
|
||||
static StorageManagerIF* store;
|
||||
/**
|
||||
* The address where the packet data of the object instance is stored.
|
||||
*/
|
||||
store_address_t storeAddress;
|
||||
/**
|
||||
* A helper method to check if a store is assigned to the class.
|
||||
* If not, the method tries to retrieve the store from the global
|
||||
* ObjectManager.
|
||||
* @return @li @c true if the store is linked or could be created.
|
||||
* @li @c false otherwise.
|
||||
*/
|
||||
bool checkAndSetStore();
|
||||
};
|
||||
|
||||
|
||||
#endif /* TCPACKETSTORED_H_ */
|
||||
#endif /* TMTCPACKET_PUS_TCPACKETSTORED_H_ */
|
||||
|
@ -1,13 +1,19 @@
|
||||
#include "TmPacketBase.h"
|
||||
|
||||
#include "../../globalfunctions/CRC.h"
|
||||
#include "../../globalfunctions/arrayprinter.h"
|
||||
#include "../../objectmanager/ObjectManagerIF.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "TmPacketBase.h"
|
||||
#include "../../timemanager/CCSDSTime.h"
|
||||
#include <string.h>
|
||||
|
||||
TmPacketBase::TmPacketBase(uint8_t* set_data) :
|
||||
SpacePacketBase(set_data) {
|
||||
tm_data = (TmPacketPointer*) set_data;
|
||||
#include <cstring>
|
||||
|
||||
TimeStamperIF* TmPacketBase::timeStamper = nullptr;
|
||||
object_id_t TmPacketBase::timeStamperId = 0;
|
||||
|
||||
TmPacketBase::TmPacketBase(uint8_t* setData) :
|
||||
SpacePacketBase(setData) {
|
||||
tmData = reinterpret_cast<TmPacketPointer*>(setData);
|
||||
}
|
||||
|
||||
TmPacketBase::~TmPacketBase() {
|
||||
@ -15,25 +21,25 @@ TmPacketBase::~TmPacketBase() {
|
||||
}
|
||||
|
||||
uint8_t TmPacketBase::getService() {
|
||||
return tm_data->data_field.service_type;
|
||||
return tmData->data_field.service_type;
|
||||
}
|
||||
|
||||
uint8_t TmPacketBase::getSubService() {
|
||||
return tm_data->data_field.service_subtype;
|
||||
return tmData->data_field.service_subtype;
|
||||
}
|
||||
|
||||
uint8_t* TmPacketBase::getSourceData() {
|
||||
return &tm_data->data;
|
||||
return &tmData->data;
|
||||
}
|
||||
|
||||
uint16_t TmPacketBase::getSourceDataSize() {
|
||||
return getPacketDataLength() - sizeof(tm_data->data_field)
|
||||
return getPacketDataLength() - sizeof(tmData->data_field)
|
||||
- CRC_SIZE + 1;
|
||||
}
|
||||
|
||||
uint16_t TmPacketBase::getErrorControl() {
|
||||
uint32_t size = getSourceDataSize() + CRC_SIZE;
|
||||
uint8_t* p_to_buffer = &tm_data->data;
|
||||
uint8_t* p_to_buffer = &tmData->data;
|
||||
return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1];
|
||||
}
|
||||
|
||||
@ -47,16 +53,12 @@ void TmPacketBase::setErrorControl() {
|
||||
|
||||
void TmPacketBase::setData(const uint8_t* p_Data) {
|
||||
SpacePacketBase::setData(p_Data);
|
||||
tm_data = (TmPacketPointer*) p_Data;
|
||||
tmData = (TmPacketPointer*) p_Data;
|
||||
}
|
||||
|
||||
void TmPacketBase::print() {
|
||||
/*uint8_t * wholeData = getWholeData();
|
||||
debug << "TmPacket contains: " << std::endl;
|
||||
for (uint8_t count = 0; count < getFullSize(); ++count ) {
|
||||
debug << std::hex << (uint16_t)wholeData[count] << " ";
|
||||
}
|
||||
debug << std::dec << std::endl;*/
|
||||
sif::debug << "TmPacketBase::print: " << std::endl;
|
||||
arrayprinter::print(getWholeData(), getFullSize());
|
||||
}
|
||||
|
||||
bool TmPacketBase::checkAndSetStamper() {
|
||||
@ -73,32 +75,36 @@ bool TmPacketBase::checkAndSetStamper() {
|
||||
|
||||
ReturnValue_t TmPacketBase::getPacketTime(timeval* timestamp) const {
|
||||
uint32_t tempSize = 0;
|
||||
return CCSDSTime::convertFromCcsds(timestamp, tm_data->data_field.time,
|
||||
&tempSize, sizeof(tm_data->data_field.time));
|
||||
return CCSDSTime::convertFromCcsds(timestamp, tmData->data_field.time,
|
||||
&tempSize, sizeof(tmData->data_field.time));
|
||||
}
|
||||
|
||||
uint8_t* TmPacketBase::getPacketTimeRaw() const{
|
||||
return tm_data->data_field.time;
|
||||
return tmData->data_field.time;
|
||||
|
||||
}
|
||||
|
||||
void TmPacketBase::initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packetSubcounter) {
|
||||
void TmPacketBase::initializeTmPacket(uint16_t apid, uint8_t service,
|
||||
uint8_t subservice, uint8_t packetSubcounter) {
|
||||
//Set primary header:
|
||||
initSpacePacketHeader(false, true, apid);
|
||||
//Set data Field Header:
|
||||
//First, set to zero.
|
||||
memset(&tm_data->data_field, 0, sizeof(tm_data->data_field));
|
||||
//Set CCSDS_secondary header flag to 0, version number to 001 and ack to 0000
|
||||
memset(&tmData->data_field, 0, sizeof(tmData->data_field));
|
||||
|
||||
// NOTE: In PUS-C, the PUS Version is 2 and specified for the first 4 bits.
|
||||
// The other 4 bits of the first byte are the spacecraft time reference status
|
||||
// To change to PUS-C, set 0b00100000
|
||||
tm_data->data_field.version_type_ack = 0b00010000;
|
||||
tm_data->data_field.service_type = service;
|
||||
tm_data->data_field.service_subtype = subservice;
|
||||
tm_data->data_field.subcounter = packetSubcounter;
|
||||
// The other 4 bits of the first byte are the spacecraft time reference
|
||||
// status. To change to PUS-C, set 0b00100000.
|
||||
// Set CCSDS_secondary header flag to 0, version number to 001 and ack
|
||||
// to 0000
|
||||
tmData->data_field.version_type_ack = 0b00010000;
|
||||
tmData->data_field.service_type = service;
|
||||
tmData->data_field.service_subtype = subservice;
|
||||
tmData->data_field.subcounter = packetSubcounter;
|
||||
//Timestamp packet
|
||||
if (checkAndSetStamper()) {
|
||||
timeStamper->addTimeStamp(tm_data->data_field.time, sizeof(tm_data->data_field.time));
|
||||
timeStamper->addTimeStamp(tmData->data_field.time,
|
||||
sizeof(tmData->data_field.time));
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,9 +112,6 @@ void TmPacketBase::setSourceDataSize(uint16_t size) {
|
||||
setPacketDataLength(size + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1);
|
||||
}
|
||||
|
||||
uint32_t TmPacketBase::getTimestampSize() const {
|
||||
return sizeof(tm_data->data_field.time);
|
||||
size_t TmPacketBase::getTimestampSize() const {
|
||||
return sizeof(tmData->data_field.time);
|
||||
}
|
||||
|
||||
TimeStamperIF* TmPacketBase::timeStamper = NULL;
|
||||
object_id_t TmPacketBase::timeStamperId = 0;
|
||||
|
@ -1,8 +1,8 @@
|
||||
#ifndef TMPACKETBASE_H_
|
||||
#define TMPACKETBASE_H_
|
||||
#ifndef TMTCPACKET_PUS_TMPACKETBASE_H_
|
||||
#define TMTCPACKET_PUS_TMPACKETBASE_H_
|
||||
|
||||
#include "../SpacePacketBase.h"
|
||||
#include "../../timemanager/TimeStamperIF.h"
|
||||
#include "../../tmtcpacket/SpacePacketBase.h"
|
||||
#include "../../timemanager/Clock.h"
|
||||
#include "../../objectmanager/SystemObjectIF.h"
|
||||
|
||||
@ -14,7 +14,7 @@ void setStaticFrameworkObjectIds();
|
||||
* This struct defines a byte-wise structured PUS TM Data Field Header.
|
||||
* Any optional fields in the header must be added or removed here.
|
||||
* Currently, no Destination field is present, but an eigth-byte representation
|
||||
* for a time tag [TBD].
|
||||
* for a time tag.
|
||||
* @ingroup tmtcpackets
|
||||
*/
|
||||
struct PUSTmDataFieldHeader {
|
||||
@ -40,7 +40,7 @@ struct TmPacketPointer {
|
||||
/**
|
||||
* This class is the basic data handler for any ECSS PUS Telemetry packet.
|
||||
*
|
||||
* In addition to \SpacePacketBase, the class provides methods to handle
|
||||
* In addition to #SpacePacketBase, the class provides methods to handle
|
||||
* the standardized entries of the PUS TM Packet Data Field Header.
|
||||
* It does not contain the packet data itself but a pointer to the
|
||||
* data must be set on instantiation. An invalid pointer may cause
|
||||
@ -54,29 +54,27 @@ public:
|
||||
/**
|
||||
* This constant defines the minimum size of a valid PUS Telemetry Packet.
|
||||
*/
|
||||
static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + sizeof(PUSTmDataFieldHeader) + 2); //!< Minimum size of a valid PUS Telemetry Packet.
|
||||
static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048; //!< Maximum size of a TM Packet in this mission.
|
||||
static const uint8_t VERSION_NUMBER_BYTE_PUS_A = 0b00010000; //!< First byte of secondary header for PUS-A packets.
|
||||
static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) +
|
||||
sizeof(PUSTmDataFieldHeader) + 2);
|
||||
//! Maximum size of a TM Packet in this mission.
|
||||
//! TODO: Make this dependant on a config variable.
|
||||
static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048;
|
||||
//! First byte of secondary header for PUS-A packets.
|
||||
//! TODO: Maybe also support PUS-C via config?
|
||||
static const uint8_t VERSION_NUMBER_BYTE_PUS_A = 0b00010000;
|
||||
|
||||
/**
|
||||
* This is the default constructor.
|
||||
* It sets its internal data pointer to the address passed and also
|
||||
* forwards the data pointer to the parent SpacePacketBase class.
|
||||
* @param set_address The position where the packet data lies.
|
||||
*/
|
||||
TmPacketBase( uint8_t* set_data );
|
||||
TmPacketBase( uint8_t* setData );
|
||||
/**
|
||||
* This is the empty default destructor.
|
||||
*/
|
||||
virtual ~TmPacketBase();
|
||||
/**
|
||||
* Initializes the Tm Packet header.
|
||||
* Does set the timestamp (to now), but not the error control field.
|
||||
* @param apid APID used.
|
||||
* @param service PUS Service
|
||||
* @param subservice PUS Subservice
|
||||
* @param packetSubcounter Additional subcounter used.
|
||||
*/
|
||||
void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packetSubcounter);
|
||||
|
||||
/**
|
||||
* This is a getter for the packet's PUS Service ID, which is the second
|
||||
* byte of the Data Field Header.
|
||||
@ -106,11 +104,14 @@ public:
|
||||
*/
|
||||
uint16_t getSourceDataSize();
|
||||
|
||||
/**
|
||||
* In case data was filled manually (almost never the case).
|
||||
* @param size Size of source data (without CRC and data filed header!).
|
||||
*/
|
||||
void setSourceDataSize(uint16_t size);
|
||||
/**
|
||||
* With this method, the Error Control Field is updated to match the
|
||||
* current content of the packet. This method is not protected because
|
||||
* a recalculation by the user might be necessary when manipulating fields
|
||||
* like the sequence count.
|
||||
*/
|
||||
void setErrorControl();
|
||||
|
||||
/**
|
||||
* This getter returns the Error Control Field of the packet.
|
||||
*
|
||||
@ -120,28 +121,15 @@ public:
|
||||
* @return The PUS Error Control
|
||||
*/
|
||||
uint16_t getErrorControl();
|
||||
/**
|
||||
* With this method, the Error Control Field is updated to match the
|
||||
* current content of the packet.
|
||||
*/
|
||||
void setErrorControl();
|
||||
/**
|
||||
* With this method, the packet data pointer can be redirected to another
|
||||
* location.
|
||||
*
|
||||
* This call overwrites the parent's setData method to set both its
|
||||
* \c tc_data pointer and the parent's \c data pointer.
|
||||
*
|
||||
* @param p_data A pointer to another PUS Telemetry Packet.
|
||||
*/
|
||||
void setData( const uint8_t* p_Data );
|
||||
|
||||
/**
|
||||
* This is a debugging helper method that prints the whole packet content
|
||||
* to the screen.
|
||||
*/
|
||||
void print();
|
||||
/**
|
||||
* Interprets the "time"-field in the secondary header and returns it in timeval format.
|
||||
* Interprets the "time"-field in the secondary header and returns it in
|
||||
* timeval format.
|
||||
* @return Converted timestamp of packet.
|
||||
*/
|
||||
ReturnValue_t getPacketTime(timeval* timestamp) const;
|
||||
@ -151,7 +139,7 @@ public:
|
||||
*/
|
||||
uint8_t* getPacketTimeRaw() const;
|
||||
|
||||
uint32_t getTimestampSize() const;
|
||||
size_t getTimestampSize() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -160,20 +148,49 @@ protected:
|
||||
*
|
||||
* To be hardware-safe, all elements are of byte size.
|
||||
*/
|
||||
TmPacketPointer* tm_data;
|
||||
TmPacketPointer* tmData;
|
||||
/**
|
||||
* The timeStamper is responsible for adding a timestamp to the packet.
|
||||
* It is initialized lazy.
|
||||
*/
|
||||
static TimeStamperIF* timeStamper;
|
||||
//! The ID to use when looking for a time stamper.
|
||||
static object_id_t timeStamperId;
|
||||
|
||||
static object_id_t timeStamperId; //!< The ID to use when looking for a time stamper.
|
||||
/**
|
||||
* Checks if a time stamper is available and tries to set it if not.
|
||||
* @return Returns false if setting failed.
|
||||
*/
|
||||
bool checkAndSetStamper();
|
||||
/**
|
||||
* Initializes the Tm Packet header.
|
||||
* Does set the timestamp (to now), but not the error control field.
|
||||
* @param apid APID used.
|
||||
* @param service PUS Service
|
||||
* @param subservice PUS Subservice
|
||||
* @param packetSubcounter Additional subcounter used.
|
||||
*/
|
||||
void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice,
|
||||
uint8_t packetSubcounter);
|
||||
|
||||
/**
|
||||
* With this method, the packet data pointer can be redirected to another
|
||||
* location.
|
||||
*
|
||||
* This call overwrites the parent's setData method to set both its
|
||||
* @c tc_data pointer and the parent's @c data pointer.
|
||||
*
|
||||
* @param p_data A pointer to another PUS Telemetry Packet.
|
||||
*/
|
||||
void setData( const uint8_t* pData );
|
||||
|
||||
/**
|
||||
* In case data was filled manually (almost never the case).
|
||||
* @param size Size of source data (without CRC and data filed header!).
|
||||
*/
|
||||
void setSourceDataSize(uint16_t size);
|
||||
|
||||
/**
|
||||
* Checks if a time stamper is available and tries to set it if not.
|
||||
* @return Returns false if setting failed.
|
||||
*/
|
||||
bool checkAndSetStamper();
|
||||
};
|
||||
|
||||
|
||||
#endif /* TMPACKETBASE_H_ */
|
||||
#endif /* TMTCPACKET_PUS_TMPACKETBASE_H_ */
|
||||
|
@ -1,11 +1,16 @@
|
||||
#include "TmPacketStored.h"
|
||||
|
||||
#include "../../objectmanager/ObjectManagerIF.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "TmPacketStored.h"
|
||||
#include "../../tmtcservices/TmTcMessage.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
StorageManagerIF *TmPacketStored::store = nullptr;
|
||||
InternalErrorReporterIF *TmPacketStored::internalErrorReporter = nullptr;
|
||||
|
||||
TmPacketStored::TmPacketStored(store_address_t setAddress) :
|
||||
TmPacketBase(NULL), storeAddress(setAddress) {
|
||||
TmPacketBase(nullptr), storeAddress(setAddress) {
|
||||
setStoreAddress(storeAddress);
|
||||
}
|
||||
|
||||
@ -14,10 +19,10 @@ TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service,
|
||||
uint32_t size, const uint8_t *headerData, uint32_t headerSize) :
|
||||
TmPacketBase(NULL) {
|
||||
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||
if (!checkAndSetStore()) {
|
||||
if (not checkAndSetStore()) {
|
||||
return;
|
||||
}
|
||||
uint8_t *pData = NULL;
|
||||
uint8_t *pData = nullptr;
|
||||
ReturnValue_t returnValue = store->getFreeElement(&storeAddress,
|
||||
(TmPacketBase::TM_PACKET_MIN_SIZE + size + headerSize), &pData);
|
||||
|
||||
@ -38,7 +43,7 @@ TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service,
|
||||
SerializeIF *header) :
|
||||
TmPacketBase(NULL) {
|
||||
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||
if (!checkAndSetStore()) {
|
||||
if (not checkAndSetStore()) {
|
||||
return;
|
||||
}
|
||||
size_t sourceDataSize = 0;
|
||||
@ -77,29 +82,29 @@ store_address_t TmPacketStored::getStoreAddress() {
|
||||
void TmPacketStored::deletePacket() {
|
||||
store->deleteData(storeAddress);
|
||||
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||
setData(NULL);
|
||||
setData(nullptr);
|
||||
}
|
||||
|
||||
void TmPacketStored::setStoreAddress(store_address_t setAddress) {
|
||||
storeAddress = setAddress;
|
||||
const uint8_t* temp_data = NULL;
|
||||
size_t temp_size;
|
||||
if (!checkAndSetStore()) {
|
||||
const uint8_t* tempData = nullptr;
|
||||
size_t tempSize;
|
||||
if (not checkAndSetStore()) {
|
||||
return;
|
||||
}
|
||||
ReturnValue_t status = store->getData(storeAddress, &temp_data, &temp_size);
|
||||
ReturnValue_t status = store->getData(storeAddress, &tempData, &tempSize);
|
||||
if (status == StorageManagerIF::RETURN_OK) {
|
||||
setData(temp_data);
|
||||
setData(tempData);
|
||||
} else {
|
||||
setData(NULL);
|
||||
setData(nullptr);
|
||||
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
bool TmPacketStored::checkAndSetStore() {
|
||||
if (store == NULL) {
|
||||
if (store == nullptr) {
|
||||
store = objectManager->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if (store == NULL) {
|
||||
if (store == nullptr) {
|
||||
sif::error << "TmPacketStored::TmPacketStored: TM Store not found!"
|
||||
<< std::endl;
|
||||
return false;
|
||||
@ -108,12 +113,9 @@ bool TmPacketStored::checkAndSetStore() {
|
||||
return true;
|
||||
}
|
||||
|
||||
StorageManagerIF *TmPacketStored::store = NULL;
|
||||
InternalErrorReporterIF *TmPacketStored::internalErrorReporter = NULL;
|
||||
|
||||
ReturnValue_t TmPacketStored::sendPacket(MessageQueueId_t destination,
|
||||
MessageQueueId_t sentFrom, bool doErrorReporting) {
|
||||
if (getWholeData() == NULL) {
|
||||
if (getWholeData() == nullptr) {
|
||||
//SHOULDDO: More decent code.
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
@ -133,11 +135,11 @@ ReturnValue_t TmPacketStored::sendPacket(MessageQueueId_t destination,
|
||||
}
|
||||
|
||||
void TmPacketStored::checkAndReportLostTm() {
|
||||
if (internalErrorReporter == NULL) {
|
||||
if (internalErrorReporter == nullptr) {
|
||||
internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
|
||||
objects::INTERNAL_ERROR_REPORTER);
|
||||
}
|
||||
if (internalErrorReporter != NULL) {
|
||||
if (internalErrorReporter != nullptr) {
|
||||
internalErrorReporter->lostTm();
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
#ifndef TMPACKETSTORED_H_
|
||||
#define TMPACKETSTORED_H_
|
||||
#ifndef TMTCPACKET_PUS_TMPACKETSTORED_H_
|
||||
#define TMTCPACKET_PUS_TMPACKETSTORED_H_
|
||||
|
||||
#include "TmPacketBase.h"
|
||||
|
||||
#include "../../serialize/SerializeIF.h"
|
||||
#include "../../storagemanager/StorageManagerIF.h"
|
||||
#include "TmPacketBase.h"
|
||||
#include "../../internalError/InternalErrorReporterIF.h"
|
||||
#include "../../ipc/MessageQueueSenderIF.h"
|
||||
|
||||
@ -18,31 +19,6 @@
|
||||
* @ingroup tmtcpackets
|
||||
*/
|
||||
class TmPacketStored : public TmPacketBase {
|
||||
private:
|
||||
/**
|
||||
* This is a pointer to the store all instances of the class use.
|
||||
* If the store is not yet set (i.e. \c store is NULL), every constructor
|
||||
* call tries to set it and throws an error message in case of failures.
|
||||
* The default store is objects::TM_STORE.
|
||||
*/
|
||||
static StorageManagerIF* store;
|
||||
|
||||
static InternalErrorReporterIF *internalErrorReporter;
|
||||
|
||||
/**
|
||||
* The address where the packet data of the object instance is stored.
|
||||
*/
|
||||
store_address_t storeAddress;
|
||||
/**
|
||||
* A helper method to check if a store is assigned to the class.
|
||||
* If not, the method tries to retrieve the store from the global
|
||||
* ObjectManager.
|
||||
* @return @li \c true if the store is linked or could be created.
|
||||
* @li \c false otherwise.
|
||||
*/
|
||||
bool checkAndSetStore();
|
||||
|
||||
void checkAndReportLostTm();
|
||||
public:
|
||||
/**
|
||||
* This is a default constructor which does not set the data pointer.
|
||||
@ -52,28 +28,38 @@ public:
|
||||
/**
|
||||
* With this constructor, new space is allocated in the packet store and
|
||||
* a new PUS Telemetry Packet is created there.
|
||||
* Packet Application Data passed in data is copied into the packet. The Application data is
|
||||
* passed in two parts, first a header, then a data field. This allows building a Telemetry
|
||||
* Packet from two separate data sources.
|
||||
* Packet Application Data passed in data is copied into the packet.
|
||||
* The Application data is passed in two parts, first a header, then a
|
||||
* data field. This allows building a Telemetry Packet from two separate
|
||||
* data sources.
|
||||
* @param apid Sets the packet's APID field.
|
||||
* @param service Sets the packet's Service ID field.
|
||||
* This specifies the source service.
|
||||
* @param subservice Sets the packet's Service Subtype field.
|
||||
* This specifies the source sub-service.
|
||||
* @param packet_counter Sets the Packet counter field of this packet
|
||||
* @param data The payload data to be copied to the Application Data Field
|
||||
* @param data The payload data to be copied to the
|
||||
* Application Data Field
|
||||
* @param size The amount of data to be copied.
|
||||
* @param headerData The header Data of the Application field; will be copied in front of data
|
||||
* @param headerData The header Data of the Application field,
|
||||
* will be copied in front of data
|
||||
* @param headerSize The size of the headerDataF
|
||||
*/
|
||||
TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packet_counter = 0, const uint8_t* data = NULL, uint32_t size = 0, const uint8_t* headerData = NULL, uint32_t headerSize = 0);
|
||||
TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice,
|
||||
uint8_t packet_counter = 0, const uint8_t* data = nullptr,
|
||||
uint32_t size = 0, const uint8_t* headerData = nullptr,
|
||||
uint32_t headerSize = 0);
|
||||
/**
|
||||
* Another ctor to directly pass structured content and header data to the packet to avoid additional buffers.
|
||||
* Another ctor to directly pass structured content and header data to the
|
||||
* packet to avoid additional buffers.
|
||||
*/
|
||||
TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packet_counter, SerializeIF* content, SerializeIF* header = NULL);
|
||||
TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice,
|
||||
uint8_t packet_counter, SerializeIF* content,
|
||||
SerializeIF* header = nullptr);
|
||||
/**
|
||||
* This is a getter for the current store address of the packet.
|
||||
* @return The current store address. The (raw) value is \c StorageManagerIF::INVALID_ADDRESS if
|
||||
* @return The current store address. The (raw) value is
|
||||
* @c StorageManagerIF::INVALID_ADDRESS if
|
||||
* the packet is not linked.
|
||||
*/
|
||||
store_address_t getStoreAddress();
|
||||
@ -89,8 +75,34 @@ public:
|
||||
*/
|
||||
void setStoreAddress( store_address_t setAddress );
|
||||
|
||||
ReturnValue_t sendPacket( MessageQueueId_t destination, MessageQueueId_t sentFrom, bool doErrorReporting = true );
|
||||
ReturnValue_t sendPacket( MessageQueueId_t destination,
|
||||
MessageQueueId_t sentFrom, bool doErrorReporting = true );
|
||||
private:
|
||||
/**
|
||||
* This is a pointer to the store all instances of the class use.
|
||||
* If the store is not yet set (i.e. @c store is NULL), every constructor
|
||||
* call tries to set it and throws an error message in case of failures.
|
||||
* The default store is objects::TM_STORE.
|
||||
*/
|
||||
static StorageManagerIF* store;
|
||||
|
||||
static InternalErrorReporterIF *internalErrorReporter;
|
||||
|
||||
/**
|
||||
* The address where the packet data of the object instance is stored.
|
||||
*/
|
||||
store_address_t storeAddress;
|
||||
/**
|
||||
* A helper method to check if a store is assigned to the class.
|
||||
* If not, the method tries to retrieve the store from the global
|
||||
* ObjectManager.
|
||||
* @return @li @c true if the store is linked or could be created.
|
||||
* @li @c false otherwise.
|
||||
*/
|
||||
bool checkAndSetStore();
|
||||
|
||||
void checkAndReportLostTm();
|
||||
};
|
||||
|
||||
|
||||
#endif /* TMPACKETSTORED_H_ */
|
||||
#endif /* TMTCPACKET_PUS_TMPACKETSTORED_H_ */
|
||||
|
59
unittest/README.md
Normal file
59
unittest/README.md
Normal file
@ -0,0 +1,59 @@
|
||||
## FSFW Testing
|
||||
This repository contains testing and unit testing components.
|
||||
|
||||
[Catch2](https://github.com/catchorg/Catch2) has been used as a framework,
|
||||
and these unit tests can only be run on a linux host machine.
|
||||
The makefile with default settings creates the unit test binary which can be
|
||||
run in the terminal or in eclipse.
|
||||
|
||||
### Instructions
|
||||
|
||||
To run the fsfw unittests in the project, perform following steps:
|
||||
|
||||
1. Copy the testcfg folder the project root (folder containing the FSFW).
|
||||
2. There is a makefile inside the testcfg folder which can be used to have
|
||||
a starting point to compile the unit tests. Copy that Makefile to the project
|
||||
root
|
||||
3. Create a folder named catch2 (can have other name which requires Makefile
|
||||
adaption) and copy the Catch2 header files there (NOTE: CMake support
|
||||
not enabled yet!)
|
||||
|
||||
### Eclipse CDT settings
|
||||
|
||||
The default eclipse terminal has issues displaying the colors used
|
||||
when running the unit test binary by catch2. To fix this issue,
|
||||
install the ANSI Escape In Console package from the eclipse marketplace.
|
||||
|
||||
### GCOV integration
|
||||
|
||||
GCOV has been integrated as a code coverage tool.
|
||||
It can be enabled by adding `GCOV=1` to the build process as an additional argument.
|
||||
Coverage data will be provided in form of .gcno and .gcda files.
|
||||
These can be displayed in eclipse by looking
|
||||
for a .gcno or .gcda file in the \_obj folder, double-clicking it
|
||||
and picking the right source-binary. This will generate
|
||||
information about which lines of a file have run, provided it is open in
|
||||
eclipse.
|
||||
|
||||
### LCOV integration
|
||||
|
||||
The files generated by GCOV can also be processed by the tool LCOV.
|
||||
On ubuntu, the tool can be installed with the following command:
|
||||
|
||||
```sh
|
||||
sudo apt-get install lcov
|
||||
````
|
||||
|
||||
After that, the tool can be run by building the unit tests with `GCOV=1`,
|
||||
running them at least one time and then executing the `lcov.sh` script.
|
||||
|
||||
### Adding unit tests
|
||||
|
||||
The catch unit tests are located in unittest/testfw. To add new unit tests,
|
||||
add them to the UnitTestCatch.cpp file or add a new source file which
|
||||
includes catch.hpp.
|
||||
|
||||
For writing basics tests, the [assertion documentation](https://github.com/catchorg/Catch2/blob/master/docs/assertions.md#top)
|
||||
or the existing examples are a good guideliens.
|
||||
For more advanced tests, refer to the [catch2 documentation](https://github.com/catchorg/Catch2/blob/master/docs/Readme.md#top).
|
||||
|
11
unittest/core/CatchDefinitions.cpp
Normal file
11
unittest/core/CatchDefinitions.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "CatchDefinitions.h"
|
||||
#include <fsfw/objectmanager/ObjectManagerIF.h>
|
||||
|
||||
StorageManagerIF* tglob::getIpcStoreHandle() {
|
||||
if(objectManager != nullptr) {
|
||||
return objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
} else {
|
||||
sif::error << "Global object manager uninitialized" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
21
unittest/core/CatchDefinitions.h
Normal file
21
unittest/core/CatchDefinitions.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef FSFW_UNITTEST_CORE_CATCHDEFINITIONS_H_
|
||||
#define FSFW_UNITTEST_CORE_CATCHDEFINITIONS_H_
|
||||
|
||||
#include <fsfw/ipc/messageQueueDefinitions.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
#include <fsfw/storagemanager/StorageManagerIF.h>
|
||||
|
||||
namespace retval {
|
||||
static constexpr int CATCH_OK = static_cast<int>(HasReturnvaluesIF::RETURN_OK);
|
||||
static constexpr int CATCH_FAILED = static_cast<int>(HasReturnvaluesIF::RETURN_FAILED);
|
||||
}
|
||||
|
||||
namespace tconst {
|
||||
static constexpr MessageQueueId_t testQueueId = 42;
|
||||
}
|
||||
|
||||
namespace tglob {
|
||||
StorageManagerIF* getIpcStoreHandle();
|
||||
}
|
||||
|
||||
#endif /* FSFW_UNITTEST_CORE_CATCHDEFINITIONS_H_ */
|
31
unittest/core/CatchRunner.cpp
Normal file
31
unittest/core/CatchRunner.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file CatchSource.cpp
|
||||
* @brief Source file to compile catch framework.
|
||||
* @details All tests should be written in other files.
|
||||
* For eclipse console output, install ANSI Escape in Console
|
||||
* from the eclipse market place to get colored characters.
|
||||
*/
|
||||
|
||||
#ifndef NO_UNIT_TEST_FRAMEWORK
|
||||
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#if CUSTOM_UNITTEST_RUNNER == 0
|
||||
|
||||
extern int customSetup();
|
||||
|
||||
int main( int argc, char* argv[] ) {
|
||||
customSetup();
|
||||
|
||||
// Catch internal function call
|
||||
int result = Catch::Session().run( argc, argv );
|
||||
|
||||
// global clean-up
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
42
unittest/core/CatchSetup.cpp
Normal file
42
unittest/core/CatchSetup.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "CatchDefinitions.h"
|
||||
|
||||
#include <testcfg/cdatapool/dataPoolInit.h>
|
||||
#include <testcfg/objects/Factory.h>
|
||||
|
||||
|
||||
#ifdef GCOV
|
||||
#include <gcov.h>
|
||||
#endif
|
||||
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
#include "../../objectmanager/ObjectManagerIF.h"
|
||||
#include "../../storagemanager/StorageManagerIF.h"
|
||||
#include "../../datapool/DataPool.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
|
||||
|
||||
/* Global instantiations normally done in main.cpp */
|
||||
/* Initialize Data Pool */
|
||||
//namespace glob {
|
||||
DataPool dataPool(datapool::dataPoolInit);
|
||||
//}
|
||||
|
||||
|
||||
namespace sif {
|
||||
/* Set up output streams */
|
||||
ServiceInterfaceStream debug("DEBUG");
|
||||
ServiceInterfaceStream info("INFO");
|
||||
ServiceInterfaceStream error("ERROR");
|
||||
ServiceInterfaceStream warning("WARNING");
|
||||
}
|
||||
|
||||
/* Global object manager */
|
||||
ObjectManagerIF *objectManager;
|
||||
|
||||
int customSetup() {
|
||||
// global setup
|
||||
objectManager = new ObjectManager(Factory::produce);
|
||||
objectManager -> initialize();
|
||||
return 0;
|
||||
}
|
||||
|
3
unittest/core/core.mk
Normal file
3
unittest/core/core.mk
Normal file
@ -0,0 +1,3 @@
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp)
|
||||
|
||||
INCLUDES += $(CURRENTPATH)
|
10
unittest/core/printChar.cpp
Normal file
10
unittest/core/printChar.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include <fsfw/unittest/core/printChar.h>
|
||||
#include <cstdio>
|
||||
|
||||
void printChar(const char* character, bool errStream) {
|
||||
if(errStream) {
|
||||
std::putc(*character, stderr);
|
||||
return;
|
||||
}
|
||||
std::putc(*character, stdout);
|
||||
}
|
8
unittest/core/printChar.h
Normal file
8
unittest/core/printChar.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef FSFW_UNITTEST_CORE_PRINTCHAR_H_
|
||||
#define FSFW_UNITTEST_CORE_PRINTCHAR_H_
|
||||
|
||||
|
||||
extern "C" void printChar(const char*, bool errStream);
|
||||
|
||||
|
||||
#endif /* FSFW_UNITTEST_CORE_PRINTCHAR_H_ */
|
27
unittest/internal/InternalUnitTester.cpp
Normal file
27
unittest/internal/InternalUnitTester.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "InternalUnitTester.h"
|
||||
#include "UnittDefinitions.h"
|
||||
|
||||
#include "osal/IntTestMq.h"
|
||||
#include "osal/IntTestSemaphore.h"
|
||||
#include "osal/IntTestMutex.h"
|
||||
#include "serialize/IntTestSerialization.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
InternalUnitTester::InternalUnitTester() {}
|
||||
|
||||
InternalUnitTester::~InternalUnitTester() {}
|
||||
|
||||
ReturnValue_t InternalUnitTester::performTests() {
|
||||
sif::info << "Running internal unit tests.." << std::endl;
|
||||
testserialize::test_serialization();
|
||||
testmq::testMq();
|
||||
testsemaph::testBinSemaph();
|
||||
testsemaph::testCountingSemaph();
|
||||
testmutex::testMutex();
|
||||
sif::info << "Internal unit tests finished." << std::endl;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
|
29
unittest/internal/InternalUnitTester.h
Normal file
29
unittest/internal/InternalUnitTester.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef FRAMEWORK_TEST_UNITTESTCLASS_H_
|
||||
#define FRAMEWORK_TEST_UNITTESTCLASS_H_
|
||||
|
||||
#include "UnittDefinitions.h"
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
/**
|
||||
* @brief Can be used for internal testing, for example for hardware specific
|
||||
* tests which can not be run on a host-machine.
|
||||
*
|
||||
* TODO: A lot of ways to improve this class. A way for tests to subscribe
|
||||
* in this central class would be nice. Right now, this is the class
|
||||
* which simply calls all other tests from other files manually.
|
||||
* Maybe there is a better way..
|
||||
*/
|
||||
class InternalUnitTester: public HasReturnvaluesIF {
|
||||
public:
|
||||
InternalUnitTester();
|
||||
virtual~ InternalUnitTester();
|
||||
|
||||
/**
|
||||
* Some function which calls all other tests
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t performTests();
|
||||
};
|
||||
|
||||
|
||||
#endif /* FRAMEWORK_TEST_UNITTESTCLASS_H_ */
|
7
unittest/internal/UnittDefinitions.cpp
Normal file
7
unittest/internal/UnittDefinitions.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include <fsfw/unittest/internal/UnittDefinitions.h>
|
||||
|
||||
ReturnValue_t unitt::put_error(std::string errorId) {
|
||||
sif::error << "Unit Tester error: Failed at test ID "
|
||||
<< errorId << "\n" << std::flush;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
33
unittest/internal/UnittDefinitions.h
Normal file
33
unittest/internal/UnittDefinitions.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef UNITTEST_INTERNAL_UNITTDEFINITIONS_H_
|
||||
#define UNITTEST_INTERNAL_UNITTDEFINITIONS_H_
|
||||
|
||||
#include "../../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace tv {
|
||||
// POD test values
|
||||
static const bool tv_bool = true;
|
||||
static const uint8_t tv_uint8 {5};
|
||||
static const uint16_t tv_uint16 {283};
|
||||
static const uint32_t tv_uint32 {929221};
|
||||
static const uint64_t tv_uint64 {2929329429};
|
||||
|
||||
static const int8_t tv_int8 {-16};
|
||||
static const int16_t tv_int16 {-829};
|
||||
static const int32_t tv_int32 {-2312};
|
||||
|
||||
static const float tv_float {8.2149214};
|
||||
static const float tv_sfloat = {-922.2321321};
|
||||
static const double tv_double {9.2132142141e8};
|
||||
static const double tv_sdouble {-2.2421e19};
|
||||
}
|
||||
|
||||
namespace unitt {
|
||||
ReturnValue_t put_error(std::string errorId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ */
|
3
unittest/internal/internal.mk
Normal file
3
unittest/internal/internal.mk
Normal file
@ -0,0 +1,3 @@
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/osal/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/serialize/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp)
|
52
unittest/internal/osal/IntTestMq.cpp
Normal file
52
unittest/internal/osal/IntTestMq.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include <fsfw/ipc/MessageQueueIF.h>
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/unittest/internal/osal/IntTestMq.h>
|
||||
#include <fsfw/unittest/internal/UnittDefinitions.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
using retval = HasReturnvaluesIF;
|
||||
|
||||
void testmq::testMq() {
|
||||
std::string id = "[testMq]";
|
||||
MessageQueueIF* testSenderMq =
|
||||
QueueFactory::instance()->createMessageQueue(1);
|
||||
MessageQueueId_t testSenderMqId = testSenderMq->getId();
|
||||
|
||||
MessageQueueIF* testReceiverMq =
|
||||
QueueFactory::instance()->createMessageQueue(1);
|
||||
MessageQueueId_t testReceiverMqId = testReceiverMq->getId();
|
||||
std::array<uint8_t, 20> testData { 0 };
|
||||
testData[0] = 42;
|
||||
MessageQueueMessage testMessage(testData.data(), 1);
|
||||
testSenderMq->setDefaultDestination(testReceiverMqId);
|
||||
|
||||
|
||||
auto result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||
if(result != retval::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
MessageQueueMessage recvMessage;
|
||||
result = testReceiverMq->receiveMessage(&recvMessage);
|
||||
if(result != retval::RETURN_OK or recvMessage.getData()[0] != 42) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||
if(result != retval::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
MessageQueueId_t senderId = 0;
|
||||
result = testReceiverMq->receiveMessage(&recvMessage,&senderId);
|
||||
if(result != retval::RETURN_OK or recvMessage.getData()[0] != 42) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
if(senderId != testSenderMqId) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
senderId = testReceiverMq->getLastPartner();
|
||||
if(senderId != testSenderMqId) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
}
|
9
unittest/internal/osal/IntTestMq.h
Normal file
9
unittest/internal/osal/IntTestMq.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef UNITTEST_INTERNAL_INTESTMQ_H_
|
||||
#define UNITTEST_INTERNAL_INTESTMQ_H_
|
||||
|
||||
namespace testmq {
|
||||
void testMq();
|
||||
}
|
||||
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_INTESTMQ_H_ */
|
42
unittest/internal/osal/IntTestMutex.cpp
Normal file
42
unittest/internal/osal/IntTestMutex.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "IntTestMutex.h"
|
||||
|
||||
#include <fsfw/ipc/MutexFactory.h>
|
||||
#include <unittest/internal/UnittDefinitions.h>
|
||||
|
||||
#if defined(hosted)
|
||||
#include <fsfw/osal/hosted/Mutex.h>
|
||||
#include <thread>
|
||||
#include <future>
|
||||
#endif
|
||||
|
||||
|
||||
void testmutex::testMutex() {
|
||||
std::string id = "[testMutex]";
|
||||
MutexIF* mutex = MutexFactory::instance()->createMutex();
|
||||
auto result = mutex->lockMutex(MutexIF::POLLING);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
// timed_mutex from the C++ library specifies undefined behaviour if
|
||||
// the timed mutex is locked twice from the same thread.
|
||||
#if defined(hosted)
|
||||
// hold on, this actually worked ? :-D This calls the function from
|
||||
// another thread and stores the returnvalue in a future.
|
||||
auto future = std::async(&MutexIF::lockMutex, mutex, 1);
|
||||
result = future.get();
|
||||
#else
|
||||
result = mutex->lockMutex(MutexIF::TimeoutType::WAITING, 1);
|
||||
#endif
|
||||
if(result != MutexIF::MUTEX_TIMEOUT) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
result = mutex->unlockMutex();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
result = mutex->unlockMutex();
|
||||
if(result != MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
10
unittest/internal/osal/IntTestMutex.h
Normal file
10
unittest/internal/osal/IntTestMutex.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef UNITTEST_INTERNAL_INTTESTMUTEX_H_
|
||||
#define UNITTEST_INTERNAL_INTTESTMUTEX_H_
|
||||
|
||||
namespace testmutex {
|
||||
void testMutex();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_INTTESTMUTEX_H_ */
|
160
unittest/internal/osal/IntTestSemaphore.cpp
Normal file
160
unittest/internal/osal/IntTestSemaphore.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#include "IntTestSemaphore.h"
|
||||
#include <fsfw/tasks/SemaphoreFactory.h>
|
||||
#include <unittest/internal/UnittDefinitions.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <fsfw/timemanager/Stopwatch.h>
|
||||
|
||||
|
||||
void testsemaph::testBinSemaph() {
|
||||
std::string id = "[BinSemaphore]";
|
||||
SemaphoreIF* binSemaph =
|
||||
SemaphoreFactory::instance()->createBinarySemaphore();
|
||||
if(binSemaph == nullptr) {
|
||||
return;
|
||||
}
|
||||
testBinSemaphoreImplementation(binSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
|
||||
#if defined(freeRTOS)
|
||||
SemaphoreIF* binSemaphUsingTask =
|
||||
SemaphoreFactory::instance()->createBinarySemaphore(1);
|
||||
testBinSemaphoreImplementation(binSemaphUsingTask, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(binSemaphUsingTask);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void testsemaph::testCountingSemaph() {
|
||||
std::string id = "[CountingSemaph]";
|
||||
{
|
||||
// First test: create a binary semaphore by using a counting semaphore.
|
||||
SemaphoreIF* countingSemaph = SemaphoreFactory::instance()->
|
||||
createCountingSemaphore(1,1);
|
||||
if(countingSemaph == nullptr) {
|
||||
return;
|
||||
}
|
||||
testBinSemaphoreImplementation(countingSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||
#if defined(freeRTOS)
|
||||
countingSemaph = SemaphoreFactory::instance()->
|
||||
createCountingSemaphore(1, 1, 1);
|
||||
testBinSemaphoreImplementation(countingSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
// Second test: counting semaphore with count 3 and init count of 3.
|
||||
SemaphoreIF* countingSemaph = SemaphoreFactory::instance()->
|
||||
createCountingSemaphore(3,3);
|
||||
testCountingSemaphImplementation(countingSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||
#if defined(freeRTOS)
|
||||
countingSemaph = SemaphoreFactory::instance()->
|
||||
createCountingSemaphore(3, 0, 1);
|
||||
uint8_t semaphCount = countingSemaph->getSemaphoreCounter();
|
||||
if(semaphCount != 0) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
// release 3 times in a row
|
||||
for(int i = 0; i < 3; i++) {
|
||||
auto result = countingSemaph->release();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
testCountingSemaphImplementation(countingSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void testsemaph::testBinSemaphoreImplementation(SemaphoreIF* binSemaph,
|
||||
std::string id) {
|
||||
uint8_t semaphCount = binSemaph->getSemaphoreCounter();
|
||||
if(semaphCount != 1) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
ReturnValue_t result = binSemaph->release();
|
||||
if(result != SemaphoreIF::SEMAPHORE_NOT_OWNED) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
result = binSemaph->acquire(SemaphoreIF::BLOCKING);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
// There is not really a point in testing time related, the task
|
||||
// might get interrupted..
|
||||
{
|
||||
//Stopwatch stopwatch(false);
|
||||
result = binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10);
|
||||
//dur_millis_t time = stopwatch.stop();
|
||||
// if(abs(time - 10) > 2) {
|
||||
// sif::error << "UnitTester: Semaphore timeout measured incorrect."
|
||||
// << std::endl;
|
||||
// unitt::put_error(id);
|
||||
// }
|
||||
}
|
||||
|
||||
if(result != SemaphoreIF::SEMAPHORE_TIMEOUT) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
semaphCount = binSemaph->getSemaphoreCounter();
|
||||
if(semaphCount != 0) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
result = binSemaph->release();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
|
||||
void testsemaph::testCountingSemaphImplementation(SemaphoreIF* countingSemaph,
|
||||
std::string id) {
|
||||
// check count getter function
|
||||
uint8_t semaphCount = countingSemaph->getSemaphoreCounter();
|
||||
if(semaphCount != 3) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
ReturnValue_t result = countingSemaph->release();
|
||||
if(result != SemaphoreIF::SEMAPHORE_NOT_OWNED) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
// acquire 3 times in a row
|
||||
for(int i = 0; i < 3; i++) {
|
||||
result = countingSemaph->acquire(SemaphoreIF::BLOCKING);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Stopwatch stopwatch(false);
|
||||
// attempt to take when count is 0, measure time
|
||||
result = countingSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10);
|
||||
dur_millis_t time = stopwatch.stop();
|
||||
if(abs(time - 10) > 1) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
|
||||
if(result != SemaphoreIF::SEMAPHORE_TIMEOUT) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
// release 3 times in a row
|
||||
for(int i = 0; i < 3; i++) {
|
||||
result = countingSemaph->release();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
// assert correct full count
|
||||
if(countingSemaph->getSemaphoreCounter() != 3) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
15
unittest/internal/osal/IntTestSemaphore.h
Normal file
15
unittest/internal/osal/IntTestSemaphore.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_
|
||||
#define UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_
|
||||
class SemaphoreIF;
|
||||
#include <string>
|
||||
|
||||
namespace testsemaph {
|
||||
void testBinSemaph();
|
||||
void testBinSemaphoreImplementation(SemaphoreIF* binSemaph, std::string id);
|
||||
void testCountingSemaph();
|
||||
void testCountingSemaphImplementation(SemaphoreIF* countingSemaph,
|
||||
std::string id);
|
||||
}
|
||||
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_ */
|
230
unittest/internal/serialize/IntTestSerialization.cpp
Normal file
230
unittest/internal/serialize/IntTestSerialization.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include "IntTestSerialization.h"
|
||||
#include <fsfw/serialize/SerializeElement.h>
|
||||
#include <fsfw/serialize/SerialBufferAdapter.h>
|
||||
#include <unittest/internal/UnittDefinitions.h>
|
||||
#include <fsfw/serialize/SerializeIF.h>
|
||||
#include <array>
|
||||
|
||||
using retval = HasReturnvaluesIF;
|
||||
std::array<uint8_t, 512> testserialize::test_array = { 0 };
|
||||
|
||||
ReturnValue_t testserialize::test_serialization() {
|
||||
// Here, we test all serialization tools. First test basic cases.
|
||||
ReturnValue_t result = test_endianness_tools();
|
||||
if(result != retval::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = test_autoserialization();
|
||||
if(result != retval::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = test_serial_buffer_adapter();
|
||||
if(result != retval::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return retval::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t testserialize::test_endianness_tools() {
|
||||
std::string id = "[test_endianness_tools]";
|
||||
test_array[0] = 0;
|
||||
test_array[1] = 0;
|
||||
uint16_t two_byte_value = 1;
|
||||
size_t size = 0;
|
||||
uint8_t* p_array = test_array.data();
|
||||
SerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2,
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
// Little endian: Value one on first byte
|
||||
if(test_array[0] != 1 and test_array[1] != 0) {
|
||||
return unitt::put_error(id);
|
||||
|
||||
}
|
||||
|
||||
p_array = test_array.data();
|
||||
size = 0;
|
||||
SerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2,
|
||||
SerializeIF::Endianness::BIG);
|
||||
// Big endian: Value one on second byte
|
||||
if(test_array[0] != 0 and test_array[1] != 1) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
return retval::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t testserialize::test_autoserialization() {
|
||||
std::string id = "[test_autoserialization]";
|
||||
// Unit Test getSerializedSize
|
||||
if(SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_bool) != sizeof(tv::tv_bool) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_uint8) != sizeof(tv::tv_uint8) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_uint16) != sizeof(tv::tv_uint16) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_uint32) != sizeof(tv::tv_uint32) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_uint64) != sizeof(tv::tv_uint64) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_int8) != sizeof(tv::tv_int8) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_double) != sizeof(tv::tv_double) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_int16) != sizeof(tv::tv_int16) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_int32) != sizeof(tv::tv_int32) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_float) != sizeof(tv::tv_float))
|
||||
{
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
size_t serialized_size = 0;
|
||||
uint8_t * p_array = test_array.data();
|
||||
|
||||
SerializeAdapter::serialize(&tv::tv_bool, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_uint8, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_uint16, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_uint32, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_int8, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_int16, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_int32, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_uint64, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_float, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_double, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_sfloat, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_sdouble, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
// expected size is 1 + 1 + 2 + 4 + 1 + 2 + 4 + 8 + 4 + 8 + 4 + 8
|
||||
if(serialized_size != 47) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
p_array = test_array.data();
|
||||
size_t remaining_size = serialized_size;
|
||||
bool tv_bool;
|
||||
uint8_t tv_uint8;
|
||||
uint16_t tv_uint16;
|
||||
uint32_t tv_uint32;
|
||||
int8_t tv_int8;
|
||||
int16_t tv_int16;
|
||||
int32_t tv_int32;
|
||||
uint64_t tv_uint64;
|
||||
float tv_float;
|
||||
double tv_double;
|
||||
float tv_sfloat;
|
||||
double tv_sdouble;
|
||||
|
||||
SerializeAdapter::deSerialize(&tv_bool,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint8,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint16,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint32,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_int8,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_int16,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_int32,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint64,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_float,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_double,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_sfloat,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_sdouble,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
|
||||
if(tv_bool != tv::tv_bool or tv_uint8 != tv::tv_uint8 or
|
||||
tv_uint16 != tv::tv_uint16 or tv_uint32 != tv::tv_uint32 or
|
||||
tv_uint64 != tv::tv_uint64 or tv_int8 != tv::tv_int8 or
|
||||
tv_int16 != tv::tv_int16 or tv_int32 != tv::tv_int32)
|
||||
{
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
// These epsilon values were just guessed.. It appears to work though.
|
||||
if(abs(tv_float - tv::tv_float) > 0.0001 or
|
||||
abs(tv_double - tv::tv_double) > 0.01 or
|
||||
abs(tv_sfloat - tv::tv_sfloat) > 0.0001 or
|
||||
abs(tv_sdouble - tv::tv_sdouble) > 0.01) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
// Check overflow
|
||||
return retval::RETURN_OK;
|
||||
}
|
||||
|
||||
// TODO: Also test for constant buffers.
|
||||
ReturnValue_t testserialize::test_serial_buffer_adapter() {
|
||||
std::string id = "[test_serial_buffer_adapter]";
|
||||
|
||||
// I will skip endian swapper testing, its going to be changed anyway..
|
||||
// uint8_t tv::tv_uint8_swapped = EndianSwapper::swap(tv::tv_uint8);
|
||||
|
||||
size_t serialized_size = 0;
|
||||
uint8_t * p_array = test_array.data();
|
||||
std::array<uint8_t, 5> test_serial_buffer {5, 4, 3, 2, 1};
|
||||
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter =
|
||||
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||
test_serial_buffer.size(), false);
|
||||
uint16_t testUint16 = 16;
|
||||
|
||||
SerializeAdapter::serialize(&tv::tv_bool, &p_array,&serialized_size,
|
||||
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_serial_buffer_adapter, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&testUint16, &p_array, &serialized_size,
|
||||
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
|
||||
if(serialized_size != 8 or test_array[0] != true or test_array[1] != 5
|
||||
or test_array[2] != 4 or test_array[3] != 3 or test_array[4] != 2
|
||||
or test_array[5] != 1)
|
||||
{
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
memcpy(&testUint16, test_array.data() + 6, sizeof(testUint16));
|
||||
if(testUint16 != 16) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
// Serialize with size field
|
||||
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter2 =
|
||||
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||
test_serial_buffer.size(), true);
|
||||
serialized_size = 0;
|
||||
p_array = test_array.data();
|
||||
SerializeAdapter::serialize(&tv::tv_bool, &p_array,&serialized_size,
|
||||
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_serial_buffer_adapter2, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&testUint16, &p_array, &serialized_size,
|
||||
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
|
||||
if(serialized_size != 9 or test_array[0] != true or test_array[1] != 5
|
||||
or test_array[2] != 5 or test_array[3] != 4 or test_array[4] != 3
|
||||
or test_array[5] != 2 or test_array[6] != 1)
|
||||
{
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
memcpy(&testUint16, test_array.data() + 7, sizeof(testUint16));
|
||||
if(testUint16 != 16) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
return retval::RETURN_OK;
|
||||
}
|
15
unittest/internal/serialize/IntTestSerialization.h
Normal file
15
unittest/internal/serialize/IntTestSerialization.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_
|
||||
#define UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
#include <array>
|
||||
|
||||
namespace testserialize {
|
||||
ReturnValue_t test_serialization();
|
||||
ReturnValue_t test_endianness_tools();
|
||||
ReturnValue_t test_autoserialization();
|
||||
ReturnValue_t test_serial_buffer_adapter();
|
||||
|
||||
extern std::array<uint8_t, 512> test_array;
|
||||
}
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ */
|
3
unittest/lcov.sh
Normal file
3
unittest/lcov.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
lcov --capture --directory . --output-file coverage.info
|
||||
genhtml coverage.info --output-directory _coverage
|
46
unittest/testcfg/FSFWConfig.h
Normal file
46
unittest/testcfg/FSFWConfig.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef CONFIG_FSFWCONFIG_H_
|
||||
#define CONFIG_FSFWCONFIG_H_
|
||||
|
||||
#include <FSFWVersion.h>
|
||||
|
||||
//! 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 -DDEBUG is supplied in the build defines, there will be
|
||||
//! additional output which requires the translation files translateObjects
|
||||
//! and translateEvents (and their compiles source files)
|
||||
#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
|
||||
|
||||
|
||||
#endif /* CONFIG_FSFWCONFIG_H_ */
|
415
unittest/testcfg/Makefile-FSFW-Tests
Normal file
415
unittest/testcfg/Makefile-FSFW-Tests
Normal file
@ -0,0 +1,415 @@
|
||||
#-------------------------------------------------------------------------------
|
||||
# Makefile for FSFW Test
|
||||
#-------------------------------------------------------------------------------
|
||||
# User-modifiable options
|
||||
#-------------------------------------------------------------------------------
|
||||
# Fundamentals on the build process of C/C++ Software:
|
||||
# https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
|
||||
|
||||
# Make documentation: https://www.gnu.org/software/make/manual/make.pdf
|
||||
# Online: https://www.gnu.org/software/make/manual/make.html
|
||||
# General rules: http://make.mad-scientist.net/papers/rules-of-makefiles/#rule3
|
||||
SHELL = /bin/sh
|
||||
|
||||
# Chip & board used for compilation
|
||||
# (can be overriden by adding CHIP=chip and BOARD=board to the command-line)
|
||||
# Unit Test can only be run on host machine for now (Linux)
|
||||
FRAMEWORK_PATH = fsfw
|
||||
FILE_ROOT = $(FRAMEWORK_PATH)/unittest
|
||||
BOARD = unittest
|
||||
LINUX = 1
|
||||
OS_FSFW = linux
|
||||
CUSTOM_DEFINES += -D$(OS_FSFW)
|
||||
|
||||
# Copied from stackoverflow, can be used to differentiate between Windows
|
||||
# and Linux
|
||||
ifeq ($(OS),Windows_NT)
|
||||
CUSTOM_DEFINES += -DWIN32
|
||||
ifeq ($(PROCESSOR_ARCHITEW6432),AMD64)
|
||||
CUSTOM_DEFINES += -DAMD64
|
||||
else
|
||||
ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
|
||||
CUSTOM_DEFINES += -DAMD64
|
||||
endif
|
||||
ifeq ($(PROCESSOR_ARCHITECTURE),x86)
|
||||
CUSTOM_DEFINES += -DIA32
|
||||
endif
|
||||
endif
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
DETECTED_OS = LINUX
|
||||
CUSTOM_DEFINES += -DLINUX
|
||||
endif
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
CUSTOM_DEFINES += -DOSX
|
||||
endif
|
||||
UNAME_P := $(shell uname -p)
|
||||
ifeq ($(UNAME_P),x86_64)
|
||||
CUSTOM_DEFINES += -DAMD64
|
||||
endif
|
||||
ifneq ($(filter %86,$(UNAME_P)),)
|
||||
CUSTOM_DEFINES += -DIA32
|
||||
endif
|
||||
ifneq ($(filter arm%,$(UNAME_P)),)
|
||||
CUSTOM_DEFINES += -DARM
|
||||
endif
|
||||
endif
|
||||
|
||||
UNIT_TEST = 1
|
||||
# General folder paths
|
||||
CONFIG_PATH = $(FILE_ROOT)/config
|
||||
UNIT_TEST_PATH = $(FILE_ROOT)/tests
|
||||
CORE_PATH = $(FILE_ROOT)/core
|
||||
|
||||
# Output file basename
|
||||
BASENAME = fsfw
|
||||
BINARY_NAME := $(BASENAME)-$(BOARD)
|
||||
# Output files will be put in this directory inside
|
||||
OUTPUT_FOLDER = $(OS)
|
||||
|
||||
# Optimization level. Optimized for debugging.
|
||||
OPTIMIZATION = -O0
|
||||
|
||||
# Default debug output. Optimized for debugging.
|
||||
DEBUG_LEVEL = -g3
|
||||
|
||||
ifdef GCOV
|
||||
CUSTOM_DEFINES += -DGCOV
|
||||
endif
|
||||
|
||||
|
||||
# Output directories
|
||||
BUILDPATH = _bin
|
||||
DEPENDPATH = _dep
|
||||
OBJECTPATH = _obj
|
||||
|
||||
ifeq ($(MAKECMDGOALS),mission)
|
||||
BUILD_FOLDER = mission
|
||||
else
|
||||
BUILD_FOLDER = devel
|
||||
endif
|
||||
|
||||
DEPENDDIR = $(DEPENDPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER)
|
||||
OBJDIR = $(OBJECTPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER)
|
||||
BINDIR = $(BUILDPATH)
|
||||
|
||||
CLEANDEP = $(DEPENDPATH)/$(OUTPUT_FOLDER)
|
||||
CLEANOBJ = $(OBJECTPATH)/$(OUTPUT_FOLDER)
|
||||
CLEANBIN = $(BUILDPATH)
|
||||
#-------------------------------------------------------------------------------
|
||||
# Tools and Includes
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# Tool suffix when cross-compiling
|
||||
CROSS_COMPILE =
|
||||
|
||||
# C Compiler
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
|
||||
# C++ compiler
|
||||
CXX = $(CROSS_COMPILE)g++
|
||||
|
||||
# Additional Tools
|
||||
SIZE = $(CROSS_COMPILE)size
|
||||
STRIP = $(CROSS_COMPILE)strip
|
||||
CP = $(CROSS_COMPILE)objcopy
|
||||
|
||||
HEXCOPY = $(CP) -O ihex
|
||||
BINCOPY = $(CP) -O binary
|
||||
# files to be compiled, will be filled in by include makefiles
|
||||
# := assignment is neccessary so we get all paths right
|
||||
# https://www.gnu.org/software/make/manual/html_node/Flavors.html
|
||||
CSRC :=
|
||||
CXXSRC :=
|
||||
ASRC :=
|
||||
INCLUDES :=
|
||||
|
||||
# Directories where $(directoryname).mk files should be included from
|
||||
SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(UNIT_TEST_PATH) $(CONFIG_PATH) \
|
||||
$(CORE_PATH)
|
||||
|
||||
|
||||
I_INCLUDES += $(addprefix -I, $(INCLUDES))
|
||||
|
||||
# This is a hack from http://make.mad-scientist.net/the-eval-function/
|
||||
#
|
||||
# The problem is, that included makefiles should be aware of their relative path
|
||||
# but not need to guess or hardcode it. So we set $(CURRENTPATH) for them. If
|
||||
# we do this globally and the included makefiles want to include other makefiles as
|
||||
# well, they would overwrite $(CURRENTPATH), screwing the include after them.
|
||||
#
|
||||
# By using a for-loop with an eval'd macro, we can generate the code to include all
|
||||
# sub-makefiles (with the correct $(CURRENTPATH) set) before actually evaluating
|
||||
# (and by this possibly changing $(CURRENTPATH)) them.
|
||||
#
|
||||
# This works recursively, if an included makefile wants to include, it can safely set
|
||||
# $(SUBDIRS) (which has already been evaluated here) and do
|
||||
# "$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))"
|
||||
# $(SUBDIRS) must be relative to the project root, so to include subdir foo, set
|
||||
# $(SUBDIRS) = $(CURRENTPATH)/foo.
|
||||
define INCLUDE_FILE
|
||||
CURRENTPATH := $S
|
||||
include $(S)/$(notdir $S).mk
|
||||
endef
|
||||
$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))
|
||||
|
||||
INCLUDES += $(FILE_ROOT)
|
||||
INCLUDES += $(FILE_ROOT)/catch2/
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Source Files
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# All source files which are not includes by the .mk files are added here
|
||||
# Please ensure that no files are included by both .mk file and here !
|
||||
|
||||
# if a target is not listed in the current directory,
|
||||
# make searches in the directories specified with VPATH
|
||||
|
||||
# All C Sources included by .mk files are assigned here
|
||||
# Add the objects to sources so dependency handling works
|
||||
C_OBJECTS += $(CSRC:.c=.o)
|
||||
|
||||
# Objects built from Assembly source files
|
||||
ASM_OBJECTS = $(ASRC:.S=.o)
|
||||
|
||||
# Objects built from C++ source files
|
||||
CXX_OBJECTS += $(CXXSRC:.cpp=.o)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Build Configuration + Output
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
TARGET = Debug build.
|
||||
DEBUG_MESSAGE = Off
|
||||
OPTIMIZATION_MESSAGE = Off
|
||||
|
||||
# Define Messages
|
||||
MSG_INFO = Software: Hosted unittest \(Catch2\) for the FSFW.
|
||||
MSG_OPTIMIZATION = Optimization: $(OPTIMIZATION), $(OPTIMIZATION_MESSAGE)
|
||||
MSG_TARGET = Target Build: $(TARGET)
|
||||
MSG_DEBUG = Debug level: $(DEBUG_LEVEL), FSFW Debugging: $(DEBUG_MESSAGE)
|
||||
|
||||
MSG_LINKING = Linking:
|
||||
MSG_COMPILING = Compiling:
|
||||
MSG_ASSEMBLING = Assembling:
|
||||
MSG_DEPENDENCY = Collecting dependencies for:
|
||||
MSG_BINARY = Generate binary:
|
||||
|
||||
# See https://stackoverflow.com/questions/6687630/how-to-remove-unused-c-c-symbols-with-gcc-and-ld
|
||||
# Used to throw away unused code. Reduces code size significantly !
|
||||
# -Wl,--gc-sections: needs to be passed to the linker to throw aways unused code
|
||||
ifdef KEEP_UNUSED_CODE
|
||||
PROTOTYPE_OPTIMIZATION =
|
||||
UNUSED_CODE_REMOVAL =
|
||||
else
|
||||
PROTOTYPE_OPTIMIZATION = -ffunction-sections -fdata-sections
|
||||
UNUSED_CODE_REMOVAL = -Wl,--gc-sections
|
||||
# Link time optimization
|
||||
# See https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html for reference
|
||||
# Link time is larger and size of object files can not be retrieved
|
||||
# but resulting binary is smaller. Could be used in mission/deployment build
|
||||
# Requires -ffunction-section in linker call
|
||||
LINK_TIME_OPTIMIZATION = -flto
|
||||
OPTIMIZATION += $(PROTOTYPE_OPTIMIZATION)
|
||||
endif
|
||||
|
||||
# Dependency Flags
|
||||
# These flags tell the compiler to build dependencies
|
||||
# See: https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html
|
||||
# Using following guide: http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#combine
|
||||
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPENDDIR)/$*.d
|
||||
|
||||
# Flags for the compiler call
|
||||
# - std: Which C++ version to use. Common versions: c++11, c++14 and c++17
|
||||
# - Wall: enable all warnings
|
||||
# - Wextra: enable extra warnings
|
||||
# - g: defines debug level
|
||||
# - fmessage-length: to control the formatting algorithm for diagnostic messages;
|
||||
# =0 means no line-wrapping is done; each error message appears on a single line
|
||||
# - fno-exceptions: stops generating extra code needed to propagate exceptions,
|
||||
# which can produce significant data size overhead
|
||||
CUSTOM_DEFINES += -DUNIT_TEST
|
||||
WARNING_FLAGS = -Wall -Wshadow=local -Wextra -Wimplicit-fallthrough=1 \
|
||||
-Wno-unused-parameter
|
||||
|
||||
CXXDEFINES := $(CUSTOM_DEFINES)
|
||||
CFLAGS +=
|
||||
CXXFLAGS += -I. $(DEBUG_LEVEL) $(WARNING_FLAGS) $(DEPFLAGS) -fmessage-length=0 $(OPTIMIZATION)\
|
||||
$(I_INCLUDES) $(CXXDEFINES)
|
||||
CPPFLAGS += -std=c++11
|
||||
|
||||
# Flags for the linker call
|
||||
# LINK_INCLUDES specify the path to used libraries and the linker script
|
||||
# LINK_LIBRARIES: Link real time support
|
||||
LDFLAGS := $(DEBUG_LEVEL) $(UNUSED_CODE_REMOVAL) $(OPTIMIZATION) -pthread
|
||||
LINK_INCLUDES :=
|
||||
LINK_LIBRARIES :=
|
||||
|
||||
ifdef LINUX
|
||||
LINK_LIBRARIES += -lrt
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
LINK_LIBRARIES += -lwsock32 -lws2_32
|
||||
LDFLASGS += -fuse-ld=lld
|
||||
endif
|
||||
|
||||
# Gnu Coverage Tools Flags
|
||||
ifdef GCOV
|
||||
GCOV_CXXFLAGS = -fprofile-arcs -ftest-coverage --coverage -fno-inline \
|
||||
-fno-inline-small-functions -fno-default-inline
|
||||
CXXFLAGS += $(GCOV_CXXFLAGS)
|
||||
GCOV_LINKER_LIBS = -lgcov -fprofile-arcs -ftest-coverage
|
||||
LINK_LIBRARIES += $(GCOV_LINKER_LIBS)
|
||||
endif
|
||||
|
||||
# $(info $${CXXFLAGS} is [${CXXFLAGS}])
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Rules
|
||||
#-------------------------------------------------------------------------------
|
||||
# the call function assigns parameters to temporary variables
|
||||
# https://www.gnu.org/software/make/manual/make.html#Call-Function
|
||||
# $(1) = Memory names
|
||||
# Rules are called for each memory type
|
||||
# Two Expansion Symbols $$ are to escape the dollar sign for eval.
|
||||
# See: http://make.mad-scientist.net/the-eval-function/
|
||||
|
||||
default: all
|
||||
|
||||
# Cleans all files
|
||||
hardclean:
|
||||
-rm -rf $(BUILDPATH)
|
||||
-rm -rf $(OBJECTPATH)
|
||||
-rm -rf $(DEPENDPATH)
|
||||
|
||||
# Only clean files for current build
|
||||
clean:
|
||||
-rm -rf $(CLEANOBJ)
|
||||
-rm -rf $(CLEANBIN)
|
||||
-rm -rf $(CLEANDEP)
|
||||
|
||||
# Only clean binaries. Useful for changing the binary type when object files
|
||||
# are already compiled so complete rebuild is not necessary
|
||||
cleanbin:
|
||||
-rm -rf $(CLEANBIN)
|
||||
|
||||
# In this section, the binaries are built for all selected memories
|
||||
# notestfw: all
|
||||
all: executable
|
||||
|
||||
# Build target configuration
|
||||
release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION)
|
||||
release: LINK_TIME_OPTIMIZATION = -flto
|
||||
release: TARGET = Mission build.
|
||||
release: OPTIMIZATION_MESSAGE = On with Link Time Optimization
|
||||
|
||||
debug: CXXDEFINES += -DDEBUG
|
||||
debug: TARGET = Debug
|
||||
debug: DEBUG_MESSAGE = On
|
||||
|
||||
ifndef KEEP_UNUSED_CODE
|
||||
debug release: OPTIMIZATION_MESSAGE += , no unused code removal
|
||||
endif
|
||||
|
||||
debug release notestfw: executable
|
||||
|
||||
executable: $(BINDIR)/$(BINARY_NAME).elf
|
||||
@echo
|
||||
@echo $(MSG_INFO)
|
||||
@echo $(MSG_TARGET)
|
||||
@echo $(MSG_OPTIMIZATION)
|
||||
@echo $(MSG_DEBUG)
|
||||
|
||||
C_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(C_OBJECTS))
|
||||
CXX_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(CXX_OBJECTS))
|
||||
ASM_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(ASM_OBJECTS))
|
||||
ALL_OBJECTS = $(ASM_OBJECTS_PREFIXED) $(C_OBJECTS_PREFIXED) \
|
||||
$(CXX_OBJECTS_PREFIXED)
|
||||
|
||||
# Useful for debugging the Makefile
|
||||
# Also see: https://www.oreilly.com/openbook/make3/book/ch12.pdf
|
||||
# $(info $${ALL_OBJECTS} is [${ALL_OBJECTS}])
|
||||
# $(info $${CXXSRC} is [${CXXSRC}])
|
||||
|
||||
# Automatic variables are used here extensively. Some of them
|
||||
# are escaped($$) to suppress immediate evaluation. The most important ones are:
|
||||
# $@: Name of Target (left side of rule)
|
||||
# $<: Name of the first prerequisite (right side of rule)
|
||||
# @^: List of all prerequisite, omitting duplicates
|
||||
# @D: Directory and file-within-directory part of $@
|
||||
|
||||
# Generates binary and displays all build properties
|
||||
# -p with mkdir ignores error and creates directory when needed.
|
||||
|
||||
# SHOW_DETAILS = 1
|
||||
|
||||
|
||||
# Link with required libraries: HAL (Hardware Abstraction Layer) and
|
||||
# HCC (File System Library)
|
||||
$(BINDIR)/$(BINARY_NAME).elf: $(ALL_OBJECTS)
|
||||
@echo
|
||||
@echo $(MSG_LINKING) Target $@
|
||||
@mkdir -p $(@D)
|
||||
ifdef SHOW_DETAILS
|
||||
$(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES)
|
||||
else
|
||||
@$(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES)
|
||||
endif
|
||||
ifeq ($(BUILD_FOLDER), mission)
|
||||
# With Link Time Optimization, section size is not available
|
||||
$(SIZE) $@
|
||||
else
|
||||
$(SIZE) $^ $@
|
||||
endif
|
||||
|
||||
$(BINDIR)/$(BINARY_NAME).hex: $(BINDIR)/$(BINARY_NAME).elf
|
||||
@echo
|
||||
@echo $(MSG_BINARY)
|
||||
@mkdir -p $(@D)
|
||||
$(HEXCOPY) $< $@
|
||||
|
||||
# Build new objects for changed dependencies.
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
$(OBJDIR)/%.o: %.cpp $(DEPENDDIR)/%.d | $(DEPENDDIR)
|
||||
@echo
|
||||
@echo $(MSG_COMPILING) $<
|
||||
@mkdir -p $(@D)
|
||||
ifdef SHOW_DETAILS
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
else
|
||||
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
endif
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
$(OBJDIR)/%.o: %.c $(DEPENDDIR)/%.d | $(DEPENDDIR)
|
||||
@echo
|
||||
@echo $(MSG_COMPILING) $<
|
||||
@mkdir -p $(@D)
|
||||
ifdef SHOW_DETAILS
|
||||
$(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
else
|
||||
@$(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
endif
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Dependency Handling
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# Dependency Handling according to following guide:
|
||||
# http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
|
||||
$(DEPENDDIR):
|
||||
@mkdir -p $(@D)
|
||||
DEPENDENCY_RELATIVE = $(CSRC:.c=.d) $(CXXSRC:.cpp=.d)
|
||||
# This is the list of all dependencies
|
||||
DEPFILES = $(addprefix $(DEPENDDIR)/, $(DEPENDENCY_RELATIVE))
|
||||
# Create subdirectories for dependencies
|
||||
$(DEPFILES):
|
||||
@mkdir -p $(@D)
|
||||
# Include all dependencies
|
||||
include $(wildcard $(DEPFILES))
|
||||
|
||||
# .PHONY tells make that these targets aren't files
|
||||
.PHONY: clean release debug all hardclean cleanbin
|
8
unittest/testcfg/TestsConfig.h
Normal file
8
unittest/testcfg/TestsConfig.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
|
||||
#define FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
|
||||
|
||||
|
||||
#define CUSTOM_UNITTEST_RUNNER 0
|
||||
|
||||
|
||||
#endif /* FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ */
|
5
unittest/testcfg/cdatapool/dataPoolInit.cpp
Normal file
5
unittest/testcfg/cdatapool/dataPoolInit.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "dataPoolInit.h"
|
||||
|
||||
void datapool::dataPoolInit(std::map<uint32_t, PoolEntryIF*> * poolMap) {
|
||||
|
||||
}
|
17
unittest/testcfg/cdatapool/dataPoolInit.h
Normal file
17
unittest/testcfg/cdatapool/dataPoolInit.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
||||
#define HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
||||
|
||||
#include <fsfw/datapool/DataPool.h>
|
||||
#include <fsfw/datapool/PoolEntryIF.h>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace datapool {
|
||||
void dataPoolInit(std::map<uint32_t, PoolEntryIF*> * poolMap);
|
||||
|
||||
enum datapoolvariables {
|
||||
NO_PARAMETER = 0,
|
||||
};
|
||||
}
|
||||
#endif /* CONFIG_CDATAPOOL_DATAPOOLINIT_H_ */
|
5
unittest/testcfg/devices/logicalAddresses.cpp
Normal file
5
unittest/testcfg/devices/logicalAddresses.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "logicalAddresses.h"
|
||||
|
||||
|
||||
|
||||
|
15
unittest/testcfg/devices/logicalAddresses.h
Normal file
15
unittest/testcfg/devices/logicalAddresses.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||
#define CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||
|
||||
#include <fsfw/devicehandlers/CookieIF.h>
|
||||
#include <fsfw/unittest/config/objects/systemObjectList.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace addresses {
|
||||
/* Logical addresses have uint32_t datatype */
|
||||
enum logicalAddresses: address_t {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */
|
4
unittest/testcfg/devices/powerSwitcherList.cpp
Normal file
4
unittest/testcfg/devices/powerSwitcherList.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#include "powerSwitcherList.h"
|
||||
|
||||
|
||||
|
12
unittest/testcfg/devices/powerSwitcherList.h
Normal file
12
unittest/testcfg/devices/powerSwitcherList.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||
#define CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||
|
||||
namespace switches {
|
||||
/* Switches are uint8_t datatype and go from 0 to 255 */
|
||||
enum switcherList {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_DEVICES_POWERSWITCHERLIST_H_ */
|
18
unittest/testcfg/events/subsystemIdRanges.h
Normal file
18
unittest/testcfg/events/subsystemIdRanges.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
|
||||
#define CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <fsfw/events/fwSubsystemIdRanges.h>
|
||||
|
||||
/**
|
||||
* @brief Custom subsystem IDs can be added here
|
||||
* @details
|
||||
* Subsystem IDs are used to create unique events.
|
||||
*/
|
||||
namespace SUBSYSTEM_ID {
|
||||
enum: uint8_t {
|
||||
SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE,
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ */
|
12
unittest/testcfg/ipc/MissionMessageTypes.cpp
Normal file
12
unittest/testcfg/ipc/MissionMessageTypes.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "MissionMessageTypes.h"
|
||||
|
||||
#include <fsfw/ipc/CommandMessage.h>
|
||||
|
||||
void messagetypes::clearMissionMessage(CommandMessage* message) {
|
||||
switch(message->getMessageType()) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
22
unittest/testcfg/ipc/MissionMessageTypes.h
Normal file
22
unittest/testcfg/ipc/MissionMessageTypes.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||
#define CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||
|
||||
#include <fsfw/ipc/FwMessageTypes.h>
|
||||
|
||||
class CommandMessage;
|
||||
|
||||
/**
|
||||
* 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 MESSAGE_TYPE {
|
||||
MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT,
|
||||
};
|
||||
|
||||
void clearMissionMessage(CommandMessage* message);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IPC_MISSIONMESSAGETYPES_H_ */
|
34
unittest/testcfg/objects/Factory.cpp
Normal file
34
unittest/testcfg/objects/Factory.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "Factory.h"
|
||||
|
||||
#include <fsfw/events/EventManager.h>
|
||||
#include <fsfw/health/HealthTable.h>
|
||||
|
||||
#include <fsfw/internalError/InternalErrorReporter.h>
|
||||
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||
|
||||
/**
|
||||
* @brief Produces system objects.
|
||||
* @details
|
||||
* Build tasks by using SystemObject Interface (Interface).
|
||||
* Header files of all tasks must be included
|
||||
* Please note that an object has to implement the system object interface
|
||||
* if the interface validity is checked or retrieved later by using the
|
||||
* get<TargetInterface>(object_id) function from the ObjectManagerIF.
|
||||
*
|
||||
* 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() {
|
||||
|
||||
}
|
||||
|
||||
|
16
unittest/testcfg/objects/Factory.h
Normal file
16
unittest/testcfg/objects/Factory.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef FACTORY_H_
|
||||
#define FACTORY_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
|
||||
namespace Factory {
|
||||
/**
|
||||
* @brief Creates all SystemObject elements which are persistent
|
||||
* during execution.
|
||||
*/
|
||||
void produce();
|
||||
void setStaticFrameworkObjectIds();
|
||||
|
||||
}
|
||||
|
||||
#endif /* FACTORY_H_ */
|
16
unittest/testcfg/objects/systemObjectList.h
Normal file
16
unittest/testcfg/objects/systemObjectList.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||
#define HOSTED_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_ */
|
23
unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp
Normal file
23
unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "PollingSequenceFactory.h"
|
||||
|
||||
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
|
||||
|
||||
ReturnValue_t pst::pollingSequenceInitDefault(
|
||||
FixedTimeslotTaskIF *thisSequence) {
|
||||
/* Length of a communication cycle */
|
||||
uint32_t length = thisSequence->getPeriodMs();
|
||||
|
||||
/* Add polling sequence table here */
|
||||
|
||||
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
else {
|
||||
sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!"
|
||||
<< std::endl;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
32
unittest/testcfg/pollingsequence/PollingSequenceFactory.h
Normal file
32
unittest/testcfg/pollingsequence/PollingSequenceFactory.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef POLLINGSEQUENCEFACTORY_H_
|
||||
#define POLLINGSEQUENCEFACTORY_H_
|
||||
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
class FixedTimeslotTaskIF;
|
||||
|
||||
/**
|
||||
* All device handlers are scheduled by adding them into Polling Sequence Tables (PST)
|
||||
* to satisfy stricter timing requirements of device communication,
|
||||
* A device handler has four different communication steps:
|
||||
* 1. DeviceHandlerIF::SEND_WRITE -> Send write via interface
|
||||
* 2. DeviceHandlerIF::GET_WRITE -> Get confirmation for write
|
||||
* 3. DeviceHandlerIF::SEND_READ -> Send read request
|
||||
* 4. DeviceHandlerIF::GET_READ -> Read from interface
|
||||
* The PST specifies precisely when the respective ComIF functions are called
|
||||
* during the communication cycle time.
|
||||
* The task is created using the FixedTimeslotTaskIF,
|
||||
* which utilises the underlying Operating System Abstraction Layer (OSAL)
|
||||
*
|
||||
* @param thisSequence FixedTimeslotTaskIF * object is passed inside the Factory class when creating the PST
|
||||
* @return
|
||||
*/
|
||||
namespace pst {
|
||||
|
||||
/* Default PST */
|
||||
ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif /* POLLINGSEQUENCEINIT_H_ */
|
16
unittest/testcfg/returnvalues/classIds.h
Normal file
16
unittest/testcfg/returnvalues/classIds.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||
#define CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||
|
||||
#include <fsfw/returnvalues/FwClassIds.h>
|
||||
|
||||
/**
|
||||
* @brief CLASS_ID defintions which are required for custom returnvalues.
|
||||
*/
|
||||
namespace CLASS_ID {
|
||||
enum {
|
||||
MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_RETURNVALUES_CLASSIDS_H_ */
|
15
unittest/testcfg/testcfg.mk
Normal file
15
unittest/testcfg/testcfg.mk
Normal file
@ -0,0 +1,15 @@
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/cdatapool/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp)
|
||||
|
||||
INCLUDES += $(CURRENTPATH)
|
||||
INCLUDES += $(CURRENTPATH)/objects
|
||||
INCLUDES += $(CURRENTPATH)/ipc
|
||||
INCLUDES += $(CURRENTPATH)/pollingsequence
|
||||
INCLUDES += $(CURRENTPATH)/returnvalues
|
||||
INCLUDES += $(CURRENTPATH)/tmtc
|
||||
INCLUDES += $(CURRENTPATH)/events
|
||||
INCLUDES += $(CURRENTPATH)/devices
|
||||
INCLUDES += $(CURRENTPATH)/cdatapool
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user