Update framework #6

Merged
meierj merged 67 commits from mueller/master into eive/develop 2021-07-23 18:26:40 +02:00
203 changed files with 5718 additions and 4166 deletions
Showing only changes of commit b00bfe4bda - Show all commits

View File

@ -1,3 +1,16 @@
## Changes from ASTP 1.0.0 to 1.1.0
### PUS
- Added PUS C support
### Configuration
- Additional configuration option fsfwconfig::FSFW_MAX_TM_PACKET_SIZE which
need to be specified in FSFWConfig.h
## Changes from ASTP 0.0.1 to 1.0.0 ## Changes from ASTP 0.0.1 to 1.0.0
### Host OSAL ### Host OSAL

View File

@ -18,6 +18,13 @@ add_library(${LIB_FSFW_NAME})
set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos) set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
elseif(${CMAKE_CXX_STANDARD} LESS 11)
message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++11 support")
endif()
if(NOT OS_FSFW) if(NOT OS_FSFW)
message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS") message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS")
# Assume host OS and autodetermine from OS_FSFW # Assume host OS and autodetermine from OS_FSFW
@ -131,9 +138,9 @@ else()
) )
endif() endif()
foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATH}) foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATHS})
if(IS_ABSOLUTE ${INCLUDE_PATH}) if(IS_ABSOLUTE ${INCLUDE_PATH})
set(CURR_ABS_INC_PATH "${FREERTOS_PATH}") set(CURR_ABS_INC_PATH "${INCLUDE_PATH}")
else() else()
get_filename_component(CURR_ABS_INC_PATH get_filename_component(CURR_ABS_INC_PATH
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR}) ${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})

7
FSFW.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef FSFW_FSFW_H_
#define FSFW_FSFW_H_
#include "FSFWConfig.h"
#endif /* FSFW_FSFW_H_ */

View File

@ -38,11 +38,12 @@ a starting point. The [configuration section](doc/README-config.md#top) provides
[1. High-level overview](doc/README-highlevel.md#top) <br> [1. High-level overview](doc/README-highlevel.md#top) <br>
[2. Core components](doc/README-core.md#top) <br> [2. Core components](doc/README-core.md#top) <br>
[3. OSAL overview](doc/README-osal.md#top) <br> [3. Configuration](doc/README-config.md#top) <br>
[4. PUS services](doc/README-pus.md#top) <br> [4. OSAL overview](doc/README-osal.md#top) <br>
[5. Device Handler overview](doc/README-devicehandlers.md#top) <br> [5. PUS services](doc/README-pus.md#top) <br>
[6. Controller overview](doc/README-controllers.md#top) <br> [6. Device Handler overview](doc/README-devicehandlers.md#top) <br>
[7. Local Data Pools](doc/README-localpools.md#top) <br> [7. Controller overview](doc/README-controllers.md#top) <br>
[8. Local Data Pools](doc/README-localpools.md#top) <br>

View File

@ -2,7 +2,7 @@
#include "HasActionsIF.h" #include "HasActionsIF.h"
#include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueSenderIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
#include "../serviceinterface/ServiceInterface.h" #include "../serviceinterface/ServiceInterface.h"
ActionHelper::ActionHelper(HasActionsIF* setOwner, ActionHelper::ActionHelper(HasActionsIF* setOwner,
@ -25,7 +25,7 @@ ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
} }
ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == nullptr) { if (ipcStore == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -1,7 +1,7 @@
#include "ActionMessage.h" #include "ActionMessage.h"
#include "HasActionsIF.h" #include "HasActionsIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
#include "../storagemanager/StorageManagerIF.h" #include "../storagemanager/StorageManagerIF.h"
ActionMessage::ActionMessage() { ActionMessage::ActionMessage() {
@ -69,7 +69,7 @@ void ActionMessage::clear(CommandMessage* message) {
switch(message->getCommand()) { switch(message->getCommand()) {
case EXECUTE_ACTION: case EXECUTE_ACTION:
case DATA_REPLY: { case DATA_REPLY: {
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>( StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
objects::IPC_STORE); objects::IPC_STORE);
if (ipcStore != NULL) { if (ipcStore != NULL) {
ipcStore->deleteData(getStoreId(message)); ipcStore->deleteData(getStoreId(message));

View File

@ -2,7 +2,8 @@
#include "CommandActionHelper.h" #include "CommandActionHelper.h"
#include "CommandsActionsIF.h" #include "CommandsActionsIF.h"
#include "HasActionsIF.h" #include "HasActionsIF.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../objectmanager/ObjectManager.h"
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) : CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) :
owner(setOwner), queueToUse(NULL), ipcStore( owner(setOwner), queueToUse(NULL), ipcStore(
@ -14,7 +15,7 @@ CommandActionHelper::~CommandActionHelper() {
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
ActionId_t actionId, SerializeIF *data) { ActionId_t actionId, SerializeIF *data) {
HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo); HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
if (receiver == NULL) { if (receiver == NULL) {
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
} }
@ -40,7 +41,7 @@ ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
// if (commandCount != 0) { // if (commandCount != 0) {
// return CommandsFunctionsIF::ALREADY_COMMANDING; // return CommandsFunctionsIF::ALREADY_COMMANDING;
// } // }
HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo); HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
if (receiver == NULL) { if (receiver == NULL) {
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
} }
@ -66,7 +67,7 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId,
} }
ReturnValue_t CommandActionHelper::initialize() { ReturnValue_t CommandActionHelper::initialize() {
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == NULL) { if (ipcStore == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -3,6 +3,7 @@
#include "../subsystem/SubsystemBase.h" #include "../subsystem/SubsystemBase.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../action/HasActionsIF.h" #include "../action/HasActionsIF.h"
#include "../objectmanager/ObjectManager.h"
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId, ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
size_t commandQueueDepth) : size_t commandQueueDepth) :
@ -25,7 +26,7 @@ ReturnValue_t ControllerBase::initialize() {
MessageQueueId_t parentQueue = 0; MessageQueueId_t parentQueue = 0;
if (parentId != objects::NO_OBJECT) { if (parentId != objects::NO_OBJECT) {
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId); SubsystemBase *parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
if (parent == nullptr) { if (parent == nullptr) {
return RETURN_FAILED; return RETURN_FAILED;
} }

View File

@ -66,6 +66,10 @@ protected:
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override = 0; LocalDataPoolManager& poolManager) override = 0;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
// Mode abstract functions
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override = 0;
}; };

View File

@ -19,7 +19,8 @@ class VirtualChannelReception;
class DataLinkLayer : public CCSDSReturnValuesIF { class DataLinkLayer : public CCSDSReturnValuesIF {
public: public:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1;
static const Event RF_AVAILABLE = MAKE_EVENT(0, severity::INFO); //!< A RF available signal was detected. P1: raw RFA state, P2: 0 //! [EXPORT] : [COMMENT] A RF available signal was detected. P1: raw RFA state, P2: 0
static const Event RF_AVAILABLE = MAKE_EVENT(0, severity::INFO);
static const Event RF_LOST = MAKE_EVENT(1, severity::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0 static const Event RF_LOST = MAKE_EVENT(1, severity::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0
static const Event BIT_LOCK = MAKE_EVENT(2, severity::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0 static const Event BIT_LOCK = MAKE_EVENT(2, severity::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0
static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0 static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0

View File

@ -1,10 +1,13 @@
#include "MapPacketExtraction.h" #include "MapPacketExtraction.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
#include "../storagemanager/StorageManagerIF.h" #include "../storagemanager/StorageManagerIF.h"
#include "../tmtcpacket/SpacePacketBase.h" #include "../tmtcpacket/SpacePacketBase.h"
#include "../tmtcservices/AcceptsTelecommandsIF.h" #include "../tmtcservices/AcceptsTelecommandsIF.h"
#include "../tmtcservices/TmTcMessage.h" #include "../tmtcservices/TmTcMessage.h"
#include "../objectmanager/ObjectManager.h"
#include <cstring> #include <cstring>
MapPacketExtraction::MapPacketExtraction(uint8_t setMapId, MapPacketExtraction::MapPacketExtraction(uint8_t setMapId,
@ -131,9 +134,9 @@ void MapPacketExtraction::clearBuffers() {
} }
ReturnValue_t MapPacketExtraction::initialize() { ReturnValue_t MapPacketExtraction::initialize() {
packetStore = objectManager->get<StorageManagerIF>(objects::TC_STORE); packetStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
AcceptsTelecommandsIF* distributor = objectManager->get< AcceptsTelecommandsIF* distributor = ObjectManager::instance()->
AcceptsTelecommandsIF>(packetDestination); get<AcceptsTelecommandsIF>(packetDestination);
if ((packetStore != NULL) && (distributor != NULL)) { if ((packetStore != NULL) && (distributor != NULL)) {
tcQueueId = distributor->getRequestQueue(); tcQueueId = distributor->getRequestQueue();
return RETURN_OK; return RETURN_OK;

View File

@ -34,7 +34,8 @@ class LocalPoolObjectBase;
* can be retrieved using the object manager, provided the target object is a SystemObject. * can be retrieved using the object manager, provided the target object is a SystemObject.
* For example, the following line of code can be used to retrieve the interface * For example, the following line of code can be used to retrieve the interface
* *
* HasLocalDataPoolIF* poolIF = objectManager->get<HasLocalDataPoolIF>(objects::SOME_OBJECT); * HasLocalDataPoolIF* poolIF = ObjectManager::instance()->
* get<HasLocalDataPoolIF>(objects::SOME_OBJECT);
* if(poolIF != nullptr) { * if(poolIF != nullptr) {
* doSomething() * doSomething()
* } * }

View File

@ -6,6 +6,7 @@
#include "internal/HasLocalDpIFManagerAttorney.h" #include "internal/HasLocalDpIFManagerAttorney.h"
#include "../housekeeping/HousekeepingSetPacket.h" #include "../housekeeping/HousekeepingSetPacket.h"
#include "../objectmanager/ObjectManager.h"
#include "../housekeeping/HousekeepingSnapshot.h" #include "../housekeeping/HousekeepingSnapshot.h"
#include "../housekeeping/AcceptsHkPacketsIF.h" #include "../housekeeping/AcceptsHkPacketsIF.h"
#include "../timemanager/CCSDSTime.h" #include "../timemanager/CCSDSTime.h"
@ -52,7 +53,7 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
} }
hkQueue = queueToUse; hkQueue = queueToUse;
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if(ipcStore == nullptr) { if(ipcStore == nullptr) {
/* Error, all destinations invalid */ /* Error, all destinations invalid */
printWarningOrError(sif::OutputTypes::OUT_ERROR, printWarningOrError(sif::OutputTypes::OUT_ERROR,
@ -63,8 +64,8 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
if(defaultHkDestination != objects::NO_OBJECT) { if(defaultHkDestination != objects::NO_OBJECT) {
AcceptsHkPacketsIF* hkPacketReceiver = AcceptsHkPacketsIF* hkPacketReceiver = ObjectManager::instance()->
objectManager->get<AcceptsHkPacketsIF>(defaultHkDestination); get<AcceptsHkPacketsIF>(defaultHkDestination);
if(hkPacketReceiver != nullptr) { if(hkPacketReceiver != nullptr) {
hkDestinationId = hkPacketReceiver->getHkQueue(); hkDestinationId = hkPacketReceiver->getHkQueue();
} }
@ -360,8 +361,8 @@ void LocalDataPoolManager::resetHkUpdateResetHelper() {
ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid, ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid,
bool enableReporting, float collectionInterval, bool isDiagnostics, bool enableReporting, float collectionInterval, bool isDiagnostics,
object_id_t packetDestination) { object_id_t packetDestination) {
AcceptsHkPacketsIF* hkReceiverObject = AcceptsHkPacketsIF* hkReceiverObject = ObjectManager::instance()->
objectManager->get<AcceptsHkPacketsIF>(packetDestination); get<AcceptsHkPacketsIF>(packetDestination);
if(hkReceiverObject == nullptr) { if(hkReceiverObject == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, printWarningOrError(sif::OutputTypes::OUT_WARNING,
"subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID);
@ -391,7 +392,7 @@ ReturnValue_t LocalDataPoolManager::subscribeForUpdatePacket(sid_t sid,
bool isDiagnostics, bool reportingEnabled, bool isDiagnostics, bool reportingEnabled,
object_id_t packetDestination) { object_id_t packetDestination) {
AcceptsHkPacketsIF* hkReceiverObject = AcceptsHkPacketsIF* hkReceiverObject =
objectManager->get<AcceptsHkPacketsIF>(packetDestination); ObjectManager::instance()->get<AcceptsHkPacketsIF>(packetDestination);
if(hkReceiverObject == nullptr) { if(hkReceiverObject == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, printWarningOrError(sif::OutputTypes::OUT_WARNING,
"subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID);
@ -553,7 +554,12 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(
case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT):
case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): {
LocalPoolDataSetBase* dataSet =HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage",
DATASET_NOT_FOUND);
return DATASET_NOT_FOUND;
}
if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT
and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
result = WRONG_HK_PACKET_TYPE; result = WRONG_HK_PACKET_TYPE;

View File

@ -3,6 +3,7 @@
#include "internal/HasLocalDpIFUserAttorney.h" #include "internal/HasLocalDpIFUserAttorney.h"
#include "../serviceinterface/ServiceInterface.h" #include "../serviceinterface/ServiceInterface.h"
#include "../objectmanager/ObjectManager.h"
#include "../globalfunctions/bitutility.h" #include "../globalfunctions/bitutility.h"
#include "../datapoollocal/LocalDataPoolManager.h" #include "../datapoollocal/LocalDataPoolManager.h"
#include "../housekeeping/PeriodicHousekeepingHelper.h" #include "../housekeeping/PeriodicHousekeepingHelper.h"
@ -45,7 +46,7 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner,
LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables): const size_t maxNumberOfVariables):
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>( HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get<HasLocalDataPoolIF>(
sid.objectId); sid.objectId);
if(hkOwner != nullptr) { if(hkOwner != nullptr) {
AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);

View File

@ -4,7 +4,7 @@
#include "HasLocalDataPoolIF.h" #include "HasLocalDataPoolIF.h"
#include "internal/HasLocalDpIFUserAttorney.h" #include "internal/HasLocalDpIFUserAttorney.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner,
@ -43,7 +43,7 @@ LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId,
"which is the NO_PARAMETER value!\n"); "which is the NO_PARAMETER value!\n");
#endif #endif
} }
HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(poolOwner); HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get<HasLocalDataPoolIF>(poolOwner);
if(hkOwner == nullptr) { if(hkOwner == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolVariable: The supplied pool owner did not implement the correct " sif::error << "LocalPoolVariable: The supplied pool owner did not implement the correct "

View File

@ -1,15 +1,23 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
ipc/missionMessageTypes.cpp
objects/FsfwFactory.cpp
pollingsequence/PollingSequenceFactory.cpp
)
# Should be added to include path
target_include_directories(${TARGET_NAME} PRIVATE target_include_directories(${TARGET_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
) )
if(NOT FSFW_CONFIG_PATH) target_sources(${TARGET_NAME} PRIVATE
set(FSFW_CONFIG_PATH ${CMAKE_CURRENT_SOURCE_DIR}) ipc/missionMessageTypes.cpp
pollingsequence/PollingSequenceFactory.cpp
objects/FsfwFactory.cpp
)
# If a special translation file for object IDs exists, compile it.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
target_sources(${TARGET_NAME} PRIVATE
objects/translateObjects.cpp
)
endif() endif()
# If a special translation file for events exists, compile it.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
target_sources(${TARGET_NAME} PRIVATE
events/translateEvents.cpp
)
endif()

View File

@ -17,6 +17,9 @@
#define FSFW_DISABLE_PRINTOUT 0 #define FSFW_DISABLE_PRINTOUT 0
#endif #endif
#define FSFW_USE_PUS_C_TELEMETRY 1
#define FSFW_USE_PUS_C_TELECOMMANDS 1
//! Can be used to disable the ANSI color sequences for C stdio. //! Can be used to disable the ANSI color sequences for C stdio.
#define FSFW_COLORED_OUTPUT 1 #define FSFW_COLORED_OUTPUT 1
@ -48,9 +51,9 @@
#define FSFW_USE_REALTIME_FOR_LINUX 1 #define FSFW_USE_REALTIME_FOR_LINUX 1
namespace fsfwconfig { namespace fsfwconfig {
//! Default timestamp size. The default timestamp will be an eight byte CDC
//! short timestamp. //! Default timestamp size. The default timestamp will be an seven byte CDC short timestamp.
static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8; static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 7;
//! Configure the allocated pool sizes for the event manager. //! Configure the allocated pool sizes for the event manager.
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
@ -65,6 +68,8 @@ static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6;
static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124; static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124;
static constexpr size_t FSFW_MAX_TM_PACKET_SIZE = 2048;
} }
#endif /* CONFIG_FSFWCONFIG_H_ */ #endif /* CONFIG_FSFWCONFIG_H_ */

View File

@ -1,6 +1,5 @@
#include "ChildHandlerBase.h" #include "ChildHandlerBase.h"
#include "../subsystem/SubsystemBase.h" #include "../subsystem/SubsystemBase.h"
#include "../subsystem/SubsystemBase.h"
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId,
object_id_t deviceCommunication, CookieIF * cookie, object_id_t deviceCommunication, CookieIF * cookie,
@ -30,7 +29,7 @@ ReturnValue_t ChildHandlerBase::initialize() {
MessageQueueId_t parentQueue = 0; MessageQueueId_t parentQueue = 0;
if (parentId != objects::NO_OBJECT) { if (parentId != objects::NO_OBJECT) {
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId); SubsystemBase *parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
if (parent == NULL) { if (parent == NULL) {
return RETURN_FAILED; return RETURN_FAILED;
} }

View File

@ -119,7 +119,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
return result; return result;
} }
communicationInterface = objectManager->get<DeviceCommunicationIF>( communicationInterface = ObjectManager::instance()->get<DeviceCommunicationIF>(
deviceCommunicationId); deviceCommunicationId);
if (communicationInterface == nullptr) { if (communicationInterface == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
@ -136,7 +136,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
return result; return result;
} }
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); IPCStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (IPCStore == nullptr) { if (IPCStore == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up"); ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up");
@ -144,8 +144,8 @@ ReturnValue_t DeviceHandlerBase::initialize() {
} }
if(rawDataReceiverId != objects::NO_OBJECT) { if(rawDataReceiverId != objects::NO_OBJECT) {
AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< AcceptsDeviceResponsesIF *rawReceiver = ObjectManager::instance()->
AcceptsDeviceResponsesIF>(rawDataReceiverId); get<AcceptsDeviceResponsesIF>(rawDataReceiverId);
if (rawReceiver == nullptr) { if (rawReceiver == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_ERROR, printWarningOrError(sif::OutputTypes::OUT_ERROR,
@ -164,7 +164,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
} }
if(powerSwitcherId != objects::NO_OBJECT) { if(powerSwitcherId != objects::NO_OBJECT) {
powerSwitcher = objectManager->get<PowerSwitchIF>(powerSwitcherId); powerSwitcher = ObjectManager::instance()->get<PowerSwitchIF>(powerSwitcherId);
if (powerSwitcher == nullptr) { if (powerSwitcher == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_ERROR, printWarningOrError(sif::OutputTypes::OUT_ERROR,
"initialize", ObjectManagerIF::CHILD_INIT_FAILED, "initialize", ObjectManagerIF::CHILD_INIT_FAILED,
@ -226,16 +226,15 @@ ReturnValue_t DeviceHandlerBase::initialize() {
} }
void DeviceHandlerBase::decrementDeviceReplyMap() { void DeviceHandlerBase::decrementDeviceReplyMap() {
for (std::map<DeviceCommandId_t, DeviceReplyInfo>::iterator iter = for (std::pair<const DeviceCommandId_t, DeviceReplyInfo>& replyPair: deviceReplyMap) {
deviceReplyMap.begin(); iter != deviceReplyMap.end(); iter++) { if (replyPair.second.delayCycles != 0) {
if (iter->second.delayCycles != 0) { replyPair.second.delayCycles--;
iter->second.delayCycles--; if (replyPair.second.delayCycles == 0) {
if (iter->second.delayCycles == 0) { if (replyPair.second.periodic) {
if (iter->second.periodic) { replyPair.second.delayCycles = replyPair.second.maxDelayCycles;
iter->second.delayCycles = iter->second.maxDelayCycles;
} }
replyToReply(iter, TIMEOUT); replyToReply(replyPair.first, replyPair.second, TIMEOUT);
missedReply(iter->first); missedReply(replyPair.first);
} }
} }
} }
@ -584,17 +583,28 @@ void DeviceHandlerBase::replyToCommand(ReturnValue_t status,
} }
} }
void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, void DeviceHandlerBase::replyToReply(const DeviceCommandId_t command, DeviceReplyInfo& replyInfo,
ReturnValue_t status) { ReturnValue_t status) {
// No need to check if iter exists, as this is checked by callers. // No need to check if iter exists, as this is checked by callers.
// If someone else uses the method, add check. // If someone else uses the method, add check.
if (iter->second.command == deviceCommandMap.end()) { if (replyInfo.command == deviceCommandMap.end()) {
//Is most likely periodic reply. Silent return. //Is most likely periodic reply. Silent return.
return; return;
} }
DeviceCommandInfo* info = &replyInfo.command->second;
if (info == nullptr){
printWarningOrError(sif::OutputTypes::OUT_ERROR,
"replyToReply", HasReturnvaluesIF::RETURN_FAILED,
"Command pointer not found");
return;
}
if (info->expectedReplies > 0){
// Check before to avoid underflow
info->expectedReplies--;
}
// Check if more replies are expected. If so, do nothing. // Check if more replies are expected. If so, do nothing.
DeviceCommandInfo* info = &(iter->second.command->second); if (info->expectedReplies == 0) {
if (--info->expectedReplies == 0) {
// Check if it was transition or internal command. // Check if it was transition or internal command.
// Don't send any replies in that case. // Don't send any replies in that case.
if (info->sendReplyTo != NO_COMMANDER) { if (info->sendReplyTo != NO_COMMANDER) {
@ -602,7 +612,7 @@ void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter,
if(status == HasReturnvaluesIF::RETURN_OK) { if(status == HasReturnvaluesIF::RETURN_OK) {
success = true; success = true;
} }
actionHelper.finish(success, info->sendReplyTo, iter->first, status); actionHelper.finish(success, info->sendReplyTo, command, status);
} }
info->isExecuting = false; info->isExecuting = false;
} }
@ -801,7 +811,7 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData,
replyRawReplyIfnotWiretapped(receivedData, foundLen); replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId); triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId);
} }
replyToReply(iter, result); replyToReply(iter->first, iter->second, result);
} }
else { else {
/* Other completion failure messages are created by timeout. /* Other completion failure messages are created by timeout.

View File

@ -667,7 +667,7 @@ protected:
static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0); static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0);
static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1); static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1);
static const MessageQueueId_t NO_COMMANDER = 0; static const MessageQueueId_t NO_COMMANDER = MessageQueueIF::NO_QUEUE;
//! Pointer to the raw packet that will be sent. //! Pointer to the raw packet that will be sent.
uint8_t *rawPacket = nullptr; uint8_t *rawPacket = nullptr;
@ -1195,7 +1195,8 @@ private:
* @foundLen the length of the packet * @foundLen the length of the packet
*/ */
void handleReply(const uint8_t *data, DeviceCommandId_t id, uint32_t foundLen); void handleReply(const uint8_t *data, DeviceCommandId_t id, uint32_t foundLen);
void replyToReply(DeviceReplyMap::iterator iter, ReturnValue_t status); void replyToReply(const DeviceCommandId_t command, DeviceReplyInfo& replyInfo,
ReturnValue_t status);
/** /**
* Build and send a command to the device. * Build and send a command to the device.

View File

@ -1,6 +1,7 @@
#include "DeviceHandlerFailureIsolation.h" #include "DeviceHandlerFailureIsolation.h"
#include "../devicehandlers/DeviceHandlerIF.h" #include "../devicehandlers/DeviceHandlerIF.h"
#include "../objectmanager/ObjectManager.h"
#include "../modes/HasModesIF.h" #include "../modes/HasModesIF.h"
#include "../health/HealthTableIF.h" #include "../health/HealthTableIF.h"
#include "../power/Fuse.h" #include "../power/Fuse.h"
@ -175,7 +176,7 @@ ReturnValue_t DeviceHandlerFailureIsolation::initialize() {
#endif #endif
return result; return result;
} }
ConfirmsFailuresIF* power = objectManager->get<ConfirmsFailuresIF>( ConfirmsFailuresIF* power = ObjectManager::instance()->get<ConfirmsFailuresIF>(
powerConfirmationId); powerConfirmationId);
if (power != nullptr) { if (power != nullptr) {
powerConfirmation = power->getEventReceptionQueue(); powerConfirmation = power->getEventReceptionQueue();

View File

@ -1,5 +1,5 @@
#include "DeviceHandlerMessage.h" #include "DeviceHandlerMessage.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
store_address_t DeviceHandlerMessage::getStoreAddress( store_address_t DeviceHandlerMessage::getStoreAddress(
const CommandMessage* message) { const CommandMessage* message) {
@ -70,7 +70,7 @@ void DeviceHandlerMessage::clear(CommandMessage* message) {
case REPLY_RAW_COMMAND: case REPLY_RAW_COMMAND:
case REPLY_RAW_REPLY: case REPLY_RAW_REPLY:
case REPLY_DIRECT_COMMAND_DATA: { case REPLY_DIRECT_COMMAND_DATA: {
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>( StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
objects::IPC_STORE); objects::IPC_STORE);
if (ipcStore != nullptr) { if (ipcStore != nullptr) {
ipcStore->deleteData(getStoreAddress(message)); ipcStore->deleteData(getStoreAddress(message));

View File

@ -1,12 +1,30 @@
Configuring the FSFW
## Configuring the FSFW ======
The FSFW can be configured via the `fsfwconfig` folder. A template folder has The FSFW can be configured via the `fsfwconfig` folder. A template folder has
been provided to have a starting point for this. The folder should be added been provided to have a starting point for this. The folder should be added
to the include path. to the include path. The primary configuration file is the `FSFWConfig.h` folder. Some
of the available options will be explained in more detail here.
# Auto-Translation of Events
### Configuring the Event Manager The FSFW allows the automatic translation of events, which allows developers to track triggered
events directly via console output. Using this feature requires:
1. `FSFW_OBJ_EVENT_TRANSLATION` set to 1 in the configuration file.
2. Special auto-generated translation files which translate event IDs and object IDs into
human readable strings. These files can be generated using the
[modgen Python scripts](https://git.ksat-stuttgart.de/source/modgen.git).
3. The generated translation files for the object IDs should be named `translatesObjects.cpp`
and `translateObjects.h` and should be copied to the `fsfwconfig/objects` folder
4. The generated translation files for the event IDs should be named `translateEvents.cpp` and
`translateEvents.h` and should be copied to the `fsfwconfig/events` folder
An example implementations of these translation file generators can be found as part
of the [SOURCE project here](https://git.ksat-stuttgart.de/source/sourceobsw/-/tree/development/generators)
or the [FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/generators)
## Configuring the Event Manager
The number of allowed subscriptions can be modified with the following The number of allowed subscriptions can be modified with the following
parameters: parameters:
@ -19,3 +37,4 @@ static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
} }
``` ```

View File

@ -19,8 +19,9 @@ A nullptr check of the returning Pointer must be done. This function is based on
```cpp ```cpp
template <typename T> T* ObjectManagerIF::get( object_id_t id ) template <typename T> T* ObjectManagerIF::get( object_id_t id )
``` ```
* A typical way to create all objects on startup is a handing a static produce function to the ObjectManager on creation. * A typical way to create all objects on startup is a handing a static produce function to the
By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards. ObjectManager on creation. By calling objectManager->initialize() the produce function will be
called and all SystemObjects will be initialized afterwards.
### Event Manager ### Event Manager
@ -36,14 +37,19 @@ By calling objectManager->initialize() the produce function will be called and a
### Stores ### Stores
* The message based communication can only exchange a few bytes of information inside the message itself. Therefore, additional information can * The message based communication can only exchange a few bytes of information inside the message
be exchanged with Stores. With this, only the store address must be exchanged in the message. itself. Therefore, additional information can be exchanged with Stores. With this, only the
* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC Store is used. For outgoing TM a TM store is used. store address must be exchanged in the message.
* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC
Store is used. For outgoing TM a TM store is used.
* All of them should use the Thread Safe Class storagemanager/PoolManager * All of them should use the Thread Safe Class storagemanager/PoolManager
### Tasks ### Tasks
There are two different types of tasks: There are two different types of tasks:
* The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the insertion to the Tasks. * The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the
* FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for DeviceHandlers, where polling should be in a defined order. An example can be found in defaultcfg/fsfwconfig/pollingSequence insertion to the Tasks.
* FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for
DeviceHandlers, where polling should be in a defined order. An example can be found in
`defaultcfg/fsfwconfig/pollingSequence` folder

View File

@ -1,99 +1,135 @@
# High-level overview High-level overview
======
## Structure # Structure
The general structure is driven by the usage of interfaces provided by objects. The general structure is driven by the usage of interfaces provided by objects.
The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be widely available, even with older compilers. The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be
widely available, even with older compilers.
The FSFW uses dynamic allocation during the initialization but provides static containers during runtime. The FSFW uses dynamic allocation during the initialization but provides static containers during runtime.
This simplifies the instantiation of objects and allows the usage of some standard containers. This simplifies the instantiation of objects and allows the usage of some standard containers.
Dynamic Allocation after initialization is discouraged and different solutions are provided in the FSFW to achieve that. Dynamic Allocation after initialization is discouraged and different solutions are provided in the
The fsfw uses run-time type information but exceptions are not allowed. FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed.
### Failure Handling # Failure Handling
Functions should return a defined ReturnValue_t to signal to the caller that something has gone wrong. Functions should return a defined `ReturnValue_t` to signal to the caller that something has
Returnvalues must be unique. For this the function HasReturnvaluesIF::makeReturnCode or the Macro MAKE_RETURN can be used. gone wrong. Returnvalues must be unique. For this the function `HasReturnvaluesIF::makeReturnCode`
The CLASS_ID is a unique id for that type of object. See returnvalues/FwClassIds. or the macro `MAKE_RETURN` can be used. The `CLASS_ID` is a unique id for that type of object.
See `returnvalues/FwClassIds` folder. The user can add custom `CLASS_ID`s via the
`fsfwconfig` folder.
### OSAL # OSAL
The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS.
The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes. The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes.
The [OSAL README](doc/README-osal.md#top) provides more detailed information on provided components and how to use them. The [OSAL README](doc/README-osal.md#top) provides more detailed information on provided components
and how to use them.
### Core Components # Core Components
The FSFW has following core components. More detailed informations can be found in the The FSFW has following core components. More detailed informations can be found in the
[core component section](doc/README-core.md#top): [core component section](doc/README-core.md#top):
1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks with fixed timeslots 1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks
2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID to the object handles. with fixed timeslots
3. Static Stores: Different stores are provided to store data of variable size (like telecommands or small telemetry) in a pool structure without 2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID
using dynamic memory allocation. These pools are allocated up front. to the object handles.
3. Static Stores: Different stores are provided to store data of variable size (like telecommands
or small telemetry) in a pool structure without using dynamic memory allocation.
These pools are allocated up front.
3. Clock: This module provided common time related functions 3. Clock: This module provided common time related functions
4. EventManager: This module allows routing of events generated by `SystemObjects` 4. EventManager: This module allows routing of events generated by `SystemObjects`
5. HealthTable: A component which stores the health states of objects 5. HealthTable: A component which stores the health states of objects
### Static IDs in the framework # Static IDs in the framework
Some parts of the framework use a static routing address for communication. Some parts of the framework use a static routing address for communication.
An example setup of ids can be found in the example config in "defaultcft/fsfwconfig/objects/Factory::setStaticFrameworkObjectIds()". An example setup of ids can be found in the example config in `defaultcft/fsfwconfig/objects`
inside the function `Factory::setStaticFrameworkObjectIds()`.
### Events # Events
Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT. This works analog to the returnvalues. Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT.
Every object that needs own EventIds has to get a unique SUBSYSTEM_ID. This works analog to the returnvalues. Every object that needs own EventIds has to get a
Every SystemObject can call triggerEvent from the parent class. unique SUBSYSTEM_ID. Every SystemObject can call triggerEvent from the parent class.
Therefore, event messages contain the specific EventId and the objectId of the object that has triggered. Therefore, event messages contain the specific EventId and the objectId of the object that
has triggered.
### Internal Communication # Internal Communication
Components communicate mostly over Message through Queues. Components communicate mostly via Messages through Queues.
Those queues are created by calling the singleton QueueFactory::instance()->create(). Those queues are created by calling the singleton `QueueFactory::instance()->create()` which
will create `MessageQueue` instances for the used OSAL.
### External Communication # External Communication
The external communication with the mission control system is mostly up to the user implementation. The external communication with the mission control system is mostly up to the user implementation.
The FSFW provides PUS Services which can be used to but don't need to be used. The FSFW provides PUS Services which can be used to but don't need to be used.
The services can be seen as a conversion from a TC to a message based communication and back. The services can be seen as a conversion from a TC to a message based communication and back.
#### CCSDS Frames, CCSDS Space Packets and PUS ## TMTC Communication
If the communication is based on CCSDS Frames and Space Packets, several classes can be used to distributed the packets to the corresponding services. Those can be found in tcdistribution. The FSFW provides some components to facilitate TMTC handling via the PUS commands.
If Space Packets are used, a timestamper must be created. For example, a UDP or TCP PUS server socket can be opened on a specific port using the
An example can be found in the timemanager folder, this uses CCSDSTime::CDS_short. files located in `osal/common`. The FSFW example uses this functionality to allow sending telecommands
and receiving telemetry using the [TMTC commander application](https://github.com/spacefisch/tmtccmd).
Simple commands like the PUS Service 17 ping service can be tested by simply running the
`tmtc_client_cli.py` or `tmtc_client_gui.py` utility in
the [example tmtc folder](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/tmtc)
while the `fsfw_example` application is running.
#### Device Handlers More generally, any class responsible for handling incoming telecommands and sending telemetry
can implement the generic `TmTcBridge` class located in `tmtcservices`. Many applications
also use a dedicated polling task for reading telecommands which passes telecommands
to the `TmTcBridge` implementation.
## CCSDS Frames, CCSDS Space Packets and PUS
If the communication is based on CCSDS Frames and Space Packets, several classes can be used to
distributed the packets to the corresponding services. Those can be found in `tcdistribution`.
If Space Packets are used, a timestamper has to be provided by the user.
An example can be found in the `timemanager` folder, which uses `CCSDSTime::CDS_short`.
# Device Handlers
DeviceHandlers are another important component of the FSFW. DeviceHandlers are another important component of the FSFW.
The idea is, to have a software counterpart of every physical device to provide a simple mode, health and commanding interface. The idea is, to have a software counterpart of every physical device to provide a simple mode,
By separating the underlying Communication Interface with DeviceCommunicationIF, a device handler (DH) can be tested on different hardware. health and commanding interface. By separating the underlying Communication Interface with
The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction. `DeviceCommunicationIF`, a device handler (DH) can be tested on different hardware.
Device Handlers can be created by overriding `DeviceHandlerBase`. The DH has mechanisms to monitor the communication with the physical device which allow
A standard FDIR component for the DH will be created automatically but can be overwritten by the user. for FDIR reaction. Device Handlers can be created by implementing `DeviceHandlerBase`.
More information on DeviceHandlers can be found in the related [documentation section](doc/README-devicehandlers.md#top). A standard FDIR component for the DH will be created automatically but can
be overwritten by the user. More information on DeviceHandlers can be found in the
related [documentation section](doc/README-devicehandlers.md#top).
#### Modes, Health # Modes and Health
The two interfaces HasModesIF and HasHealthIF provide access for commanding and monitoring of components. The two interfaces `HasModesIF` and `HasHealthIF` provide access for commanding and monitoring
On-board Mode Management is implement in hierarchy system. of components. On-board Mode Management is implement in hierarchy system.
DeviceHandlers and Controllers are the lowest part of the hierarchy. DeviceHandlers and Controllers are the lowest part of the hierarchy.
The next layer are Assemblies. Those assemblies act as a component which handle redundancies of handlers. The next layer are Assemblies. Those assemblies act as a component which handle
Assemblies share a common core with the next level which are the Subsystems. redundancies of handlers. Assemblies share a common core with the next level which
are the Subsystems.
Those Assemblies are intended to act as auto-generated components from a database which describes the subsystem modes. Those Assemblies are intended to act as auto-generated components from a database which describes
The definitions contain transition and target tables which contain the DH, Assembly and Controller Modes to be commanded. the subsystem modes. The definitions contain transition and target tables which contain the DH,
Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a switch into any higher AOCS mode might first turn on the sensors, than the actuators and the controller as last component. Assembly and Controller Modes to be commanded.
Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a
switch into any higher AOCS mode might first turn on the sensors, than the actuators and the
controller as last component.
The target table is used to describe the state that is checked continuously by the subsystem. The target table is used to describe the state that is checked continuously by the subsystem.
All of this allows System Modes to be generated as Subsystem object as well from the same database. All of this allows System Modes to be generated as Subsystem object as well from the same database.
This System contains list of subsystem modes in the transition and target tables. This System contains list of subsystem modes in the transition and target tables.
Therefore, it allows a modular system to create system modes and easy commanding of those, because only the highest components must be commanded. Therefore, it allows a modular system to create system modes and easy commanding of those, because
only the highest components must be commanded.
The health state represents if the component is able to perform its tasks. The health state represents if the component is able to perform its tasks.
This can be used to signal the system to avoid using this component instead of a redundant one. This can be used to signal the system to avoid using this component instead of a redundant one.
The on-board FDIR uses the health state for isolation and recovery. The on-board FDIR uses the health state for isolation and recovery.
## Unit Tests # Unit Tests
Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include catch2 itself. More information on how to run these tests can be found in the separate Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include
catch2 itself. More information on how to run these tests can be found in the separate
[`fsfw_tests` reposoitory](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests) [`fsfw_tests` reposoitory](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests)

View File

@ -1,8 +1,6 @@
#include "EventManager.h" #include "EventManager.h"
#include "EventMessage.h" #include "EventMessage.h"
#include <FSFWConfig.h>
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
@ -115,53 +113,6 @@ ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener,
return result; return result;
} }
#if FSFW_OBJ_EVENT_TRANSLATION == 1
void EventManager::printEvent(EventMessage* message) {
const char *string = 0;
switch (message->getSeverity()) {
case severity::INFO:
#if DEBUG_INFO_EVENT == 1
string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "EVENT: ";
if (string != 0) {
sif::info << string;
} else {
sif::info << "0x" << std::hex << message->getReporter() << std::dec;
}
sif::info << " reported " << translateEvents(message->getEvent()) << " ("
<< std::dec << message->getEventId() << std::hex << ") P1: 0x"
<< message->getParameter1() << " P2: 0x"
<< message->getParameter2() << std::dec << std::endl;
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* DEBUG_INFO_EVENT == 1 */
break;
default:
string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "EventManager: ";
if (string != 0) {
sif::debug << string;
}
else {
sif::debug << "0x" << std::hex << message->getReporter() << std::dec;
}
sif::debug << " reported " << translateEvents(message->getEvent())
<< " (" << std::dec << message->getEventId() << ") "
<< std::endl;
sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1()
<< ", P1 Dec: " << std::dec << message->getParameter1()
<< std::endl;
sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2()
<< ", P2 Dec: " << std::dec << message->getParameter2()
<< std::endl;
#endif
break;
}
}
#endif
void EventManager::lockMutex() { void EventManager::lockMutex() {
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
} }
@ -175,3 +126,85 @@ void EventManager::setMutexTimeout(MutexIF::TimeoutType timeoutType,
this->timeoutType = timeoutType; this->timeoutType = timeoutType;
this->timeoutMs = timeoutMs; this->timeoutMs = timeoutMs;
} }
#if FSFW_OBJ_EVENT_TRANSLATION == 1
void EventManager::printEvent(EventMessage* message) {
switch (message->getSeverity()) {
case severity::INFO: {
#if FSFW_DEBUG_INFO == 1
printUtility(sif::OutputTypes::OUT_INFO, message);
#endif /* DEBUG_INFO_EVENT == 1 */
break;
}
default:
printUtility(sif::OutputTypes::OUT_DEBUG, message);
break;
}
}
void EventManager::printUtility(sif::OutputTypes printType, EventMessage *message) {
const char *string = 0;
if(printType == sif::OutputTypes::OUT_INFO) {
string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "EventManager: ";
if (string != 0) {
sif::info << string;
}
else {
sif::info << "0x" << std::hex << std::setw(8) << std::setfill('0') <<
message->getReporter() << std::setfill(' ') << std::dec;
}
sif::info << " reported event with ID " << message->getEventId() << std::endl;
sif::debug << translateEvents(message->getEvent()) << " | " <<std::hex << "P1 Hex: 0x" <<
message->getParameter1() << " | P1 Dec: " << std::dec << message->getParameter1() <<
std::hex << " | P2 Hex: 0x" << message->getParameter2() << " | P2 Dec: " <<
std::dec << message->getParameter2() << std::endl;
#else
if (string != 0) {
sif::printInfo("Event Manager: %s reported event with ID %d\n", string,
message->getEventId());
}
else {
sif::printInfo("Event Manager: Reporter ID 0x%08x reported event with ID %d\n",
message->getReporter(), message->getEventId());
}
sif::printInfo("P1 Hex: 0x%x | P1 Dec: %d | P2 Hex: 0x%x | P2 Dec: %d\n",
message->getParameter1(), message->getParameter1(),
message->getParameter2(), message->getParameter2());
#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */
}
else {
string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "EventManager: ";
if (string != 0) {
sif::debug << string;
}
else {
sif::debug << "0x" << std::hex << std::setw(8) << std::setfill('0') <<
message->getReporter() << std::setfill(' ') << std::dec;
}
sif::debug << " reported event with ID " << message->getEventId() << std::endl;
sif::debug << translateEvents(message->getEvent()) << " | " <<std::hex << "P1 Hex: 0x" <<
message->getParameter1() << " | P1 Dec: " << std::dec << message->getParameter1() <<
std::hex << " | P2 Hex: 0x" << message->getParameter2() << " | P2 Dec: " <<
std::dec << message->getParameter2() << std::endl;
#else
if (string != 0) {
sif::printDebug("Event Manager: %s reported event with ID %d\n", string,
message->getEventId());
}
else {
sif::printDebug("Event Manager: Reporter ID 0x%08x reported event with ID %d\n",
message->getReporter(), message->getEventId());
}
sif::printDebug("P1 Hex: 0x%x | P1 Dec: %d | P2 Hex: 0x%x | P2 Dec: %d\n",
message->getParameter1(), message->getParameter1(),
message->getParameter2(), message->getParameter2());
#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */
}
}
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */

View File

@ -3,9 +3,9 @@
#include "EventManagerIF.h" #include "EventManagerIF.h"
#include "eventmatching/EventMatchTree.h" #include "eventmatching/EventMatchTree.h"
#include "FSFWConfig.h"
#include <FSFWConfig.h> #include "../serviceinterface/ServiceInterface.h"
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "../storagemanager/LocalPool.h" #include "../storagemanager/LocalPool.h"
#include "../tasks/ExecutableObjectIF.h" #include "../tasks/ExecutableObjectIF.h"
@ -67,6 +67,7 @@ protected:
#if FSFW_OBJ_EVENT_TRANSLATION == 1 #if FSFW_OBJ_EVENT_TRANSLATION == 1
void printEvent(EventMessage *message); void printEvent(EventMessage *message);
void printUtility(sif::OutputTypes printType, EventMessage* message);
#endif #endif
void lockMutex(); void lockMutex();

View File

@ -3,7 +3,7 @@
#include "EventMessage.h" #include "EventMessage.h"
#include "eventmatching/eventmatching.h" #include "eventmatching/eventmatching.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
#include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueSenderIF.h"
#include "../ipc/MessageQueueIF.h" #include "../ipc/MessageQueueIF.h"
#include "../serviceinterface/ServiceInterface.h" #include "../serviceinterface/ServiceInterface.h"
@ -43,7 +43,7 @@ public:
static void triggerEvent(EventMessage* message, static void triggerEvent(EventMessage* message,
MessageQueueId_t sentFrom = 0) { MessageQueueId_t sentFrom = 0) {
if (eventmanagerQueue == MessageQueueIF::NO_QUEUE) { if (eventmanagerQueue == MessageQueueIF::NO_QUEUE) {
EventManagerIF *eventmanager = objectManager->get<EventManagerIF>( EventManagerIF *eventmanager = ObjectManager::instance()->get<EventManagerIF>(
objects::EVENT_MANAGER); objects::EVENT_MANAGER);
if (eventmanager == nullptr) { if (eventmanager == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1

View File

@ -1,8 +1,10 @@
#ifndef FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ #ifndef FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
#define FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ #define FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
#include <cstdint>
namespace SUBSYSTEM_ID { namespace SUBSYSTEM_ID {
enum { enum: uint8_t {
MEMORY = 22, MEMORY = 22,
OBSW = 26, OBSW = 26,
CDH = 28, CDH = 28,
@ -19,12 +21,17 @@ enum {
SYSTEM_MANAGER_1 = 75, SYSTEM_MANAGER_1 = 75,
SYSTEM_1 = 79, SYSTEM_1 = 79,
PUS_SERVICE_1 = 80, PUS_SERVICE_1 = 80,
PUS_SERVICE_2 = 82,
PUS_SERVICE_3 = 83,
PUS_SERVICE_5 = 85,
PUS_SERVICE_6 = 86,
PUS_SERVICE_8 = 88,
PUS_SERVICE_9 = 89, PUS_SERVICE_9 = 89,
PUS_SERVICE_17 = 97, PUS_SERVICE_17 = 97,
PUS_SERVICE_23 = 103,
FW_SUBSYSTEM_ID_RANGE FW_SUBSYSTEM_ID_RANGE
}; };
} }
#endif /* FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ */ #endif /* FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ */

View File

@ -3,7 +3,7 @@
#include "../health/HasHealthIF.h" #include "../health/HasHealthIF.h"
#include "../health/HealthMessage.h" #include "../health/HealthMessage.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
FailureIsolationBase::FailureIsolationBase(object_id_t owner, FailureIsolationBase::FailureIsolationBase(object_id_t owner,
object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) : object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) :
@ -18,7 +18,7 @@ FailureIsolationBase::~FailureIsolationBase() {
} }
ReturnValue_t FailureIsolationBase::initialize() { ReturnValue_t FailureIsolationBase::initialize() {
EventManagerIF* manager = objectManager->get<EventManagerIF>( EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(
objects::EVENT_MANAGER); objects::EVENT_MANAGER);
if (manager == nullptr) { if (manager == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -36,7 +36,7 @@ ReturnValue_t FailureIsolationBase::initialize() {
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
owner = objectManager->get<HasHealthIF>(ownerId); owner = ObjectManager::instance()->get<HasHealthIF>(ownerId);
if (owner == nullptr) { if (owner == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FailureIsolationBase::intialize: Owner object " sif::error << "FailureIsolationBase::intialize: Owner object "
@ -46,7 +46,7 @@ ReturnValue_t FailureIsolationBase::initialize() {
} }
} }
if (faultTreeParent != objects::NO_OBJECT) { if (faultTreeParent != objects::NO_OBJECT) {
ConfirmsFailuresIF* parentIF = objectManager->get<ConfirmsFailuresIF>( ConfirmsFailuresIF* parentIF = ObjectManager::instance()->get<ConfirmsFailuresIF>(
faultTreeParent); faultTreeParent);
if (parentIF == nullptr) { if (parentIF == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1

View File

@ -5,6 +5,15 @@
void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, void arrayprinter::print(const uint8_t *data, size_t size, OutputType type,
bool printInfo, size_t maxCharPerLine) { bool printInfo, size_t maxCharPerLine) {
if(size == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Size is zero, nothing to print" << std::endl;
#else
sif::printInfo("Size is zero, nothing to print\n");
#endif
return;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
if(printInfo) { if(printInfo) {
sif::info << "Printing data with size " << size << ": " << std::endl; sif::info << "Printing data with size " << size << ": " << std::endl;

View File

@ -1,5 +1,5 @@
#include "HealthHelper.h" #include "HealthHelper.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) : HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) :
objectId(objectId), owner(owner) { objectId(objectId), owner(owner) {
@ -37,8 +37,8 @@ void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) {
} }
ReturnValue_t HealthHelper::initialize() { ReturnValue_t HealthHelper::initialize() {
healthTable = objectManager->get<HealthTableIF>(objects::HEALTH_TABLE); healthTable = ObjectManager::instance()->get<HealthTableIF>(objects::HEALTH_TABLE);
eventSender = objectManager->get<EventReportingProxyIF>(objectId); eventSender = ObjectManager::instance()->get<EventReportingProxyIF>(objectId);
if (healthTable == nullptr) { if (healthTable == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1

View File

@ -1,6 +1,6 @@
#include "HousekeepingMessage.h" #include "HousekeepingMessage.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
#include <cstring> #include <cstring>
HousekeepingMessage::~HousekeepingMessage() {} HousekeepingMessage::~HousekeepingMessage() {}
@ -161,7 +161,7 @@ void HousekeepingMessage::clear(CommandMessage* message) {
case(UPDATE_SNAPSHOT_VARIABLE): { case(UPDATE_SNAPSHOT_VARIABLE): {
store_address_t storeId; store_address_t storeId;
getHkDataReply(message, &storeId); getHkDataReply(message, &storeId);
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>( StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
objects::IPC_STORE); objects::IPC_STORE);
if (ipcStore != nullptr) { if (ipcStore != nullptr) {
ipcStore->deleteData(storeId); ipcStore->deleteData(storeId);

View File

@ -1,5 +1,6 @@
#include "CommandMessageCleaner.h" #include "CommandMessageCleaner.h"
#include "../memory/GenericFileSystemMessage.h"
#include "../devicehandlers/DeviceHandlerMessage.h" #include "../devicehandlers/DeviceHandlerMessage.h"
#include "../health/HealthMessage.h" #include "../health/HealthMessage.h"
#include "../memory/MemoryMessage.h" #include "../memory/MemoryMessage.h"
@ -42,6 +43,9 @@ void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) {
case messagetypes::HOUSEKEEPING: case messagetypes::HOUSEKEEPING:
HousekeepingMessage::clear(message); HousekeepingMessage::clear(message);
break; break;
case messagetypes::FILE_SYSTEM_MESSAGE:
GenericFileSystemMessage::clear(message);
break;
default: default:
messagetypes::clearMissionMessage(message); messagetypes::clearMissionMessage(message);
break; break;

View File

@ -22,11 +22,11 @@ public:
static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF;
//! No new messages on the queue //! No new messages on the queue
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1); static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1);
//! No space left for more messages //! [EXPORT] : [COMMENT] No space left for more messages
static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); static const ReturnValue_t FULL = MAKE_RETURN_CODE(2);
//! Returned if a reply method was called without partner //! [EXPORT] : [COMMENT] Returned if a reply method was called without partner
static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3); static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3);
//! Returned if the target destination is invalid. //! [EXPORT] : [COMMENT] Returned if the target destination is invalid.
static constexpr ReturnValue_t DESTINATION_INVALID = MAKE_RETURN_CODE(4); static constexpr ReturnValue_t DESTINATION_INVALID = MAKE_RETURN_CODE(4);
virtual ~MessageQueueIF() {} virtual ~MessageQueueIF() {}

View File

@ -1,5 +1,5 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE
MemoryHelper.cpp MemoryHelper.cpp
MemoryMessage.cpp MemoryMessage.cpp
GenericFileSystemMessage.cpp
) )

View File

@ -0,0 +1,161 @@
#include "GenericFileSystemMessage.h"
#include "../objectmanager/ObjectManager.h"
#include "../storagemanager/StorageManagerIF.h"
void GenericFileSystemMessage::setCreateFileCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_CREATE_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setDeleteFileCommand(
CommandMessage* message, store_address_t storeId) {
message->setCommand(CMD_DELETE_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setCreateDirectoryCommand(
CommandMessage* message, store_address_t storeId) {
message->setCommand(CMD_CREATE_DIRECTORY);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setReportFileAttributesCommand(CommandMessage *message,
store_address_t storeId) {
message->setCommand(CMD_REPORT_FILE_ATTRIBUTES);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setReportFileAttributesReply(CommandMessage *message,
store_address_t storeId) {
message->setCommand(REPLY_REPORT_FILE_ATTRIBUTES);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setDeleteDirectoryCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_DELETE_DIRECTORY);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setLockFileCommand(CommandMessage *message,
store_address_t storeId) {
message->setCommand(CMD_LOCK_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setUnlockFileCommand(CommandMessage *message,
store_address_t storeId) {
message->setCommand(CMD_UNLOCK_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setSuccessReply(CommandMessage *message) {
message->setCommand(COMPLETION_SUCCESS);
}
void GenericFileSystemMessage::setFailureReply(CommandMessage *message,
ReturnValue_t errorCode, uint32_t errorParam) {
message->setCommand(COMPLETION_FAILED);
message->setParameter(errorCode);
message->setParameter2(errorParam);
}
store_address_t GenericFileSystemMessage::getStoreId(const CommandMessage* message) {
store_address_t temp;
temp.raw = message->getParameter2();
return temp;
}
ReturnValue_t GenericFileSystemMessage::getFailureReply(
const CommandMessage *message, uint32_t* errorParam) {
if(errorParam != nullptr) {
*errorParam = message->getParameter2();
}
return message->getParameter();
}
void GenericFileSystemMessage::setFinishStopWriteCommand(CommandMessage *message,
store_address_t storeId) {
message->setCommand(CMD_FINISH_APPEND_TO_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setFinishStopWriteReply(CommandMessage *message,
store_address_t storeId) {
message->setCommand(REPLY_FINISH_APPEND);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setCopyCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_COPY_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setWriteCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_APPEND_TO_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setReadCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_READ_FROM_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setFinishAppendReply(CommandMessage* message,
store_address_t storageID) {
message->setCommand(REPLY_FINISH_APPEND);
message->setParameter2(storageID.raw);
}
void GenericFileSystemMessage::setReadReply(CommandMessage* message,
bool readFinished, store_address_t storeId) {
message->setCommand(REPLY_READ_FROM_FILE);
message->setParameter(readFinished);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setReadFinishedReply(CommandMessage *message,
store_address_t storeId) {
message->setCommand(REPLY_READ_FINISHED_STOP);
message->setParameter2(storeId.raw);
}
bool GenericFileSystemMessage::getReadReply(const CommandMessage *message,
store_address_t *storeId) {
if(storeId != nullptr) {
(*storeId).raw = message->getParameter2();
}
return message->getParameter();
}
ReturnValue_t GenericFileSystemMessage::clear(CommandMessage* message) {
switch(message->getCommand()) {
case(CMD_CREATE_FILE):
case(CMD_DELETE_FILE):
case(CMD_CREATE_DIRECTORY):
case(CMD_REPORT_FILE_ATTRIBUTES):
case(REPLY_REPORT_FILE_ATTRIBUTES):
case(CMD_LOCK_FILE):
case(CMD_UNLOCK_FILE):
case(CMD_COPY_FILE):
case(REPLY_READ_FROM_FILE):
case(CMD_READ_FROM_FILE):
case(CMD_APPEND_TO_FILE):
case(CMD_FINISH_APPEND_TO_FILE):
case(REPLY_READ_FINISHED_STOP):
case(REPLY_FINISH_APPEND): {
store_address_t storeId = GenericFileSystemMessage::getStoreId(message);
auto ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if(ipcStore == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return ipcStore->deleteData(storeId);
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,115 @@
#ifndef MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_
#define MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_
#include <cstdint>
#include <fsfw/ipc/CommandMessageIF.h>
#include <fsfw/ipc/FwMessageTypes.h>
#include <fsfw/ipc/CommandMessage.h>
#include <fsfw/storagemanager/storeAddress.h>
/**
* @brief These messages are sent to an object implementing HasFilesystemIF.
* @details
* Enables a message-based file management. The user can add custo commands be implementing
* this generic class.
* @author Jakob Meier, R. Mueller
*/
class GenericFileSystemMessage {
public:
/* Instantiation forbidden */
GenericFileSystemMessage() = delete;
static const uint8_t MESSAGE_ID = messagetypes::FILE_SYSTEM_MESSAGE;
/* PUS standard (ECSS-E-ST-70-41C15 2016 p.654) */
static const Command_t CMD_CREATE_FILE = MAKE_COMMAND_ID(1);
static const Command_t CMD_DELETE_FILE = MAKE_COMMAND_ID(2);
/** Report file attributes */
static const Command_t CMD_REPORT_FILE_ATTRIBUTES = MAKE_COMMAND_ID(3);
static const Command_t REPLY_REPORT_FILE_ATTRIBUTES = MAKE_COMMAND_ID(4);
/** Command to lock a file, setting it read-only */
static const Command_t CMD_LOCK_FILE = MAKE_COMMAND_ID(5);
/** Command to unlock a file, enabling further operations on it */
static const Command_t CMD_UNLOCK_FILE = MAKE_COMMAND_ID(6);
/**
* Find file in repository, using a search pattern.
* Please note that * is the wildcard character.
* For example, when looking for all files which start with have the
* structure tm<something>.bin, tm*.bin can be used.
*/
static const Command_t CMD_FIND_FILE = MAKE_COMMAND_ID(7);
static const Command_t CMD_CREATE_DIRECTORY = MAKE_COMMAND_ID(9);
static const Command_t CMD_DELETE_DIRECTORY = MAKE_COMMAND_ID(10);
static const Command_t CMD_RENAME_DIRECTORY = MAKE_COMMAND_ID(11);
/** Dump contents of a repository */
static const Command_t CMD_DUMP_REPOSITORY = MAKE_COMMAND_ID(12);
/** Repository dump reply */
static const Command_t REPLY_DUMY_REPOSITORY = MAKE_COMMAND_ID(13);
static constexpr Command_t CMD_COPY_FILE = MAKE_COMMAND_ID(14);
static constexpr Command_t CMD_MOVE_FILE = MAKE_COMMAND_ID(15);
static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(128);
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(129);
// These command IDs will remain until CFDP has been introduced and consolidated.
/** Append operation commands */
static const Command_t CMD_APPEND_TO_FILE = MAKE_COMMAND_ID(130);
static const Command_t CMD_FINISH_APPEND_TO_FILE = MAKE_COMMAND_ID(131);
static const Command_t REPLY_FINISH_APPEND = MAKE_COMMAND_ID(132);
static const Command_t CMD_READ_FROM_FILE = MAKE_COMMAND_ID(140);
static const Command_t REPLY_READ_FROM_FILE = MAKE_COMMAND_ID(141);
static const Command_t CMD_STOP_READ = MAKE_COMMAND_ID(142);
static const Command_t REPLY_READ_FINISHED_STOP = MAKE_COMMAND_ID(143);
static void setLockFileCommand(CommandMessage* message, store_address_t storeId);
static void setUnlockFileCommand(CommandMessage* message, store_address_t storeId);
static void setCreateFileCommand(CommandMessage* message,
store_address_t storeId);
static void setDeleteFileCommand(CommandMessage* message,
store_address_t storeId);
static void setReportFileAttributesCommand(CommandMessage* message,
store_address_t storeId);
static void setReportFileAttributesReply(CommandMessage* message,
store_address_t storeId);
static void setCreateDirectoryCommand(CommandMessage* message,
store_address_t storeId);
static void setDeleteDirectoryCommand(CommandMessage* message,
store_address_t storeId);
static void setSuccessReply(CommandMessage* message);
static void setFailureReply(CommandMessage* message,
ReturnValue_t errorCode, uint32_t errorParam = 0);
static void setCopyCommand(CommandMessage* message, store_address_t storeId);
static void setWriteCommand(CommandMessage* message,
store_address_t storeId);
static void setFinishStopWriteCommand(CommandMessage* message,
store_address_t storeId);
static void setFinishStopWriteReply(CommandMessage* message,
store_address_t storeId);
static void setFinishAppendReply(CommandMessage* message,
store_address_t storeId);
static void setReadCommand(CommandMessage* message,
store_address_t storeId);
static void setReadFinishedReply(CommandMessage* message,
store_address_t storeId);
static void setReadReply(CommandMessage* message, bool readFinished,
store_address_t storeId);
static bool getReadReply(const CommandMessage* message,
store_address_t* storeId);
static store_address_t getStoreId(const CommandMessage* message);
static ReturnValue_t getFailureReply(const CommandMessage* message,
uint32_t* errorParam = nullptr);
static ReturnValue_t clear(CommandMessage* message);
};
#endif /* MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_ */

View File

@ -2,9 +2,9 @@
#include "MemoryMessage.h" #include "MemoryMessage.h"
#include "../globalfunctions/CRC.h" #include "../globalfunctions/CRC.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
#include "../serialize/EndianConverter.h" #include "../serialize/EndianConverter.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
MemoryHelper::MemoryHelper(HasMemoryIF* workOnThis, MemoryHelper::MemoryHelper(HasMemoryIF* workOnThis,
MessageQueueIF* useThisQueue): MessageQueueIF* useThisQueue):
@ -187,7 +187,7 @@ ReturnValue_t MemoryHelper::initialize(MessageQueueIF* queueToUse_) {
} }
ReturnValue_t MemoryHelper::initialize() { ReturnValue_t MemoryHelper::initialize() {
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore != nullptr) { if (ipcStore != nullptr) {
return RETURN_OK; return RETURN_OK;
} else { } else {

View File

@ -1,6 +1,6 @@
#include "MemoryMessage.h" #include "MemoryMessage.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
uint32_t MemoryMessage::getAddress(const CommandMessage* message) { uint32_t MemoryMessage::getAddress(const CommandMessage* message) {
return message->getParameter(); return message->getParameter();
@ -44,7 +44,7 @@ void MemoryMessage::clear(CommandMessage* message) {
switch (message->getCommand()) { switch (message->getCommand()) {
case CMD_MEMORY_LOAD: case CMD_MEMORY_LOAD:
case REPLY_MEMORY_DUMP: { case REPLY_MEMORY_DUMP: {
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>( StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
objects::IPC_STORE); objects::IPC_STORE);
if (ipcStore != NULL) { if (ipcStore != NULL) {
ipcStore->deleteData(getStoreID(message)); ipcStore->deleteData(getStoreID(message));

View File

@ -1,13 +1,8 @@
/**
* @file LimitViolationReporter.cpp
* @brief This file defines the LimitViolationReporter class.
* @date 17.07.2014
* @author baetz
*/
#include "LimitViolationReporter.h" #include "LimitViolationReporter.h"
#include "MonitoringIF.h" #include "MonitoringIF.h"
#include "ReceivesMonitoringReportsIF.h" #include "ReceivesMonitoringReportsIF.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../objectmanager/ObjectManager.h"
#include "../serialize/SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF* data) { ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF* data) {
@ -16,7 +11,7 @@ ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF
return result; return result;
} }
store_address_t storeId; store_address_t storeId;
uint8_t* dataTarget = NULL; uint8_t* dataTarget = nullptr;
size_t maxSize = data->getSerializedSize(); size_t maxSize = data->getSerializedSize();
if (maxSize > MonitoringIF::VIOLATION_REPORT_MAX_SIZE) { if (maxSize > MonitoringIF::VIOLATION_REPORT_MAX_SIZE) {
return MonitoringIF::INVALID_SIZE; return MonitoringIF::INVALID_SIZE;
@ -38,16 +33,16 @@ ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF
ReturnValue_t LimitViolationReporter::checkClassLoaded() { ReturnValue_t LimitViolationReporter::checkClassLoaded() {
if (reportQueue == 0) { if (reportQueue == 0) {
ReceivesMonitoringReportsIF* receiver = objectManager->get< ReceivesMonitoringReportsIF* receiver = ObjectManager::instance()->get<
ReceivesMonitoringReportsIF>(reportingTarget); ReceivesMonitoringReportsIF>(reportingTarget);
if (receiver == NULL) { if (receiver == nullptr) {
return ObjectManagerIF::NOT_FOUND; return ObjectManagerIF::NOT_FOUND;
} }
reportQueue = receiver->getCommandQueue(); reportQueue = receiver->getCommandQueue();
} }
if (ipcStore == NULL) { if (ipcStore == nullptr) {
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == NULL) { if (ipcStore == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
@ -56,5 +51,5 @@ ReturnValue_t LimitViolationReporter::checkClassLoaded() {
//Lazy initialization. //Lazy initialization.
MessageQueueId_t LimitViolationReporter::reportQueue = 0; MessageQueueId_t LimitViolationReporter::reportQueue = 0;
StorageManagerIF* LimitViolationReporter::ipcStore = NULL; StorageManagerIF* LimitViolationReporter::ipcStore = nullptr;
object_id_t LimitViolationReporter::reportingTarget = 0; object_id_t LimitViolationReporter::reportingTarget = 0;

View File

@ -1,5 +1,5 @@
#include "MonitoringMessage.h" #include "MonitoringMessage.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
MonitoringMessage::~MonitoringMessage() { MonitoringMessage::~MonitoringMessage() {
} }
@ -25,7 +25,7 @@ void MonitoringMessage::clear(CommandMessage* message) {
message->setCommand(CommandMessage::CMD_NONE); message->setCommand(CommandMessage::CMD_NONE);
switch (message->getCommand()) { switch (message->getCommand()) {
case MonitoringMessage::LIMIT_VIOLATION_REPORT: { case MonitoringMessage::LIMIT_VIOLATION_REPORT: {
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>( StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
objects::IPC_STORE); objects::IPC_STORE);
if (ipcStore != NULL) { if (ipcStore != NULL) {
ipcStore->deleteData(getStoreId(message)); ipcStore->deleteData(getStoreId(message));

View File

@ -5,7 +5,7 @@
#include "MonitoringIF.h" #include "MonitoringIF.h"
#include "../datapoollocal/localPoolDefinitions.h" #include "../datapoollocal/localPoolDefinitions.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
#include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialBufferAdapter.h"
#include "../serialize/SerialFixedArrayListAdapter.h" #include "../serialize/SerialFixedArrayListAdapter.h"
#include "../serialize/SerializeElement.h" #include "../serialize/SerializeElement.h"
@ -71,7 +71,7 @@ private:
} }
bool checkAndSetStamper() { bool checkAndSetStamper() {
if (timeStamper == nullptr) { if (timeStamper == nullptr) {
timeStamper = objectManager->get<TimeStamperIF>( timeStamperId ); timeStamper = ObjectManager::instance()->get<TimeStamperIF>( timeStamperId );
if ( timeStamper == nullptr ) { if ( timeStamper == nullptr ) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MonitoringReportContent::checkAndSetStamper: " sif::error << "MonitoringReportContent::checkAndSetStamper: "

View File

@ -5,7 +5,7 @@
#include "../datapool/PIDReaderList.h" #include "../datapool/PIDReaderList.h"
#include "../health/HealthTableIF.h" #include "../health/HealthTableIF.h"
#include "../parameters/HasParametersIF.h" #include "../parameters/HasParametersIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
//SHOULDDO: This is by far not perfect. Could be merged with new Monitor classes. But still, it's over-engineering. //SHOULDDO: This is by far not perfect. Could be merged with new Monitor classes. But still, it's over-engineering.
@ -64,7 +64,7 @@ public:
return result; return result;
} }
ReturnValue_t initialize() { ReturnValue_t initialize() {
healthTable = objectManager->get<HealthTableIF>(objects::HEALTH_TABLE); healthTable = ObjectManager::instance()->get<HealthTableIF>(objects::HEALTH_TABLE);
if (healthTable == NULL) { if (healthTable == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -6,11 +6,23 @@
#endif #endif
#include <cstdlib> #include <cstdlib>
ObjectManager::ObjectManager( void (*setProducer)() ): ObjectManager* ObjectManager::objManagerInstance = nullptr;
produceObjects(setProducer) {
//There's nothing special to do in the constructor. ObjectManager* ObjectManager::instance() {
if(objManagerInstance == nullptr) {
objManagerInstance = new ObjectManager();
}
return objManagerInstance;
} }
void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc, void *factoryArgs) {
this->objectFactoryFunction = objFactoryFunc;
this->factoryArgs = factoryArgs;
}
ObjectManager::ObjectManager() {}
ObjectManager::~ObjectManager() { ObjectManager::~ObjectManager() {
for (auto const& iter : objectList) { for (auto const& iter : objectList) {
@ -28,10 +40,13 @@ ReturnValue_t ObjectManager::insert( object_id_t id, SystemObjectIF* object) {
return this->RETURN_OK; return this->RETURN_OK;
} else { } else {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::insert: Object id " << std::hex sif::error << "ObjectManager::insert: Object ID " << std::hex <<
<< static_cast<uint32_t>(id) << std::dec static_cast<uint32_t>(id) << std::dec << " is already in use!" << std::endl;
<< " is already in use!" << std::endl; sif::error << "Terminating program" << std::endl;
sif::error << "Terminating program." << std::endl; #else
sif::printError("ObjectManager::insert: Object ID 0x%08x is already in use!\n",
static_cast<unsigned int>(id));
sif::printError("Terminating program");
#endif #endif
//This is very severe and difficult to handle in other places. //This is very severe and difficult to handle in other places.
std::exit(INSERTION_FAILED); std::exit(INSERTION_FAILED);
@ -66,12 +81,8 @@ SystemObjectIF* ObjectManager::getSystemObject( object_id_t id ) {
} }
} }
ObjectManager::ObjectManager() : produceObjects(nullptr) {
}
void ObjectManager::initialize() { void ObjectManager::initialize() {
if(produceObjects == nullptr) { if(objectFactoryFunction == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::initialize: Passed produceObjects " sif::error << "ObjectManager::initialize: Passed produceObjects "
"functions is nullptr!" << std::endl; "functions is nullptr!" << std::endl;
@ -80,7 +91,7 @@ void ObjectManager::initialize() {
#endif #endif
return; return;
} }
this->produceObjects(); objectFactoryFunction(factoryArgs);
ReturnValue_t result = RETURN_FAILED; ReturnValue_t result = RETURN_FAILED;
uint32_t errorCount = 0; uint32_t errorCount = 0;
for (auto const& it : objectList) { for (auto const& it : objectList) {
@ -108,9 +119,9 @@ void ObjectManager::initialize() {
result = it.second->checkObjectConnections(); result = it.second->checkObjectConnections();
if ( result != RETURN_OK ) { if ( result != RETURN_OK ) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::ObjectManager: Object " << std::hex << sif::error << "ObjectManager::ObjectManager: Object 0x" << std::hex <<
(int) it.first << " connection check failed with code 0x" (int) it.first << " connection check failed with code 0x" << result <<
<< result << std::dec << std::endl; std::dec << std::endl;
#endif #endif
errorCount++; errorCount++;
} }

View File

@ -5,6 +5,7 @@
#include "SystemObjectIF.h" #include "SystemObjectIF.h"
#include <map> #include <map>
/** /**
* @brief This class implements a global object manager. * @brief This class implements a global object manager.
* @details This manager handles a list of available objects with system-wide * @details This manager handles a list of available objects with system-wide
@ -19,15 +20,32 @@
* @author Bastian Baetz * @author Bastian Baetz
*/ */
class ObjectManager : public ObjectManagerIF { class ObjectManager : public ObjectManagerIF {
private: public:
//comparison?
using produce_function_t = void (*) (void* args);
/** /**
* @brief This is the map of all initialized objects in the manager. * Returns the single instance of TaskFactory.
* @details Objects in the List must inherit the SystemObjectIF. * The implementation of #instance is found in its subclasses.
* Thus, we choose link-time variability of the instance.
*/ */
std::map<object_id_t, SystemObjectIF*> objectList; static ObjectManager* instance();
void setObjectFactoryFunction(produce_function_t prodFunc, void* args);
template <typename T> T* get( object_id_t id );
/**
* @brief In the class's destructor, all objects in the list are deleted.
*/
virtual ~ObjectManager();
ReturnValue_t insert(object_id_t id, SystemObjectIF* object) override;
ReturnValue_t remove(object_id_t id) override;
void initialize() override;
void printList() override;
protected: protected:
SystemObjectIF* getSystemObject( object_id_t id ); SystemObjectIF* getSystemObject(object_id_t id) override;
/** /**
* @brief This attribute is initialized with the factory function * @brief This attribute is initialized with the factory function
* that creates new objects. * that creates new objects.
@ -36,27 +54,25 @@ protected:
* @param The id of the object to be created. * @param The id of the object to be created.
* @return Returns a pointer to the newly created object or NULL. * @return Returns a pointer to the newly created object or NULL.
*/ */
void (*produceObjects)(); produce_function_t objectFactoryFunction = nullptr;
public: void* factoryArgs = nullptr;
/**
* @brief Apart from setting the producer function, nothing special private:
* happens in the constructor.
* @param setProducer A pointer to a factory function.
*/
ObjectManager( void (*produce)() );
ObjectManager(); ObjectManager();
/** /**
* @brief In the class's destructor, all objects in the list are deleted. * @brief This is the map of all initialized objects in the manager.
* @details Objects in the List must inherit the SystemObjectIF.
*/ */
// SHOULDDO: If, for some reason, deleting an ObjectManager instance is std::map<object_id_t, SystemObjectIF*> objectList;
// required, check if this works. static ObjectManager* objManagerInstance;
virtual ~ObjectManager( void );
ReturnValue_t insert( object_id_t id, SystemObjectIF* object );
ReturnValue_t remove( object_id_t id );
void initialize();
void printList();
}; };
// Documentation can be found in the class method declaration above
template <typename T>
T* ObjectManager::get( object_id_t id ) {
SystemObjectIF* temp = this->getSystemObject(id);
return dynamic_cast<T*>(temp);
}
#endif /* FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ */ #endif /* FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ */

View File

@ -4,15 +4,15 @@
#include "frameworkObjects.h" #include "frameworkObjects.h"
#include "SystemObjectIF.h" #include "SystemObjectIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
/** /**
* @brief This class provides an interface to the global object manager. * @brief This class provides an interface to the global object manager.
* @details This manager handles a list of available objects with system-wide * @details
* relevance, such as device handlers, and TM/TC services. They can be * This manager handles a list of available objects with system-wide relevance, such as device
* inserted, removed and retrieved from the list. On getting the * handlers, and TM/TC services. They can be inserted, removed and retrieved from the list.
* object, the call checks if the object implements the requested * On getting the object, the call checks if the object implements the requested interface.
* interface. * This interface does not specify a getter function because templates can't be used in interfaces.
* @author Bastian Baetz * @author Bastian Baetz
* @ingroup system_objects * @ingroup system_objects
*/ */
@ -21,7 +21,8 @@ public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF; static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF;
static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 );
static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 );
static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); //!< Can be used if the initialization of a SystemObject failed. //!< Can be used if the initialization of a SystemObject failed.
static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 );
static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 ); static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 );
protected: protected:
@ -49,22 +50,11 @@ public:
* @li RETURN_OK in case the object was successfully inserted * @li RETURN_OK in case the object was successfully inserted
*/ */
virtual ReturnValue_t insert( object_id_t id, SystemObjectIF* object ) = 0; virtual ReturnValue_t insert( object_id_t id, SystemObjectIF* object ) = 0;
/**
* @brief With the get call, interfaces of an object can be retrieved in
* a type-safe manner.
* @details With the template-based call, the object list is searched with the
* getSystemObject method and afterwards it is checked, if the object
* implements the requested interface (with a dynamic_cast).
* @param id The object id of the requested object.
* @return The method returns a pointer to an object implementing the
* requested interface, or NULL.
*/
template <typename T> T* get( object_id_t id );
/** /**
* @brief With this call, an object is removed from the list. * @brief With this call, an object is removed from the list.
* @param id The object id of the object to be removed. * @param id The object id of the object to be removed.
* @return \li NOT_FOUND in case the object was not found * @return @li NOT_FOUND in case the object was not found
* \li RETURN_OK in case the object was successfully removed * @li RETURN_OK in case the object was successfully removed
*/ */
virtual ReturnValue_t remove( object_id_t id ) = 0; virtual ReturnValue_t remove( object_id_t id ) = 0;
virtual void initialize() = 0; virtual void initialize() = 0;
@ -75,24 +65,4 @@ public:
virtual void printList() = 0; virtual void printList() = 0;
}; };
/**
* @brief This is the forward declaration of the global objectManager instance.
*/
// SHOULDDO: maybe put this in the glob namespace to explicitely mark it global?
extern ObjectManagerIF *objectManager;
/*Documentation can be found in the class method declaration above.*/
template <typename T>
T* ObjectManagerIF::get( object_id_t id ) {
if(objectManager == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManagerIF: Global object manager has not "
"been initialized yet!" << std::endl;
#endif
}
SystemObjectIF* temp = this->getSystemObject(id);
return dynamic_cast<T*>(temp);
}
#endif /* OBJECTMANAGERIF_H_ */ #endif /* OBJECTMANAGERIF_H_ */

View File

@ -5,17 +5,13 @@
SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) : SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) :
objectId(setObjectId), registered(doRegister) { objectId(setObjectId), registered(doRegister) {
if (registered) { if (registered) {
if(objectManager != nullptr) { ObjectManager::instance()->insert(objectId, this);
objectManager->insert(objectId, this);
}
} }
} }
SystemObject::~SystemObject() { SystemObject::~SystemObject() {
if (registered) { if (registered) {
if(objectManager != nullptr) { ObjectManager::instance()->remove(objectId);
objectManager->remove(objectId);
}
} }
} }

View File

@ -1,8 +1,9 @@
#ifndef FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ #ifndef FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_
#define FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ #define FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_
#include <fsfw/objectmanager/SystemObjectIF.h> #include "SystemObjectIF.h"
// The objects will be instantiated in the ID order
namespace objects { namespace objects {
enum framework_objects: object_id_t { enum framework_objects: object_id_t {
FSFW_OBJECTS_START = 0x53000000, FSFW_OBJECTS_START = 0x53000000,
@ -16,6 +17,7 @@ enum framework_objects: object_id_t {
PUS_SERVICE_17_TEST = 0x53000017, PUS_SERVICE_17_TEST = 0x53000017,
PUS_SERVICE_20_PARAMETERS = 0x53000020, PUS_SERVICE_20_PARAMETERS = 0x53000020,
PUS_SERVICE_200_MODE_MGMT = 0x53000200, PUS_SERVICE_200_MODE_MGMT = 0x53000200,
PUS_SERVICE_201_HEALTH = 0x53000201,
//Generic IDs for IPC, modes, health, events //Generic IDs for IPC, modes, health, events
HEALTH_TABLE = 0x53010000, HEALTH_TABLE = 0x53010000,

View File

@ -15,6 +15,7 @@ target_sources(${LIB_FSFW_NAME}
TaskFactory.cpp TaskFactory.cpp
Timekeeper.cpp Timekeeper.cpp
TaskManagement.cpp TaskManagement.cpp
QueueMapManager.cpp
) )
# FreeRTOS is required to link the FSFW now. It is recommended to compile # FreeRTOS is required to link the FSFW now. It is recommended to compile

View File

@ -134,71 +134,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
/ 3600.; / 3600.;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::checkOrCreateClockMutex() {
if (timeMutex == NULL) {
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,6 +1,7 @@
#include "FixedTimeslotTask.h" #include "FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../objectmanager/ObjectManager.h"
#include "../../serviceinterface/ServiceInterface.h"
uint32_t FixedTimeslotTask::deadlineMissedCount = 0; uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
@ -66,8 +67,7 @@ ReturnValue_t FixedTimeslotTask::startTask() {
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) { uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* handler = ExecutableObjectIF* handler = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
objectManager->get<ExecutableObjectIF>(componentId);
if (handler != nullptr) { if (handler != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, handler, this); pst.addSlot(componentId, slotTimeMs, executionStep, handler, this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;

View File

@ -1,26 +1,23 @@
#include "MessageQueue.h" #include "MessageQueue.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "QueueMapManager.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../objectmanager/ObjectManager.h"
#include "../../serviceinterface/ServiceInterface.h"
// TODO I guess we should have a way of checking if we are in an ISR and then
// use the "fromISR" versions of all calls
// As a first step towards this, introduces system context variable which needs
// to be switched manually
// Haven't found function to find system context.
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
maxMessageSize(maxMessageSize) { maxMessageSize(maxMessageSize) {
handle = xQueueCreate(messageDepth, maxMessageSize); handle = xQueueCreate(messageDepth, maxMessageSize);
#if FSFW_CPP_OSTREAM_ENABLED == 1
if (handle == nullptr) { if (handle == nullptr) {
sif::error << "MessageQueue::MessageQueue:" #if FSFW_CPP_OSTREAM_ENABLED == 1
<< " Creation failed." << std::endl; sif::error << "MessageQueue::MessageQueue: Creation failed" << std::endl;
sif::error << "Specified Message Depth: " << messageDepth sif::error << "Specified Message Depth: " << messageDepth << std::endl;
<< std::endl; sif::error << "Specified Maximum Message Size: " << maxMessageSize << std::endl;
sif::error << "Specified Maximum Message Size: " #else
<< maxMessageSize << std::endl; sif::printError("MessageQueue::MessageQueue: Creation failed\n");
sif::printError("Specified Message Depth: %d\n", messageDepth);
} sif::printError("Specified MAximum Message Size: %d\n", maxMessageSize);
#endif #endif
}
QueueMapManager::instance()->addMessageQueue(handle, &queueId);
} }
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {
@ -62,13 +59,15 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
callContext); callContext);
} }
QueueHandle_t MessageQueue::getNativeQueueHandle() {
return handle;
}
ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) {
if (result != pdPASS) { if (result != pdPASS) {
if (not ignoreFault) { if (not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter = objectManager-> InternalErrorReporterIF* internalErrorReporter = ObjectManager::instance()->
get<InternalErrorReporterIF>( get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != nullptr) { if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
@ -110,7 +109,7 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
} }
MessageQueueId_t MessageQueue::getId() const { MessageQueueId_t MessageQueue::getId() const {
return reinterpret_cast<MessageQueueId_t>(handle); return queueId;
} }
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
@ -132,29 +131,24 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault, CallContext callContext) { bool ignoreFault, CallContext callContext) {
BaseType_t result = pdFALSE; BaseType_t result = pdFALSE;
QueueHandle_t destination = nullptr; if(sendTo == MessageQueueIF::NO_QUEUE) {
if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) {
return MessageQueueIF::DESTINATION_INVALID; return MessageQueueIF::DESTINATION_INVALID;
} }
else {
destination = reinterpret_cast<QueueHandle_t>(sendTo); QueueHandle_t destination = QueueMapManager::instance()->getMessageQueue(sendTo);
if(destination == nullptr) {
return MessageQueueIF::DESTINATION_INVALID;
} }
message->setSender(sentFrom); message->setSender(sentFrom);
if(callContext == CallContext::TASK) { if(callContext == CallContext::TASK) {
result = xQueueSendToBack(destination, result = xQueueSendToBack(destination, static_cast<const void*>(message->getBuffer()), 0);
static_cast<const void*>(message->getBuffer()), 0);
} }
else { else {
/* If the call context is from an interrupt, /* If the call context is from an interrupt, request a context switch if a higher priority
* request a context switch if a higher priority task task was blocked by the interrupt. */
* was blocked by the interrupt. */
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
result = xQueueSendFromISR(reinterpret_cast<QueueHandle_t>(sendTo), result = xQueueSendFromISR(destination, static_cast<const void*>(message->getBuffer()),
static_cast<const void*>(message->getBuffer()),
&xHigherPriorityTaskWoken); &xHigherPriorityTaskWoken);
if(xHigherPriorityTaskWoken == pdTRUE) { if(xHigherPriorityTaskWoken == pdTRUE) {
TaskManagement::requestContextSwitch(callContext); TaskManagement::requestContextSwitch(callContext);

View File

@ -11,11 +11,6 @@
#include <freertos/queue.h> #include <freertos/queue.h>
#include <fsfw/ipc/MessageQueueMessage.h> #include <fsfw/ipc/MessageQueueMessage.h>
// TODO: this class assumes that MessageQueueId_t is the same size as void*
// (the FreeRTOS handle type), compiler will catch this but it might be nice
// to have something checking or even an always working solution
// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/
/** /**
* @brief This class manages sending and receiving of * @brief This class manages sending and receiving of
* message queue messages. * message queue messages.
@ -112,6 +107,8 @@ public:
bool isDefaultDestinationSet() const override; bool isDefaultDestinationSet() const override;
QueueHandle_t getNativeQueueHandle();
protected: protected:
/** /**
* @brief Implementation to be called from any send Call within * @brief Implementation to be called from any send Call within
@ -141,6 +138,8 @@ protected:
private: private:
bool defaultDestinationSet = false; bool defaultDestinationSet = false;
QueueHandle_t handle; QueueHandle_t handle;
MessageQueueId_t queueId = MessageQueueIF::NO_QUEUE;
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE; MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE; MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
const size_t maxMessageSize; const size_t maxMessageSize;

View File

@ -1,6 +1,7 @@
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../objectmanager/ObjectManager.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
@ -100,7 +101,7 @@ void PeriodicTask::taskFunctionality() {
} }
ReturnValue_t PeriodicTask::addComponent(object_id_t object) { ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>( ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(
object); object);
if (newObject == nullptr) { if (newObject == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1

View File

@ -0,0 +1,58 @@
#include "QueueMapManager.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexGuard.h"
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
QueueMapManager::QueueMapManager() {
mapLock = MutexFactory::instance()->createMutex();
}
QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager();
}
return QueueMapManager::mqManagerInstance;
}
ReturnValue_t QueueMapManager::addMessageQueue(QueueHandle_t queue, MessageQueueId_t* id) {
MutexGuard lock(mapLock);
uint32_t currentId = queueCounter++;
auto returnPair = queueMap.emplace(currentId, queue);
if(not returnPair.second) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "QueueMapManager::addMessageQueue This ID is already "
"inside the map!" << std::endl;
#else
sif::printError("QueueMapManager::addMessageQueue This ID is already "
"inside the map!\n");
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
if (id != nullptr) {
*id = currentId;
}
return HasReturnvaluesIF::RETURN_OK;
}
QueueHandle_t QueueMapManager::getMessageQueue(MessageQueueId_t messageQueueId) const {
auto queueIter = queueMap.find(messageQueueId);
if(queueIter != queueMap.end()) {
return queueIter->second;
}
else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "QueueMapManager::getQueueHandle: The ID " << messageQueueId <<
" does not exists in the map!" << std::endl;
#else
sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n",
messageQueueId);
#endif
}
return nullptr;
}
QueueMapManager::~QueueMapManager() {
MutexFactory::instance()->deleteMutex(mapLock);
}

View File

@ -0,0 +1,50 @@
#ifndef FSFW_OSAL_FREERTOS_QUEUEMAPMANAGER_H_
#define FSFW_OSAL_FREERTOS_QUEUEMAPMANAGER_H_
#include "../../ipc/MutexIF.h"
#include "../../ipc/messageQueueDefinitions.h"
#include "../../ipc/MessageQueueIF.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include <map>
using QueueMap = std::map<MessageQueueId_t, QueueHandle_t>;
class QueueMapManager {
public:
//! Returns the single instance of QueueMapManager
static QueueMapManager* instance();
/**
* Insert a message queue and the corresponding QueueHandle into the map
* @param queue The message queue to insert.
* @param id The passed value will be set unless a nullptr is passed
* @return
*/
ReturnValue_t addMessageQueue(QueueHandle_t queue, MessageQueueId_t* id);
/**
* Get the message queue handle by providing a message queue ID. Returns nullptr
* if the queue ID does not exist in the internal map.
* @param messageQueueId
* @return
*/
QueueHandle_t getMessageQueue(MessageQueueId_t messageQueueId) const;
private:
//! External instantiation forbidden. Constructor still required for singleton instantiation.
QueueMapManager();
~QueueMapManager();
uint32_t queueCounter = 0;
MutexIF* mapLock;
QueueMap queueMap;
static QueueMapManager* mqManagerInstance;
};
#endif /* FSFW_OSAL_FREERTOS_QUEUEMAPMANAGER_H_ */

View File

@ -5,6 +5,7 @@ if(DEFINED WIN32 OR DEFINED UNIX)
UdpTcPollingTask.cpp UdpTcPollingTask.cpp
UdpTmTcBridge.cpp UdpTmTcBridge.cpp
TcpTmTcServer.cpp TcpTmTcServer.cpp
TcpTmTcBridge.cpp
) )
endif() endif()

View File

@ -1,10 +1,9 @@
#include "TcpIpBase.h" #include "TcpIpBase.h"
#include "../../platform.h"
#ifdef __unix__ #ifdef PLATFORM_UNIX
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
TcpIpBase::TcpIpBase() { TcpIpBase::TcpIpBase() {
@ -37,17 +36,17 @@ TcpIpBase::~TcpIpBase() {
} }
int TcpIpBase::closeSocket(socket_t socket) { int TcpIpBase::closeSocket(socket_t socket) {
#ifdef _WIN32 #ifdef PLATFORM_WIN
return closesocket(socket); return closesocket(socket);
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
return close(socket); return close(socket);
#endif #endif
} }
int TcpIpBase::getLastSocketError() { int TcpIpBase::getLastSocketError() {
#ifdef _WIN32 #ifdef PLATFORM_WIN
return WSAGetLastError(); return WSAGetLastError();
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
return errno; return errno;
#endif #endif
} }

View File

@ -1,28 +1,25 @@
#ifndef FSFW_OSAL_COMMON_TCPIPIF_H_ #ifndef FSFW_OSAL_COMMON_TCPIPIF_H_
#define FSFW_OSAL_COMMON_TCPIPIF_H_ #define FSFW_OSAL_COMMON_TCPIPIF_H_
#include <fsfw/returnvalues/HasReturnvaluesIF.h> #include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../platform.h"
#ifdef _WIN32
#ifdef PLATFORM_WIN
#include <winsock2.h> #include <winsock2.h>
#elif defined(PLATFORM_UNIX)
#elif defined(__unix__)
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
class TcpIpBase { class TcpIpBase {
protected: protected:
#ifdef _WIN32 #ifdef PLATFORM_WIN
static constexpr int SHUT_RECV = SD_RECEIVE; static constexpr int SHUT_RECV = SD_RECEIVE;
static constexpr int SHUT_SEND = SD_SEND; static constexpr int SHUT_SEND = SD_SEND;
static constexpr int SHUT_BOTH = SD_BOTH; static constexpr int SHUT_BOTH = SD_BOTH;
using socket_t = SOCKET; using socket_t = SOCKET;
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
using socket_t = int; using socket_t = int;
static constexpr int INVALID_SOCKET = -1; static constexpr int INVALID_SOCKET = -1;

View File

@ -0,0 +1,77 @@
#include "TcpTmTcBridge.h"
#include "tcpipHelpers.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/ipc/MutexGuard.h>
#include <fsfw/osal/common/TcpTmTcBridge.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#elif defined(__unix__)
#include <netdb.h>
#include <arpa/inet.h>
#endif
const std::string TcpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
// Connection is always up, TM is requested by connecting to server and receiving packets
registerCommConnect();
}
ReturnValue_t TcpTmTcBridge::initialize() {
ReturnValue_t result = TmTcBridge::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcpTmTcBridge::initialize: TmTcBridge initialization failed!"
<< std::endl;
#else
sif::printError("TcpTmTcBridge::initialize: TmTcBridge initialization failed!\n");
#endif
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
TcpTmTcBridge::~TcpTmTcBridge() {
if(mutex != nullptr) {
MutexFactory::instance()->deleteMutex(mutex);
}
}
ReturnValue_t TcpTmTcBridge::handleTm() {
// Simply store the telemetry in the FIFO, the server will use it to access the TM
MutexGuard guard(mutex, timeoutType, mutexTimeoutMs);
TmTcMessage message;
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message);
result == HasReturnvaluesIF::RETURN_OK;
result = tmTcReceptionQueue->receiveMessage(&message))
{
status = storeDownlinkData(&message);
if(status != HasReturnvaluesIF::RETURN_OK) {
break;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
// Not used. The Server uses the FIFO to access and send the telemetry.
return HasReturnvaluesIF::RETURN_OK;
}
void TcpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType,
dur_millis_t timeoutMs) {
this->timeoutType = timeoutType;
this->mutexTimeoutMs = timeoutMs;
}

View File

@ -0,0 +1,71 @@
#ifndef FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_
#define FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_
#include "TcpIpBase.h"
#include "../../tmtcservices/TmTcBridge.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#elif defined(__unix__)
#include <sys/socket.h>
#endif
#include <string>
/**
* @brief This class should be used with the TcpTmTcServer to implement a TCP server
* for receiving and sending PUS telemetry and telecommands (TMTC)
* @details
* This bridge tasks takes care of filling a FIFO which generated telemetry. The TcpTmTcServer
* will take care of sending the telemetry stored in the FIFO if a client connects to the
* server. This bridge will also be the default destination for telecommands, but the telecommands
* will be relayed to a specified tcDestination directly.
*/
class TcpTmTcBridge:
public TmTcBridge {
friend class TcpTmTcServer;
public:
/* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_UDP_SERVER_PORT;
/**
* Constructor
* @param objectId Object ID of the TcpTmTcBridge.
* @param tcDestination Destination for received TC packets. Any received telecommands will
* be sent there directly. The destination object needs to implement
* AcceptsTelecommandsIF.
* @param tmStoreId TM store object ID. It is recommended to the default object ID
* @param tcStoreId TC store object ID. It is recommended to the default object ID
*/
TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId = objects::TM_STORE,
object_id_t tcStoreId = objects::TC_STORE);
virtual~ TcpTmTcBridge();
/**
* Set properties of internal mutex.
*/
void setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs);
ReturnValue_t initialize() override;
protected:
ReturnValue_t handleTm() override;
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
//! Access to the FIFO needs to be mutex protected because it is used by the bridge and
//! the server.
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
dur_millis_t mutexTimeoutMs = 20;
MutexIF* mutex;
};
#endif /* FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_ */

View File

@ -1,23 +1,33 @@
#include "TcpTmTcServer.h" #include "TcpTmTcServer.h"
#include "TcpTmTcBridge.h"
#include "tcpipHelpers.h" #include "tcpipHelpers.h"
#include "../../serviceinterface/ServiceInterface.h"
#ifdef _WIN32 #include "../../platform.h"
#include "../../container/SharedRingBuffer.h"
#include "../../ipc/MessageQueueSenderIF.h"
#include "../../ipc/MutexGuard.h"
#include "../../objectmanager/ObjectManager.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../tmtcservices/TmTcMessage.h"
#ifdef PLATFORM_WIN
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(PLATFORM_UNIX)
#elif defined(__unix__)
#include <netdb.h> #include <netdb.h>
#endif #endif
const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7301"; #ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED
const std::string TcpTmTcServer::DEFAULT_TCP_CLIENT_PORT = "7302"; #define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0
#endif
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge, const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7303";
std::string customTcpServerPort):
SystemObject(objectId), tcpPort(customTcpServerPort) { TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
size_t receptionBufferSize, std::string customTcpServerPort):
SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge),
tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) {
if(tcpPort == "") { if(tcpPort == "") {
tcpPort = DEFAULT_TCP_SERVER_PORT; tcpPort = DEFAULT_TCP_SERVER_PORT;
} }
@ -31,6 +41,18 @@ ReturnValue_t TcpTmTcServer::initialize() {
return result; return result;
} }
tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcpTmTcServer::initialize: TC store uninitialized!" << std::endl;
#else
sif::printError("TcpTmTcServer::initialize: TC store uninitialized!\n");
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = ObjectManager::instance()->get<TcpTmTcBridge>(tmtcBridgeId);
int retval = 0; int retval = 0;
struct addrinfo *addrResult = nullptr; struct addrinfo *addrResult = nullptr;
struct addrinfo hints = {}; struct addrinfo hints = {};
@ -40,34 +62,25 @@ ReturnValue_t TcpTmTcServer::initialize() {
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
// Listen to all addresses (0.0.0.0) by using AI_PASSIVE in the hint flags
retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult); retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult);
if (retval != 0) { if (retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcpTmTcServer: Retrieving address info failed!" <<
std::endl;
#endif
handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL); handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
/* Open TCP (stream) socket */ // Open TCP (stream) socket
listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype, listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype,
addrResult->ai_protocol); addrResult->ai_protocol);
if(listenerTcpSocket == INVALID_SOCKET) { if(listenerTcpSocket == INVALID_SOCKET) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcWinTcpServer: Socket creation failed!" << std::endl;
#endif
freeaddrinfo(addrResult); freeaddrinfo(addrResult);
handleError(Protocol::TCP, ErrorSources::SOCKET_CALL); handleError(Protocol::TCP, ErrorSources::SOCKET_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
// Bind to the address found by getaddrinfo
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen)); retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
if(retval == SOCKET_ERROR) { if(retval == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcpTmTcServer: Binding socket failed!" <<
std::endl;
#endif
freeaddrinfo(addrResult); freeaddrinfo(addrResult);
handleError(Protocol::TCP, ErrorSources::BIND_CALL); handleError(Protocol::TCP, ErrorSources::BIND_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@ -84,49 +97,130 @@ TcpTmTcServer::~TcpTmTcServer() {
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
using namespace tcpip; using namespace tcpip;
/* If a connection is accepted, the corresponding socket will be assigned to the new socket */ // If a connection is accepted, the corresponding socket will be assigned to the new socket
socket_t clientSocket = 0; socket_t connSocket = 0;
sockaddr clientSockAddr = {}; // sockaddr clientSockAddr = {};
socklen_t connectorSockAddrLen = 0; // socklen_t connectorSockAddrLen = 0;
int retval = 0; int retval = 0;
/* Listen for connection requests permanently for lifetime of program */ // Listen for connection requests permanently for lifetime of program
while(true) { while(true) {
retval = listen(listenerTcpSocket, currentBacklog); retval = listen(listenerTcpSocket, tcpBacklog);
if(retval == SOCKET_ERROR) { if(retval == SOCKET_ERROR) {
handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500); handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500);
continue; continue;
} }
clientSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen); //connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
connSocket = accept(listenerTcpSocket, nullptr, nullptr);
if(clientSocket == INVALID_SOCKET) { if(connSocket == INVALID_SOCKET) {
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500); handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
closeSocket(clientSocket); closeSocket(connSocket);
continue; continue;
}; };
retval = recv(clientSocket, reinterpret_cast<char*>(receptionBuffer.data()), handleServerOperation(connSocket);
receptionBuffer.size(), 0);
if(retval > 0) {
#if FSFW_TCP_RCV_WIRETAPPING_ENABLED == 1
sif::info << "TcpTmTcServer::performOperation: Received " << retval << " bytes."
std::endl;
#endif
handleError(Protocol::TCP, ErrorSources::RECV_CALL, 500);
}
else if(retval == 0) {
// Done, shut down connection and go back to listening for client requests
retval = shutdown(connSocket, SHUT_SEND);
if(retval != 0) {
handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL);
} }
else { closeSocket(connSocket);
}
/* Done, shut down connection */
retval = shutdown(clientSocket, SHUT_SEND);
closeSocket(clientSocket);
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
if(tmtcBridge == nullptr) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
/* Initialize the destination after task creation. This ensures
that the destination has already been set in the TMTC bridge. */
targetTcDestination = tmtcBridge->getRequestQueue();
tcStore = tmtcBridge->tcStore;
tmStore = tmtcBridge->tmStore;
return HasReturnvaluesIF::RETURN_OK;
}
void TcpTmTcServer::handleServerOperation(socket_t connSocket) {
int retval = 0;
do {
// Read all telecommands sent by the client
retval = recv(connSocket,
reinterpret_cast<char*>(receptionBuffer.data()),
receptionBuffer.capacity(),
tcpFlags);
if (retval > 0) {
handleTcReception(retval);
}
else if(retval == 0) {
// Client has finished sending telecommands, send telemetry now
handleTmSending(connSocket);
}
else {
// Should not happen
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL);
}
} while(retval > 0);
}
ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) {
#if FSFW_TCP_RECV_WIRETAPPING_ENABLED == 1
arrayprinter::print(receptionBuffer.data(), bytesRead);
#endif
store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRecvd);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning<< "TcpTmTcServer::handleServerOperation: Data storage failed." << std::endl;
sif::warning << "Packet size: " << bytesRecvd << std::endl;
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UdpTcPollingTask::handleSuccessfullTcRead: "
" Sending message to queue failed" << std::endl;
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
tcStore->deleteData(storeId);
}
return result;
}
void TcpTmTcServer::setTcpBacklog(uint8_t tcpBacklog) {
this->tcpBacklog = tcpBacklog;
}
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket) {
// Access to the FIFO is mutex protected because it is filled by the bridge
MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
store_address_t storeId;
while((not tmtcBridge->tmFifo->empty()) and
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
tmtcBridge->tmFifo->retrieve(&storeId);
// Using the store accessor will take care of deleting TM from the store automatically
ConstStorageAccessor storeAccessor(storeId);
ReturnValue_t result = tmStore->getData(storeId, storeAccessor);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
int retval = send(connSocket,
reinterpret_cast<const char*>(storeAccessor.data()),
storeAccessor.size(),
tcpTmFlags);
if(retval != static_cast<int>(storeAccessor.size())) {
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::SEND_CALL);
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,24 +1,40 @@
#ifndef FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ #ifndef FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_
#define FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ #define FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_
#include "TcpIpBase.h" #include "TcpIpBase.h"
#include "../../platform.h"
#include "../../ipc/messageQueueDefinitions.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../objectmanager/frameworkObjects.h"
#include "../../objectmanager/SystemObject.h" #include "../../objectmanager/SystemObject.h"
#include "../../storagemanager/StorageManagerIF.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
#ifdef __unix__ #ifdef PLATFORM_UNIX
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#include <string> #include <string>
#include <vector> #include <vector>
//! Debugging preprocessor define. class TcpTmTcBridge;
#define FSFW_TCP_RCV_WIRETAPPING_ENABLED 0
/** /**
* @brief Windows TCP server used to receive telecommands on a Windows Host * @brief TCP server implementation
* @details * @details
* Based on: https://docs.microsoft.com/en-us/windows/win32/winsock/complete-server-code * This server will run for the whole program lifetime and will take care of serving client
* requests on a specified TCP server port. This server was written in a generic way and
* can be used on Unix and on Windows systems.
*
* If a connection is accepted, the server will read all telecommands sent by a client and then
* send all telemetry currently found in the TMTC bridge FIFO.
*
* Reading telemetry without sending telecommands is possible by connecting, shutting down the
* send operation immediately and then reading the telemetry. It is therefore recommended to
* connect to the server regularly, even if no telecommands need to be sent.
*
* The server will listen to a specific port on all addresses (0.0.0.0).
*/ */
class TcpTmTcServer: class TcpTmTcServer:
public SystemObject, public SystemObject,
@ -27,27 +43,51 @@ class TcpTmTcServer:
public: public:
/* The ports chosen here should not be used by any other process. */ /* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_TCP_SERVER_PORT; static const std::string DEFAULT_TCP_SERVER_PORT;
static const std::string DEFAULT_TCP_CLIENT_PORT;
TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge, static constexpr size_t ETHERNET_MTU_SIZE = 1500;
/**
* TCP Server Constructor
* @param objectId Object ID of the TCP Server
* @param tmtcTcpBridge Object ID of the TCP TMTC Bridge object
* @param receptionBufferSize This will be the size of the reception buffer. Default buffer
* size will be the Ethernet MTU size
* @param customTcpServerPort The user can specify another port than the default (7301) here.
*/
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
size_t receptionBufferSize = ETHERNET_MTU_SIZE + 1,
std::string customTcpServerPort = ""); std::string customTcpServerPort = "");
virtual~ TcpTmTcServer(); virtual~ TcpTmTcServer();
void setTcpBacklog(uint8_t tcpBacklog);
ReturnValue_t initialize() override; ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t opCode) override; ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initializeAfterTaskCreation() override;
protected:
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
private: private:
//! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT;
TcpTmTcBridge* tmtcBridge = nullptr;
std::string tcpPort; std::string tcpPort;
int tcpFlags = 0;
socket_t listenerTcpSocket = 0; socket_t listenerTcpSocket = 0;
struct sockaddr tcpAddress; struct sockaddr tcpAddress;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
int tcpAddrLen = sizeof(tcpAddress); int tcpAddrLen = sizeof(tcpAddress);
int currentBacklog = 3; int tcpBacklog = 3;
std::vector<uint8_t> receptionBuffer; std::vector<uint8_t> receptionBuffer;
int tcpSockOpt = 0; int tcpSockOpt = 0;
int tcpTmFlags = 0;
void handleServerOperation(socket_t connSocket);
ReturnValue_t handleTcReception(size_t bytesRecvd);
ReturnValue_t handleTmSending(socket_t connSocket);
}; };
#endif /* FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ */ #endif /* FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ */

View File

@ -1,26 +1,24 @@
#include "UdpTcPollingTask.h" #include "UdpTcPollingTask.h"
#include "tcpipHelpers.h" #include "tcpipHelpers.h"
#include "../../platform.h"
#include "../../globalfunctions/arrayprinter.h" #include "../../globalfunctions/arrayprinter.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../objectmanager/ObjectManager.h"
#ifdef _WIN32
#ifdef PLATFORM_WIN
#include <winsock2.h> #include <winsock2.h>
#elif defined(PLATFORM_UNIX)
#else
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
//! Debugging preprocessor define. //! Debugging preprocessor define.
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0 #define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t maxRecvSize, object_id_t tmtcUdpBridge, size_t maxRecvSize,
double timeoutSeconds): SystemObject(objectId), double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) { tmtcBridgeId(tmtcUdpBridge) {
if(frameSize > 0) { if(frameSize > 0) {
this->frameSize = frameSize; this->frameSize = frameSize;
} }
@ -119,7 +117,7 @@ ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
} }
ReturnValue_t UdpTcPollingTask::initialize() { ReturnValue_t UdpTcPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE); tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) { if (tcStore == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UdpTcPollingTask::initialize: TC store uninitialized!" << std::endl; sif::error << "UdpTcPollingTask::initialize: TC store uninitialized!" << std::endl;
@ -127,7 +125,7 @@ ReturnValue_t UdpTcPollingTask::initialize() {
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
tmtcBridge = objectManager->get<UdpTmTcBridge>(tmtcBridgeId); tmtcBridge = ObjectManager::instance()->get<UdpTmTcBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) { if(tmtcBridge == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UdpTcPollingTask::initialize: Invalid TMTC bridge object!" << sif::error << "UdpTcPollingTask::initialize: Invalid TMTC bridge object!" <<
@ -155,7 +153,7 @@ ReturnValue_t UdpTcPollingTask::initializeAfterTaskCreation() {
} }
void UdpTcPollingTask::setTimeout(double timeoutSeconds) { void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
#ifdef _WIN32 #ifdef PLATFORM_WIN
DWORD timeoutMs = timeoutSeconds * 1000.0; DWORD timeoutMs = timeoutSeconds * 1000.0;
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD)); reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
@ -165,7 +163,7 @@ void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
"receive timeout failed with " << strerror(errno) << std::endl; "receive timeout failed with " << strerror(errno) << std::endl;
#endif #endif
} }
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
timeval tval; timeval tval;
tval = timevalOperations::toTimeval(timeoutSeconds); tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,

View File

@ -1,5 +1,5 @@
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ #ifndef FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ #define FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_
#include "UdpTmTcBridge.h" #include "UdpTmTcBridge.h"
#include "../../objectmanager/SystemObject.h" #include "../../objectmanager/SystemObject.h"
@ -9,8 +9,11 @@
#include <vector> #include <vector>
/** /**
* @brief This class should be used with the UdpTmTcBridge to implement a UDP server * @brief This class can be used with the UdpTmTcBridge to implement a UDP server
* for receiving and sending PUS TMTC. * for receiving and sending PUS TMTC.
* @details
* This task is exclusively used to poll telecommands from a given socket and transfer them
* to the FSFW software bus. It used the blocking recvfrom call to do this.
*/ */
class UdpTcPollingTask: class UdpTcPollingTask:
public TcpIpBase, public TcpIpBase,
@ -22,7 +25,7 @@ public:
//! 0.5 default milliseconds timeout for now. //! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {0, 500}; static constexpr timeval DEFAULT_TIMEOUT = {0, 500};
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
size_t maxRecvSize = 0, double timeoutSeconds = -1); size_t maxRecvSize = 0, double timeoutSeconds = -1);
virtual~ UdpTcPollingTask(); virtual~ UdpTcPollingTask();
@ -45,8 +48,6 @@ private:
object_id_t tmtcBridgeId = objects::NO_OBJECT; object_id_t tmtcBridgeId = objects::NO_OBJECT;
UdpTmTcBridge* tmtcBridge = nullptr; UdpTmTcBridge* tmtcBridge = nullptr;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
//! See: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom
int receptionFlags = 0; int receptionFlags = 0;
std::vector<uint8_t> receptionBuffer; std::vector<uint8_t> receptionBuffer;
@ -57,4 +58,4 @@ private:
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
}; };
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */ #endif /* FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_ */

View File

@ -1,27 +1,26 @@
#include "UdpTmTcBridge.h"
#include "tcpipHelpers.h" #include "tcpipHelpers.h"
#include <fsfw/serviceinterface/ServiceInterface.h> #include "../../platform.h"
#include <fsfw/ipc/MutexGuard.h> #include "../../serviceinterface/ServiceInterface.h"
#include <fsfw/osal/common/UdpTmTcBridge.h> #include "../../ipc/MutexGuard.h"
#ifdef _WIN32
#ifdef PLATFORM_WIN
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(PLATFORM_UNIX)
#elif defined(__unix__)
#include <netdb.h> #include <netdb.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
//! Debugging preprocessor define. //! Debugging preprocessor define.
#ifndef FSFW_UDP_SEND_WIRETAPPING_ENABLED
#define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0 #define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0
#endif
const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort): std::string udpServerPort, object_id_t tmStoreId, object_id_t tcStoreId):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
if(udpServerPort == "") { if(udpServerPort == "") {
this->udpServerPort = DEFAULT_UDP_SERVER_PORT; this->udpServerPort = DEFAULT_UDP_SERVER_PORT;
@ -38,7 +37,7 @@ ReturnValue_t UdpTmTcBridge::initialize() {
ReturnValue_t result = TmTcBridge::initialize(); ReturnValue_t result = TmTcBridge::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::initialize: TmTcBridge initialization failed!" sif::error << "UdpTmTcBridge::initialize: TmTcBridge initialization failed!"
<< std::endl; << std::endl;
#endif #endif
return result; return result;
@ -54,10 +53,10 @@ ReturnValue_t UdpTmTcBridge::initialize() {
/* Tell the user that we could not find a usable */ /* Tell the user that we could not find a usable */
/* Winsock DLL. */ /* Winsock DLL. */
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: " << sif::error << "UdpTmTcBridge::UdpTmTcBridge: WSAStartup failed with error: " <<
err << std::endl; err << std::endl;
#else #else
sif::printError("TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: %d\n", sif::printError("UdpTmTcBridge::UdpTmTcBridge: WSAStartup failed with error: %d\n",
err); err);
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@ -78,19 +77,12 @@ ReturnValue_t UdpTmTcBridge::initialize() {
getaddrinfo to assign the address 0.0.0.0 (any address) */ getaddrinfo to assign the address 0.0.0.0 (any address) */
int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult); int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult);
if (retval != 0) { if (retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::GETADDRINFO_CALL);
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Retrieving address info failed!" <<
std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol); serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol);
if(serverSocket == INVALID_SOCKET) { if(serverSocket == INVALID_SOCKET) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Could not open UDP socket!" <<
std::endl;
#endif
freeaddrinfo(addrResult); freeaddrinfo(addrResult);
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL); tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@ -102,10 +94,6 @@ ReturnValue_t UdpTmTcBridge::initialize() {
retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen)); retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
if(retval != 0) { if(retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::TmTcUdpBridge: Could not bind "
"local port (" << udpServerPort << ") to server socket!" << std::endl;
#endif
freeaddrinfo(addrResult); freeaddrinfo(addrResult);
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL); tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;

View File

@ -1,24 +1,26 @@
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_ #ifndef FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_ #define FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_
#include "TcpIpBase.h" #include "TcpIpBase.h"
#include "../../platform.h"
#include "../../tmtcservices/TmTcBridge.h" #include "../../tmtcservices/TmTcBridge.h"
#ifdef _WIN32 #ifdef PLATFORM_WIN
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(PLATFORM_UNIX)
#elif defined(__unix__)
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#include <string> #include <string>
/** /**
* @brief This class should be used with the UdpTcPollingTask to implement a UDP server * @brief This class can be used with the UdpTcPollingTask to implement a UDP server
* for receiving and sending PUS TMTC. * for receiving and sending PUS TMTC.
* @details
* This bridge task will take care of sending telemetry back to a UDP client if a connection
* was established and store them in a FIFO if this was not done yet. It is also be the default
* destination for telecommands, but the telecommands will be relayed to a specified tcDestination
* directly.
*/ */
class UdpTmTcBridge: class UdpTmTcBridge:
public TmTcBridge, public TmTcBridge,
@ -29,7 +31,8 @@ public:
static const std::string DEFAULT_UDP_SERVER_PORT; static const std::string DEFAULT_UDP_SERVER_PORT;
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort = ""); std::string udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
object_id_t tcStoreId = objects::TC_STORE);
virtual~ UdpTmTcBridge(); virtual~ UdpTmTcBridge();
/** /**
@ -56,5 +59,5 @@ private:
MutexIF* mutex; MutexIF* mutex;
}; };
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */ #endif /* FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_ */

View File

@ -32,9 +32,18 @@ void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std:
else if(errorSrc == ErrorSources::RECVFROM_CALL) { else if(errorSrc == ErrorSources::RECVFROM_CALL) {
srcString = "recvfrom call"; srcString = "recvfrom call";
} }
else if(errorSrc == ErrorSources::SEND_CALL) {
srcString = "send call";
}
else if(errorSrc == ErrorSources::SENDTO_CALL) {
srcString = "sendto call";
}
else if(errorSrc == ErrorSources::GETADDRINFO_CALL) { else if(errorSrc == ErrorSources::GETADDRINFO_CALL) {
srcString = "getaddrinfo call"; srcString = "getaddrinfo call";
} }
else if(errorSrc == ErrorSources::SHUTDOWN_CALL) {
srcString = "shutdown call";
}
else { else {
srcString = "unknown call"; srcString = "unknown call";
} }

View File

@ -29,7 +29,9 @@ enum class ErrorSources {
RECVFROM_CALL, RECVFROM_CALL,
LISTEN_CALL, LISTEN_CALL,
ACCEPT_CALL, ACCEPT_CALL,
SENDTO_CALL SEND_CALL,
SENDTO_CALL,
SHUTDOWN_CALL
}; };
void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr, void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr,

View File

@ -1,10 +1,12 @@
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../timemanager/Clock.h" #include "../../timemanager/Clock.h"
#include "../../platform.h"
#include <chrono> #include <chrono>
#if defined(WIN32)
#if defined(PLATFORM_WIN)
#include <sysinfoapi.h> #include <sysinfoapi.h>
#elif defined(LINUX) #elif defined(PLATFORM_UNIX)
#include <fstream> #include <fstream>
#endif #endif
@ -46,7 +48,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
} }
ReturnValue_t Clock::getClock_timeval(timeval* time) { ReturnValue_t Clock::getClock_timeval(timeval* time) {
#if defined(WIN32) #if defined(PLATFORM_WIN)
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now); auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto epoch = now.time_since_epoch(); auto epoch = now.time_since_epoch();
@ -54,7 +56,7 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
auto fraction = now - secondsChrono; auto fraction = now - secondsChrono;
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(fraction).count(); time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(fraction).count();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX) #elif defined(PLATFORM_UNIX)
timespec timeUnix; timespec timeUnix;
int status = clock_gettime(CLOCK_REALTIME,&timeUnix); int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
if(status!=0){ if(status!=0){
@ -85,14 +87,14 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval Clock::getUptime() { timeval Clock::getUptime() {
timeval timeval; timeval timeval;
#if defined(WIN32) #if defined(PLATFORM_WIN)
auto uptime = std::chrono::milliseconds(GetTickCount64()); auto uptime = std::chrono::milliseconds(GetTickCount64());
auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime); auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime);
timeval.tv_sec = secondsChrono.count(); timeval.tv_sec = secondsChrono.count();
auto fraction = uptime - secondsChrono; auto fraction = uptime - secondsChrono;
timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>( timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count(); fraction).count();
#elif defined(LINUX) #elif defined(PLATFORM_UNIX)
double uptimeSeconds; double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds)
{ {
@ -119,7 +121,6 @@ ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
/* Do some magic with chrono (C++20!) */ /* Do some magic with chrono (C++20!) */
/* Right now, the library doesn't have the new features to get the required values yet. /* Right now, the library doesn't have the new features to get the required values yet.
@ -170,71 +171,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
/ 3600.; / 3600.;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex == nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex == nullptr){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,18 +1,21 @@
#include "taskHelpers.h" #include "taskHelpers.h"
#include "../../platform.h"
#include "../../osal/host/FixedTimeslotTask.h" #include "../../osal/host/FixedTimeslotTask.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h" #include "../../osal/host/Mutex.h"
#include "../../osal/host/FixedTimeslotTask.h" #include "../../osal/host/FixedTimeslotTask.h"
#include "../../objectmanager/ObjectManager.h"
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#if defined(WIN32) #if defined(PLATFORM_WIN)
#include <windows.h> #include <windows.h>
#include "../windows/winTaskHelpers.h" #include "../windows/winTaskHelpers.h"
#elif defined(LINUX) #elif defined(PLATFORM_UNIX)
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -109,7 +112,7 @@ void FixedTimeslotTask::taskFunctionality() {
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) { uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* executableObject = objectManager-> ExecutableObjectIF* executableObject = ObjectManager::instance()->
get<ExecutableObjectIF>(componentId); get<ExecutableObjectIF>(componentId);
if (executableObject != nullptr) { if (executableObject != nullptr) {
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep,

View File

@ -1,18 +1,22 @@
#include "MessageQueue.h" #include "MessageQueue.h"
#include "QueueMapManager.h" #include "QueueMapManager.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../objectmanager/ObjectManager.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexGuard.h" #include "../../ipc/MutexGuard.h"
#include <cstring>
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
messageSize(maxMessageSize), messageDepth(messageDepth) { messageSize(maxMessageSize), messageDepth(messageDepth) {
queueLock = MutexFactory::instance()->createMutex(); queueLock = MutexFactory::instance()->createMutex();
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue:" sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl;
<< " Could not be created" << std::endl; #else
sif::printError("MessageQueue::MessageQueue: Could not be created\n");
#endif #endif
} }
} }
@ -119,15 +123,13 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
QueueMapManager::instance()->getMessageQueue(sendTo)); QueueMapManager::instance()->getMessageQueue(sendTo));
if(targetQueue == nullptr) { if(targetQueue == nullptr) {
if(not ignoreFault) { if(not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter = InternalErrorReporterIF* internalErrorReporter = ObjectManager::instance()->
objectManager->get<InternalErrorReporterIF>( get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != nullptr) { if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
} }
// TODO: Better returnvalue return MessageQueueIF::DESTINATION_INVALID;
return HasReturnvaluesIF::RETURN_FAILED;
} }
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) { if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
MutexGuard mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20); MutexGuard mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20);

View File

@ -217,15 +217,15 @@ private:
* @brief The class stores the queue id it got assigned. * @brief The class stores the queue id it got assigned.
* If initialization fails, the queue id is set to zero. * If initialization fails, the queue id is set to zero.
*/ */
MessageQueueId_t mqId = 0; MessageQueueId_t mqId = MessageQueueIF::NO_QUEUE;
size_t messageSize = 0; size_t messageSize = 0;
size_t messageDepth = 0; size_t messageDepth = 0;
MutexIF* queueLock; MutexIF* queueLock;
bool defaultDestinationSet = false; bool defaultDestinationSet = false;
MessageQueueId_t defaultDestination = 0; MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
MessageQueueId_t lastPartner = 0; MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
}; };
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */ #endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */

View File

@ -2,17 +2,19 @@
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include "taskHelpers.h" #include "taskHelpers.h"
#include "../../platform.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../objectmanager/ObjectManager.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#if defined(WIN32) #if defined(PLATFORM_WIN)
#include <processthreadsapi.h> #include <processthreadsapi.h>
#include <fsfw/osal/windows/winTaskHelpers.h> #include <fsfw/osal/windows/winTaskHelpers.h>
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -24,9 +26,9 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
// It is probably possible to set task priorities by using the native // It is probably possible to set task priorities by using the native
// task handles for Windows / Linux // task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
#if defined(_WIN32) #if defined(PLATFORM_WIN)
tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority); tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
// TODO: We could reuse existing code here. // TODO: We could reuse existing code here.
#endif #endif
tasks::insertTaskName(mainThread.get_id(), taskName); tasks::insertTaskName(mainThread.get_id(), taskName);
@ -102,7 +104,7 @@ void PeriodicTask::taskFunctionality() {
} }
ReturnValue_t PeriodicTask::addComponent(object_id_t object) { ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>( ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(
object); object);
if (newObject == nullptr) { if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;

View File

@ -23,9 +23,7 @@ QueueMapManager* QueueMapManager::instance() {
ReturnValue_t QueueMapManager::addMessageQueue( ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* queueToInsert, MessageQueueId_t* id) { MessageQueueIF* queueToInsert, MessageQueueId_t* id) {
/* Not thread-safe, but it is assumed all message queues are created at software initialization MutexGuard lock(mapLock);
now. If this is to be made thread-safe in the future, it propably would be sufficient to lock
the increment operation here. */
uint32_t currentId = queueCounter++; uint32_t currentId = queueCounter++;
auto returnPair = queueMap.emplace(currentId, queueToInsert); auto returnPair = queueMap.emplace(currentId, queueToInsert);
if(not returnPair.second) { if(not returnPair.second) {
@ -47,7 +45,6 @@ ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* QueueMapManager::getMessageQueue( MessageQueueIF* QueueMapManager::getMessageQueue(
MessageQueueId_t messageQueueId) const { MessageQueueId_t messageQueueId) const {
MutexGuard(mapLock, MutexIF::TimeoutType::WAITING, 50);
auto queueIter = queueMap.find(messageQueueId); auto queueIter = queueMap.find(messageQueueId);
if(queueIter != queueMap.end()) { if(queueIter != queueMap.end()) {
return queueIter->second; return queueIter->second;
@ -60,7 +57,7 @@ MessageQueueIF* QueueMapManager::getMessageQueue(
sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n", sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n",
messageQueueId); messageQueueId);
#endif #endif
return nullptr;
} }
return nullptr;
} }

View File

@ -15,7 +15,9 @@ using QueueMap = std::unordered_map<MessageQueueId_t, MessageQueueIF*>;
*/ */
class QueueMapManager { class QueueMapManager {
public: public:
//! Returns the single instance of SemaphoreFactory.
//! Returns the single instance of QueueMapManager.
static QueueMapManager* instance(); static QueueMapManager* instance();
/** /**
@ -27,14 +29,15 @@ public:
ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t* ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t*
id = nullptr); id = nullptr);
/** /**
* Get the message queue handle by providing a message queue ID. * Get the message queue handle by providing a message queue ID. Returns nullptr
* if the queue ID is not contained inside the internal map.
* @param messageQueueId * @param messageQueueId
* @return * @return
*/ */
MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const; MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const;
private: private:
//! External instantiation is forbidden. //! External instantiation is forbidden. Constructor still required for singleton instantiation.
QueueMapManager(); QueueMapManager();
~QueueMapManager(); ~QueueMapManager();

View File

@ -1,4 +1,5 @@
#include "BinarySemaphore.h" #include "BinarySemaphore.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterfacePrinter.h" #include "../../serviceinterface/ServiceInterfacePrinter.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
@ -44,10 +45,7 @@ ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
result = sem_timedwait(&handle, &timeOut); result = sem_timedwait(&handle, &timeOut);
if(result != 0 and errno == EINVAL) { if(result != 0 and errno == EINVAL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "sem_timedwait");
sif::debug << "BinarySemaphore::acquire: Invalid time value possible"
<< std::endl;
#endif
} }
} }
if(result == 0) { if(result == 0) {
@ -57,19 +55,21 @@ ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
switch(errno) { switch(errno) {
case(EAGAIN): case(EAGAIN):
// Operation could not be performed without blocking (for sem_trywait) // Operation could not be performed without blocking (for sem_trywait)
case(ETIMEDOUT): case(ETIMEDOUT): {
// Semaphore is 0 // Semaphore is 0
utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "ETIMEDOUT");
return SemaphoreIF::SEMAPHORE_TIMEOUT; return SemaphoreIF::SEMAPHORE_TIMEOUT;
case(EINVAL): }
case(EINVAL): {
// Semaphore invalid // Semaphore invalid
utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "EINVAL");
return SemaphoreIF::SEMAPHORE_INVALID; return SemaphoreIF::SEMAPHORE_INVALID;
case(EINTR): }
case(EINTR): {
// Call was interrupted by signal handler // Call was interrupted by signal handler
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "EINTR");
sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." return HasReturnvaluesIF::RETURN_FAILED;
"Code " << strerror(errno) << std::endl; }
#endif
/* No break */
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -91,11 +91,16 @@ ReturnValue_t BinarySemaphore::release(sem_t *handle) {
} }
switch(errno) { switch(errno) {
case(EINVAL): case(EINVAL): {
// Semaphore invalid // Semaphore invalid
utility::printUnixErrorGeneric(CLASS_NAME, "release", "EINVAL");
return SemaphoreIF::SEMAPHORE_INVALID; return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW): }
case(EOVERFLOW): {
// SEM_MAX_VALUE overflow. This should never happen // SEM_MAX_VALUE overflow. This should never happen
utility::printUnixErrorGeneric(CLASS_NAME, "release", "EOVERFLOW");
return HasReturnvaluesIF::RETURN_FAILED;
}
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -128,17 +133,14 @@ void BinarySemaphore::initSemaphore(uint8_t initCount) {
auto result = sem_init(&handle, true, initCount); auto result = sem_init(&handle, true, initCount);
if(result == -1) { if(result == -1) {
switch(errno) { switch(errno) {
case(EINVAL): case(EINVAL): {
// Value exceeds SEM_VALUE_MAX utility::printUnixErrorGeneric(CLASS_NAME, "initSemaphore", "EINVAL");
break;
}
case(ENOSYS): { case(ENOSYS): {
// System does not support process-shared semaphores // System does not support process-shared semaphores
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "initSemaphore", "ENOSYS");
sif::error << "BinarySemaphore: Init failed with " break;
<< strerror(errno) << std::endl;
#else
sif::printError("BinarySemaphore: Init failed with %s\n",
strerror(errno));
#endif
} }
} }
} }
@ -151,8 +153,7 @@ ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) {
// Binary Semaphore special case. // Binary Semaphore special case.
// This is a config error use lightweight printf is this is called // This is a config error use lightweight printf is this is called
// from an interrupt // from an interrupt
printf("BinarySemaphore::release: Value of binary semaphore greater" printf("BinarySemaphore::release: Value of binary semaphore greater than 1!\n");
" than 1!\n");
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return SemaphoreIF::SEMAPHORE_NOT_OWNED; return SemaphoreIF::SEMAPHORE_NOT_OWNED;

View File

@ -76,6 +76,7 @@ public:
static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount);
protected: protected:
sem_t handle; sem_t handle;
static constexpr const char* CLASS_NAME = "BinarySemaphore";
}; };
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */

View File

@ -15,6 +15,7 @@ target_sources(${LIB_FSFW_NAME}
TaskFactory.cpp TaskFactory.cpp
Timer.cpp Timer.cpp
tcpipHelpers.cpp tcpipHelpers.cpp
unixUtility.cpp
) )
find_package(Threads REQUIRED) find_package(Threads REQUIRED)

View File

@ -153,71 +153,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
/ 3600.; / 3600.;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex==NULL){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex == nullptr){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,4 +1,6 @@
#include "../../osal/linux/CountingSemaphore.h" #include "CountingSemaphore.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
#include <errno.h> #include <errno.h>
@ -7,8 +9,11 @@ CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount):
maxCount(maxCount), initCount(initCount) { maxCount(maxCount), initCount(initCount) {
if(initCount > maxCount) { if(initCount > maxCount) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CountingSemaphoreUsingTask: Max count bigger than " sif::warning << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl; "intial cout. Setting initial count to max count" << std::endl;
#else
sif::printWarning("CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count\n");
#endif #endif
initCount = maxCount; initCount = maxCount;
} }
@ -42,11 +47,18 @@ ReturnValue_t CountingSemaphore::release(sem_t* handle) {
} }
switch(errno) { switch(errno) {
case(EINVAL): case(EINVAL): {
// Semaphore invalid // Semaphore invalid
utility::printUnixErrorGeneric("CountingSemaphore", "release", "EINVAL");
return SemaphoreIF::SEMAPHORE_INVALID; return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW): }
case(EOVERFLOW): {
// SEM_MAX_VALUE overflow. This should never happen // SEM_MAX_VALUE overflow. This should never happen
utility::printUnixErrorGeneric("CountingSemaphore", "release", "EOVERFLOW");
return SemaphoreIF::SEMAPHORE_INVALID;
}
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -1,5 +1,7 @@
#include "FixedTimeslotTask.h" #include "FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../objectmanager/ObjectManager.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <limits.h> #include <limits.h>
@ -40,7 +42,7 @@ uint32_t FixedTimeslotTask::getPeriodMs() const {
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) { uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* executableObject = ExecutableObjectIF* executableObject =
objectManager->get<ExecutableObjectIF>(componentId); ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
if (executableObject != nullptr) { if (executableObject != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, pst.addSlot(componentId, slotTimeMs, executionStep,
executableObject,this); executableObject,this);

View File

@ -1,6 +1,8 @@
#include "MessageQueue.h" #include "MessageQueue.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManager.h"
#include <fstream> #include <fstream>
@ -12,9 +14,7 @@
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize):
id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE), id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE),
defaultDestination(MessageQueueIF::NO_QUEUE), defaultDestination(MessageQueueIF::NO_QUEUE), maxMessageSize(maxMessageSize) {
maxMessageSize(maxMessageSize) {
//debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl;
mq_attr attributes; mq_attr attributes;
this->id = 0; this->id = 0;
//Set attributes //Set attributes
@ -31,7 +31,7 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize):
mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH; mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH;
mqd_t tempId = mq_open(name, oflag, mode, &attributes); mqd_t tempId = mq_open(name, oflag, mode, &attributes);
if (tempId == -1) { if (tempId == -1) {
handleError(&attributes, messageDepth); handleOpenError(&attributes, messageDepth);
} }
else { else {
//Successful mq_open call //Successful mq_open call
@ -42,102 +42,14 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize):
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {
int status = mq_close(this->id); int status = mq_close(this->id);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "~MessageQueue", "close");
sif::error << "MessageQueue::Destructor: mq_close Failed with status: "
<< strerror(errno) <<std::endl;
#endif
} }
status = mq_unlink(name); status = mq_unlink(name);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "~MessageQueue", "unlink");
sif::error << "MessageQueue::Destructor: mq_unlink Failed with status: "
<< strerror(errno) << std::endl;
#endif
} }
} }
ReturnValue_t MessageQueue::handleError(mq_attr* attributes,
uint32_t messageDepth) {
switch(errno) {
case(EINVAL): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue: Invalid name or attributes"
" for message size" << std::endl;
#endif
size_t defaultMqMaxMsg = 0;
// Not POSIX conformant, but should work for all UNIX systems.
// Just an additional helpful printout :-)
if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >>
defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) {
/*
See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html
This happens if the msg_max value is not large enough
It is ignored if the executable is run in privileged mode.
Run the unlockRealtime script or grant the mode manually by using:
sudo setcap 'CAP_SYS_RESOURCE=+ep' <pathToBinary>
Persistent solution for session:
echo <newMsgMax> | sudo tee /proc/sys/fs/mqueue/msg_max
Permanent solution:
sudo nano /etc/sysctl.conf
Append at end: fs/mqueue/msg_max = <newMsgMaxLen>
Apply changes with: sudo sysctl -p
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue: Default MQ size "
<< defaultMqMaxMsg << " is too small for requested size "
<< messageDepth << std::endl;
sif::error << "This error can be fixed by setting the maximum "
"allowed message size higher!" << std::endl;
#endif
}
break;
}
case(EEXIST): {
// An error occured during open
// We need to distinguish if it is caused by an already created queue
//There's another queue with the same name
//We unlink the other queue
int status = mq_unlink(name);
if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "mq_unlink Failed with status: " << strerror(errno)
<< std::endl;
#endif
}
else {
// Successful unlinking, try to open again
mqd_t tempId = mq_open(name,
O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL,
S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes);
if (tempId != -1) {
//Successful mq_open
this->id = tempId;
return HasReturnvaluesIF::RETURN_OK;
}
}
break;
}
default: {
// Failed either the first time or the second time
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue: Creating Queue " << name
<< " failed with status: " << strerror(errno) << std::endl;
#else
sif::printError("MessageQueue::MessageQueue: Creating Queue %s"
" failed with status: %s\n", name, strerror(errno));
#endif
}
}
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault) { MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), false); return sendMessageFrom(sendTo, message, this->getId(), false);
@ -204,14 +116,12 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
//O_NONBLOCK or MQ_NONBLOCK was set and there are no messages //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages
//currently on the specified queue. //currently on the specified queue.
return MessageQueueIF::EMPTY; return MessageQueueIF::EMPTY;
case EBADF: case EBADF: {
//mqdes doesn't represent a valid queue open for reading. //mqdes doesn't represent a valid queue open for reading.
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EBADF");
sif::error << "MessageQueue::receive: configuration error " break;
<< strerror(errno) << std::endl; }
#endif case EINVAL: {
/*NO BREAK*/
case EINVAL:
/* /*
* This value indicates one of the following: * This value indicates one of the following:
* - The pointer to the buffer for storing the received message, * - The pointer to the buffer for storing the received message,
@ -221,12 +131,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
* queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't * queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't
* been set in the queue's mq_flags. * been set in the queue's mq_flags.
*/ */
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EINVAL");
sif::error << "MessageQueue::receive: configuration error " break;
<< strerror(errno) << std::endl; }
#endif case EMSGSIZE: {
/*NO BREAK*/
case EMSGSIZE:
/* /*
* This value indicates one of the following: * This value indicates one of the following:
* - the QNX extended option MQ_READBUF_DYNAMIC hasn't been set, * - the QNX extended option MQ_READBUF_DYNAMIC hasn't been set,
@ -236,18 +144,25 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
* given msg_len is too short for the message that would have * given msg_len is too short for the message that would have
* been received. * been received.
*/ */
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EMSGSIZE");
sif::error << "MessageQueue::receive: configuration error " break;
<< strerror(errno) << std::endl;
#endif
/*NO BREAK*/
case EINTR:
//The operation was interrupted by a signal.
default:
return HasReturnvaluesIF::RETURN_FAILED;
} }
case EINTR: {
//The operation was interrupted by a signal.
utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EINTR");
break;
}
case ETIMEDOUT: {
//The operation was interrupted by a signal.
utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "ETIMEDOUT");
break;
}
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
@ -262,29 +177,27 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
switch(errno){ switch(errno){
case EBADF: case EBADF:
//mqdes doesn't represent a valid message queue. //mqdes doesn't represent a valid message queue.
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EBADF");
sif::error << "MessageQueue::flush configuration error, " break;
"called flush with an invalid queue ID" << std::endl;
#endif
/*NO BREAK*/ /*NO BREAK*/
case EINVAL: case EINVAL:
//mq_attr is NULL //mq_attr is NULL
utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EINVAL");
break;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_FAILED;
} }
*count = attrib.mq_curmsgs; *count = attrib.mq_curmsgs;
attrib.mq_curmsgs = 0; attrib.mq_curmsgs = 0;
status = mq_setattr(id,&attrib,NULL); status = mq_setattr(id,&attrib,NULL);
if(status != 0){ if(status != 0){
switch(errno){ switch(errno) {
case EBADF: case EBADF:
//mqdes doesn't represent a valid message queue. //mqdes doesn't represent a valid message queue.
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EBADF");
sif::error << "MessageQueue::flush configuration error, " break;
"called flush with an invalid queue ID" << std::endl;
#endif
/*NO BREAK*/
case EINVAL: case EINVAL:
/* /*
* This value indicates one of the following: * This value indicates one of the following:
@ -293,9 +206,12 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
* mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once * mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once
* MQ_MULT_NOTIFY has been turned on, it may never be turned off. * MQ_MULT_NOTIFY has been turned on, it may never be turned off.
*/ */
utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EINVAL");
break;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -336,8 +252,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
bool ignoreFault) { bool ignoreFault) {
if(message == nullptr) { if(message == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is " sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr!" << std::endl;
"nullptr!" << std::endl; #else
sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr!\n");
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -350,9 +267,8 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
//TODO: Check if we're in ISR. //TODO: Check if we're in ISR.
if (result != 0) { if (result != 0) {
if(!ignoreFault){ if(!ignoreFault){
InternalErrorReporterIF* internalErrorReporter = InternalErrorReporterIF* internalErrorReporter = ObjectManager::instance()->
objectManager->get<InternalErrorReporterIF>( get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != NULL) { if (internalErrorReporter != NULL) {
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
@ -366,17 +282,20 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
case EBADF: { case EBADF: {
//mq_des doesn't represent a valid message queue descriptor, //mq_des doesn't represent a valid message queue descriptor,
//or mq_des wasn't opened for writing. //or mq_des wasn't opened for writing.
utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EBADF");
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::sendMessage: Configuration error, MQ" sif::warning << "mq_send to: " << sendTo << " sent from "
<< " destination invalid." << std::endl; << sentFrom << "failed" << std::endl;
sif::error << strerror(errno) << " in " #else
<<"mq_send to: " << sendTo << " sent from " sif::printWarning("mq_send to: %d sent from %d failed\n", sendTo, sentFrom);
<< sentFrom << std::endl;
#endif #endif
return DESTINATION_INVALID; return DESTINATION_INVALID;
} }
case EINTR: case EINTR:
//The call was interrupted by a signal. //The call was interrupted by a signal.
utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EINTR");
break;
case EINVAL: case EINVAL:
/* /*
* This value indicates one of the following: * This value indicates one of the following:
@ -387,22 +306,87 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
* - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and * - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and
* msg_prio is greater than the priority of the calling process. * msg_prio is greater than the priority of the calling process.
*/ */
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EINVAL");
sif::error << "MessageQueue::sendMessage: Configuration error " break;
<< strerror(errno) << " in mq_send" << std::endl;
#endif
/*NO BREAK*/
case EMSGSIZE: case EMSGSIZE:
// The msg_len is greater than the msgsize associated with // The msg_len is greater than the msgsize associated with
//the specified queue. //the specified queue.
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EMSGSIZE");
sif::error << "MessageQueue::sendMessage: Size error [" << break;
strerror(errno) << "] in mq_send" << std::endl;
#endif
/*NO BREAK*/
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t MessageQueue::handleOpenError(mq_attr* attributes,
uint32_t messageDepth) {
switch(errno) {
case(EINVAL): {
utility::printUnixErrorGeneric(CLASS_NAME, "MessageQueue", "EINVAL");
size_t defaultMqMaxMsg = 0;
// Not POSIX conformant, but should work for all UNIX systems.
// Just an additional helpful printout :-)
if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >>
defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) {
/*
See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html
This happens if the msg_max value is not large enough
It is ignored if the executable is run in privileged mode.
Run the unlockRealtime script or grant the mode manually by using:
sudo setcap 'CAP_SYS_RESOURCE=+ep' <pathToBinary>
Persistent solution for session:
echo <newMsgMax> | sudo tee /proc/sys/fs/mqueue/msg_max
Permanent solution:
sudo nano /etc/sysctl.conf
Append at end: fs/mqueue/msg_max = <newMsgMaxLen>
Apply changes with: sudo sysctl -p
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue: Default MQ size " << defaultMqMaxMsg <<
" is too small for requested size " << messageDepth << std::endl;
sif::error << "This error can be fixed by setting the maximum "
"allowed message size higher!" << std::endl;
#else
sif::printError("MessageQueue::MessageQueue: Default MQ size %d is too small for"
"requested size %d\n");
sif::printError("This error can be fixes by setting the maximum allowed"
"message size higher!\n");
#endif
}
break;
}
case(EEXIST): {
// An error occured during open.
// We need to distinguish if it is caused by an already created queue
// There's another queue with the same name
// We unlink the other queue
int status = mq_unlink(name);
if (status != 0) {
utility::printUnixErrorGeneric(CLASS_NAME, "MessageQueue", "EEXIST");
}
else {
// Successful unlinking, try to open again
mqd_t tempId = mq_open(name,
O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL,
S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes);
if (tempId != -1) {
//Successful mq_open
this->id = tempId;
return HasReturnvaluesIF::RETURN_OK;
}
}
break;
}
default: {
// Failed either the first time or the second time
utility::printUnixErrorGeneric(CLASS_NAME, "MessageQueue", "Unknown");
}
}
return HasReturnvaluesIF::RETURN_FAILED;
}

View File

@ -181,7 +181,8 @@ private:
static uint16_t queueCounter; static uint16_t queueCounter;
const size_t maxMessageSize; const size_t maxMessageSize;
ReturnValue_t handleError(mq_attr* attributes, uint32_t messageDepth); static constexpr const char* CLASS_NAME = "MessageQueue";
ReturnValue_t handleOpenError(mq_attr* attributes, uint32_t messageDepth);
}; };
#endif /* FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ */ #endif /* FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ */

View File

@ -1,43 +1,34 @@
#include "Mutex.h" #include "Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../timemanager/Clock.h" #include "../../timemanager/Clock.h"
uint8_t Mutex::count = 0;
#include <cstring> #include <cstring>
#include <errno.h> #include <errno.h>
uint8_t Mutex::count = 0;
Mutex::Mutex() { Mutex::Mutex() {
pthread_mutexattr_t mutexAttr; pthread_mutexattr_t mutexAttr;
int status = pthread_mutexattr_init(&mutexAttr); int status = pthread_mutexattr_init(&mutexAttr);
if (status != 0) { if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutexattr_init");
sif::error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl;
#endif
} }
status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT); status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT);
if (status != 0) { if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutexattr_setprotocol");
sif::error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status)
<< std::endl;
#endif
} }
status = pthread_mutex_init(&mutex, &mutexAttr); status = pthread_mutex_init(&mutex, &mutexAttr);
if (status != 0) { if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutex_init");
sif::error << "Mutex: creation with name, id " << mutex.__data.__count
<< ", " << " failed with " << strerror(status) << std::endl;
#endif
} }
// After a mutex attributes object has been used to initialize one or more // After a mutex attributes object has been used to initialize one or more
// mutexes, any function affecting the attributes object // mutexes, any function affecting the attributes object
// (including destruction) shall not affect any previously initialized mutexes. // (including destruction) shall not affect any previously initialized mutexes.
status = pthread_mutexattr_destroy(&mutexAttr); status = pthread_mutexattr_destroy(&mutexAttr);
if (status != 0) { if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutexattr_destroy");
sif::error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl;
#endif
} }
} }

View File

@ -1,8 +1,11 @@
#include "../../tasks/ExecutableObjectIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <errno.h>
#include "PeriodicPosixTask.h" #include "PeriodicPosixTask.h"
#include "../../objectmanager/ObjectManager.h"
#include "../../tasks/ExecutableObjectIF.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <errno.h>
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_,
size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()): size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):
PosixThread(name_, priority_, stackSize_), objectList(), started(false), PosixThread(name_, priority_, stackSize_), objectList(), started(false),
@ -22,12 +25,15 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) {
} }
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>( ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(
object); object);
if (newObject == nullptr) { if (newObject == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
<< " it implements ExecutableObjectIF!" << std::endl; << " it implements ExecutableObjectIF!" << std::endl;
#else
sif::printError("PeriodicTask::addComponent: Invalid object. Make sure it "
"implements ExecutableObjectIF!\n");
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -44,9 +50,6 @@ ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
ReturnValue_t PeriodicPosixTask::startTask(void) { ReturnValue_t PeriodicPosixTask::startTask(void) {
started = true; started = true;
#if FSFW_CPP_OSTREAM_ENABLED == 1
//sif::info << stackSize << std::endl;
#endif
PosixThread::createTask(&taskEntryPoint,this); PosixThread::createTask(&taskEntryPoint,this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -1,4 +1,5 @@
#include "PosixThread.h" #include "PosixThread.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
@ -49,8 +50,10 @@ void PosixThread::suspend() {
sigwait(&waitSignal, &caughtSig); sigwait(&waitSignal, &caughtSig);
if (caughtSig != SIGUSR1) { if (caughtSig != SIGUSR1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FixedTimeslotTask: Unknown Signal received: " << sif::error << "FixedTimeslotTask::suspend: Unknown Signal received: " << caughtSig <<
caughtSig << std::endl; std::endl;
#else
sif::printError("FixedTimeslotTask::suspend: Unknown Signal received: %d\n", caughtSig);
#endif #endif
} }
} }
@ -133,18 +136,11 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
pthread_attr_t attributes; pthread_attr_t attributes;
int status = pthread_attr_init(&attributes); int status = pthread_attr_init(&attributes);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_init");
sif::error << "Posix Thread attribute init failed with: " <<
strerror(status) << std::endl;
#endif
} }
void* stackPointer; void* stackPointer;
status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize); status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize);
if(status != 0){ if(status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: Stack init failed with: " <<
strerror(status) << std::endl;
#endif
if(errno == ENOMEM) { if(errno == ENOMEM) {
size_t stackMb = stackSize/10e6; size_t stackMb = stackSize/10e6;
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -154,35 +150,35 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
sif::printError("PosixThread::createTask: Insufficient memory for " sif::printError("PosixThread::createTask: Insufficient memory for "
"the requested %lu MB\n", static_cast<unsigned long>(stackMb)); "the requested %lu MB\n", static_cast<unsigned long>(stackMb));
#endif #endif
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "ENOMEM");
} }
else if(errno == EINVAL) { else if(errno == EINVAL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: Wrong alignment argument!" sif::error << "PosixThread::createTask: Wrong alignment argument!"
<< std::endl; << std::endl;
#else #else
sif::printError("PosixThread::createTask: " sif::printError("PosixThread::createTask: Wrong alignment argument!\n");
"Wrong alignment argument!\n");
#endif #endif
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "EINVAL");
} }
return; return;
} }
status = pthread_attr_setstack(&attributes, stackPointer, stackSize); status = pthread_attr_setstack(&attributes, stackPointer, stackSize);
if(status != 0){ if(status != 0) {
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setstack");
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: pthread_attr_setstack " sif::warning << "Make sure the specified stack size is valid and is "
" failed with: " << strerror(status) << std::endl;
sif::error << "Make sure the specified stack size is valid and is "
"larger than the minimum allowed stack size." << std::endl; "larger than the minimum allowed stack size." << std::endl;
#else
sif::printWarning("Make sure the specified stack size is valid and is "
"larger than the minimum allowed stack size.\n");
#endif #endif
} }
status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED); status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setinheritsched");
sif::error << "Posix Thread attribute setinheritsched failed with: " <<
strerror(status) << std::endl;
#endif
} }
#ifndef FSFW_USE_REALTIME_FOR_LINUX #ifndef FSFW_USE_REALTIME_FOR_LINUX
#error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1" #error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1"
@ -191,20 +187,14 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
// FIFO -> This needs root privileges for the process // FIFO -> This needs root privileges for the process
status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO); status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy");
sif::error << "Posix Thread attribute schedule policy failed with: " <<
strerror(status) << std::endl;
#endif
} }
sched_param scheduleParams; sched_param scheduleParams;
scheduleParams.__sched_priority = priority; scheduleParams.__sched_priority = priority;
status = pthread_attr_setschedparam(&attributes, &scheduleParams); status = pthread_attr_setschedparam(&attributes, &scheduleParams);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedparam");
sif::error << "Posix Thread attribute schedule params failed with: " <<
strerror(status) << std::endl;
#endif
} }
#endif #endif
//Set Signal Mask for suspend until startTask is called //Set Signal Mask for suspend until startTask is called
@ -213,23 +203,17 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
sigaddset(&waitSignal, SIGUSR1); sigaddset(&waitSignal, SIGUSR1);
status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL); status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_sigmask");
sif::error << "Posix Thread sigmask failed failed with: " <<
strerror(status) << " errno: " << strerror(errno) << std::endl;
#endif
} }
status = pthread_create(&thread,&attributes,fnc_,arg_); status = pthread_create(&thread,&attributes,fnc_,arg_);
if(status != 0){ if(status != 0){
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_create");
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: Failed with: " <<
strerror(status) << std::endl;
sif::error << "For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " << sif::error << "For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " <<
"\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set " "\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set "
"/etc/security/limit.conf" << std::endl; "/etc/security/limit.conf" << std::endl;
#else #else
sif::printError("PosixThread::createTask: Create failed with: %s\n", strerror(status));
sif::printError("For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " sif::printError("For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call "
"\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set " "\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set "
"/etc/security/limit.conf\n"); "/etc/security/limit.conf\n");
@ -238,31 +222,25 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
status = pthread_setname_np(thread,name); status = pthread_setname_np(thread,name);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_setname_np");
sif::error << "PosixThread::createTask: setname failed with: " <<
strerror(status) << std::endl;
#endif
if(status == ERANGE) { if(status == ERANGE) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PosixThread::createTask: Task name length longer" sif::warning << "PosixThread::createTask: Task name length longer"
" than 16 chars. Truncating.." << std::endl; " than 16 chars. Truncating.." << std::endl;
#else
sif::printWarning("PosixThread::createTask: Task name length longer"
" than 16 chars. Truncating..\n");
#endif #endif
name[15] = '\0'; name[15] = '\0';
status = pthread_setname_np(thread,name); status = pthread_setname_np(thread,name);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_setname_np");
sif::error << "PosixThread::createTask: Setting name"
" did not work.." << std::endl;
#endif
} }
} }
} }
status = pthread_attr_destroy(&attributes); status = pthread_attr_destroy(&attributes);
if(status!=0){ if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_destroy");
sif::error << "Posix Thread attribute destroy failed with: " <<
strerror(status) << std::endl;
#endif
} }
} }

View File

@ -72,6 +72,8 @@ private:
char name[PTHREAD_MAX_NAMELEN]; char name[PTHREAD_MAX_NAMELEN];
int priority; int priority;
size_t stackSize = 0; size_t stackSize = 0;
static constexpr const char* CLASS_NAME = "PosixThread";
}; };
#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */ #endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */

View File

@ -0,0 +1,32 @@
#include "FSFWConfig.h"
#include "unixUtility.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <cstring>
#include <errno.h>
void utility::printUnixErrorGeneric(const char* const className,
const char* const function, const char* const failString,
sif::OutputTypes outputType) {
if(className == nullptr or failString == nullptr or function == nullptr) {
return;
}
#if FSFW_VERBOSE_LEVEL >= 1
if(outputType == sif::OutputTypes::OUT_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << className << "::" << function << ":" << failString << " error: "
<< strerror(errno) << std::endl;
#else
sif::printError("%s::%s: %s error: %s\n", className, function, failString, strerror(errno));
#endif
}
else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << className << "::" << function << ":" << failString << " error: "
<< strerror(errno) << std::endl;
#else
sif::printWarning("%s::%s: %s error: %s\n", className, function, failString, strerror(errno));
#endif
}
#endif
}

13
osal/linux/unixUtility.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef FSFW_OSAL_LINUX_UNIXUTILITY_H_
#define FSFW_OSAL_LINUX_UNIXUTILITY_H_
#include "../../serviceinterface/serviceInterfaceDefintions.h"
namespace utility {
void printUnixErrorGeneric(const char* const className, const char* const function,
const char* const failString, sif::OutputTypes outputType = sif::OutputTypes::OUT_ERROR);
}
#endif /* FSFW_OSAL_LINUX_UNIXUTILITY_H_ */

View File

@ -154,65 +154,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
/ 3600.; / 3600.;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED;
}
MutexGuard helper(timeMutex);
leapSeconds = leapSeconds_;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex==nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
MutexGuard helper(timeMutex);
*leapSeconds_ = leapSeconds;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex==nullptr){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -3,7 +3,7 @@
#include "../../tasks/FixedSequenceSlot.h" #include "../../tasks/FixedSequenceSlot.h"
#include "../../objectmanager/SystemObjectIF.h" #include "../../objectmanager/SystemObjectIF.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManager.h"
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
@ -81,7 +81,7 @@ ReturnValue_t FixedTimeslotTask::startTask() {
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) { uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* object = objectManager->get<ExecutableObjectIF>(componentId); ExecutableObjectIF* object = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
if (object != nullptr) { if (object != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, object, this); pst.addSlot(componentId, slotTimeMs, executionStep, object, this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;

View File

@ -1,8 +1,11 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "MessageQueue.h" #include "MessageQueue.h"
#include "RtemsBasic.h" #include "RtemsBasic.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../objectmanager/ObjectManager.h"
#include <cstring> #include <cstring>
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) :
id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) { id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) {
rtems_name name = ('Q' << 24) + (queueCounter++ << 8); rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
@ -94,7 +97,7 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
//TODO: Check if we're in ISR. //TODO: Check if we're in ISR.
if (result != RTEMS_SUCCESSFUL && !ignoreFault) { if (result != RTEMS_SUCCESSFUL && !ignoreFault) {
if (internalErrorReporter == nullptr) { if (internalErrorReporter == nullptr) {
internalErrorReporter = objectManager->get<InternalErrorReporterIF>( internalErrorReporter = ObjectManager::instance()->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER); objects::INTERNAL_ERROR_REPORTER);
} }
if (internalErrorReporter != nullptr) { if (internalErrorReporter != nullptr) {

View File

@ -1,6 +1,7 @@
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../objectmanager/ObjectManager.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
PeriodicTask::PeriodicTask(const char *name, rtems_task_priority setPriority, PeriodicTask::PeriodicTask(const char *name, rtems_task_priority setPriority,
@ -68,7 +69,7 @@ void PeriodicTask::taskFunctionality() {
} }
ReturnValue_t PeriodicTask::addComponent(object_id_t object) { ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(object); ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
if (newObject == nullptr) { if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -50,8 +50,8 @@ void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t s
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString << sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
" | " << infoString << std::endl; " | " << infoString << std::endl;
#else #else
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString, sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString.c_str(),
errorSrcString, infoString); errorSrcString.c_str(), infoString.c_str());
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */

View File

@ -1,6 +1,7 @@
#include "ParameterHelper.h" #include "ParameterHelper.h"
#include "ParameterMessage.h" #include "ParameterMessage.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../objectmanager/ObjectManager.h"
ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner): ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner):
owner(owner) {} owner(owner) {}
@ -124,7 +125,7 @@ ReturnValue_t ParameterHelper::sendParameter(MessageQueueId_t to, uint32_t id,
ReturnValue_t ParameterHelper::initialize() { ReturnValue_t ParameterHelper::initialize() {
ownerQueueId = owner->getCommandQueue(); ownerQueueId = owner->getCommandQueue();
storage = objectManager->get<StorageManagerIF>(objects::IPC_STORE); storage = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (storage == nullptr) { if (storage == nullptr) {
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }

View File

@ -1,5 +1,6 @@
#include "../parameters/ParameterMessage.h" #include "ParameterMessage.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../objectmanager/ObjectManager.h"
ParameterId_t ParameterMessage::getParameterId(const CommandMessage* message) { ParameterId_t ParameterMessage::getParameterId(const CommandMessage* message) {
return message->getParameter(); return message->getParameter();
@ -51,7 +52,7 @@ void ParameterMessage::clear(CommandMessage* message) {
switch (message->getCommand()) { switch (message->getCommand()) {
case CMD_PARAMETER_LOAD: case CMD_PARAMETER_LOAD:
case REPLY_PARAMETER_DUMP: { case REPLY_PARAMETER_DUMP: {
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>( StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
objects::IPC_STORE); objects::IPC_STORE);
if (ipcStore != NULL) { if (ipcStore != NULL) {
ipcStore->deleteData(getStoreId(message)); ipcStore->deleteData(getStoreId(message));

10
platform.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef FSFW_PLATFORM_H_
#define FSFW_PLATFORM_H_
#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define PLATFORM_UNIX
#elif defined(_WIN32)
#define PLATFORM_WIN
#endif
#endif /* FSFW_PLATFORM_H_ */

View File

@ -2,7 +2,7 @@
#include "../monitoring/LimitViolationReporter.h" #include "../monitoring/LimitViolationReporter.h"
#include "../monitoring/MonitoringMessageContent.h" #include "../monitoring/MonitoringMessageContent.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManager.h"
#include "../serialize/SerialFixedArrayListAdapter.h" #include "../serialize/SerialFixedArrayListAdapter.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
@ -44,7 +44,7 @@ ReturnValue_t Fuse::initialize() {
if (result != RETURN_OK) { if (result != RETURN_OK) {
return result; return result;
} }
powerIF = objectManager->get<PowerSwitchIF>(powerSwitchId); powerIF = ObjectManager::instance()->get<PowerSwitchIF>(powerSwitchId);
if (powerIF == NULL) { if (powerIF == NULL) {
return RETURN_FAILED; return RETURN_FAILED;
} }

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