Merge branch 'development' into gaisser_fixes_subsystem

This commit is contained in:
Steffen Gaisser 2021-04-20 21:07:31 +02:00
commit 9244a96e7b
120 changed files with 3073 additions and 2109 deletions

View File

@ -1,5 +1,13 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
option(FSFW_GENERATE_SECTIONS
"Generate function and data sections. Required to remove unused code" ON
)
if(FSFW_GENERATE_SECTIONS)
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
endif()
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON) option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
# Options to exclude parts of the FSFW from compilation. # Options to exclude parts of the FSFW from compilation.
option(FSFW_USE_RMAP "Compile with RMAP" ON) option(FSFW_USE_RMAP "Compile with RMAP" ON)
@ -26,15 +34,22 @@ if(NOT OS_FSFW)
endif() endif()
set(FSFW_OSAL_DEFINITION FSFW_HOST)
if(${OS_FSFW} STREQUAL host) if(${OS_FSFW} STREQUAL host)
set(OS_FSFW_NAME "Host") set(OS_FSFW_NAME "Host")
elseif(${OS_FSFW} STREQUAL linux) elseif(${OS_FSFW} STREQUAL linux)
set(OS_FSFW_NAME "Linux") set(OS_FSFW_NAME "Linux")
set(FSFW_OSAL_DEFINITION FSFW_LINUX)
elseif(${OS_FSFW} STREQUAL freertos) elseif(${OS_FSFW} STREQUAL freertos)
set(OS_FSFW_NAME "FreeRTOS") set(OS_FSFW_NAME "FreeRTOS")
target_link_libraries(${LIB_FSFW_NAME} ${LIB_OS_NAME}) set(FSFW_OSAL_DEFINITION FSFW_FREERTOS)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${LIB_OS_NAME}
)
elseif(${OS_FSFW} STREQUAL rtems) elseif(${OS_FSFW} STREQUAL rtems)
set(OS_FSFW_NAME "RTEMS") set(OS_FSFW_NAME "RTEMS")
set(FSFW_OSAL_DEFINITION FSFW_RTEMS)
else() else()
message(WARNING message(WARNING
"Invalid operating system for FSFW specified! Setting to host.." "Invalid operating system for FSFW specified! Setting to host.."
@ -43,6 +58,14 @@ else()
set(OS_FSFW "host") set(OS_FSFW "host")
endif() endif()
target_compile_definitions(${LIB_FSFW_NAME} PRIVATE
${FSFW_OSAL_DEFINITION}
)
target_compile_definitions(${LIB_FSFW_NAME} INTERFACE
${FSFW_OSAL_DEFINITION}
)
message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.") message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.")
add_subdirectory(action) add_subdirectory(action)
@ -88,6 +111,7 @@ add_subdirectory(timemanager)
add_subdirectory(tmstorage) add_subdirectory(tmstorage)
add_subdirectory(tmtcpacket) add_subdirectory(tmtcpacket)
add_subdirectory(tmtcservices) add_subdirectory(tmtcservices)
add_subdirectory(unittest)
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. # The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
# If this is not given, we include the default configuration and emit a warning. # If this is not given, we include the default configuration and emit a warning.
@ -107,6 +131,21 @@ else()
) )
endif() endif()
foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATH})
if(IS_ABSOLUTE ${INCLUDE_PATH})
set(CURR_ABS_INC_PATH "${FREERTOS_PATH}")
else()
get_filename_component(CURR_ABS_INC_PATH
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
endif()
if(CMAKE_VERBOSE)
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
endif()
list(APPEND FSFW_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
endforeach()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(NOT DEFINED FSFW_WARNING_FLAGS) if(NOT DEFINED FSFW_WARNING_FLAGS)
set(FSFW_WARNING_FLAGS set(FSFW_WARNING_FLAGS
@ -117,7 +156,20 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-Wno-psabi -Wno-psabi
) )
endif() endif()
if(FSFW_GENERATE_SECTIONS)
target_compile_options(${LIB_FSFW_NAME} PRIVATE
"-ffunction-sections"
"-fdata-sections"
)
endif()
if(FSFW_REMOVE_UNUSED_CODE)
target_link_options(${LIB_FSFW_NAME} PRIVATE
"Wl,--gc-sections"
)
endif()
if(FSFW_WARNING_SHADOW_LOCAL_GCC) if(FSFW_WARNING_SHADOW_LOCAL_GCC)
list(APPEND WARNING_FLAGS "-Wshadow=local") list(APPEND WARNING_FLAGS "-Wshadow=local")
endif() endif()
@ -132,6 +184,7 @@ endif()
target_include_directories(${LIB_FSFW_NAME} INTERFACE target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}
${FSFW_CONFIG_PATH_ABSOLUTE} ${FSFW_CONFIG_PATH_ABSOLUTE}
${FSFW_ADD_INC_PATHS_ABS}
) )
# Includes path required to compile FSFW itself as well # Includes path required to compile FSFW itself as well
@ -140,9 +193,14 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE
target_include_directories(${LIB_FSFW_NAME} PRIVATE target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}
${FSFW_CONFIG_PATH_ABSOLUTE} ${FSFW_CONFIG_PATH_ABSOLUTE}
${FSFW_ADD_INC_PATHS_ABS}
) )
target_compile_options(${LIB_FSFW_NAME} PRIVATE target_compile_options(${LIB_FSFW_NAME} PRIVATE
${FSFW_WARNING_FLAGS} ${FSFW_WARNING_FLAGS}
${COMPILER_FLAGS} ${COMPILER_FLAGS}
) )
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${FSFW_ADDITIONAL_LINK_LIBS}
)

View File

@ -3,9 +3,9 @@
const char* const FSFW_VERSION_NAME = "ASTP"; const char* const FSFW_VERSION_NAME = "ASTP";
#define FSFW_VERSION 0 #define FSFW_VERSION 1
#define FSFW_SUBVERSION 0 #define FSFW_SUBVERSION 0
#define FSFW_REVISION 1 #define FSFW_REVISION 0

View File

@ -147,11 +147,6 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
return result; return result;
} }
if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeAddress);
return result;
}
/* We don't need to report the objectId, as we receive REQUESTED data before the completion /* We don't need to report the objectId, as we receive REQUESTED data before the completion
success message. True aperiodic replies need to be reported with another dedicated message. */ success message. True aperiodic replies need to be reported with another dedicated message. */
ActionMessage::setDataReply(&reply, replyId, storeAddress); ActionMessage::setDataReply(&reply, replyId, storeAddress);

View File

@ -8,7 +8,9 @@
*/ */
template<typename T, size_t MAX_SIZE, typename count_t = uint8_t> template<typename T, size_t MAX_SIZE, typename count_t = uint8_t>
class FixedArrayList: public ArrayList<T, count_t> { class FixedArrayList: public ArrayList<T, count_t> {
static_assert(MAX_SIZE <= (pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE"); #if !defined(_MSC_VER)
static_assert(MAX_SIZE <= (std::pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE");
#endif
private: private:
T data[MAX_SIZE]; T data[MAX_SIZE];
public: public:

View File

@ -1,6 +1,6 @@
#include "SharedRingBuffer.h" #include "SharedRingBuffer.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
#include "../ipc/MutexHelper.h" #include "../ipc/MutexGuard.h"
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size, SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes): bool overwriteOld, size_t maxExcessBytes):
@ -17,6 +17,9 @@ SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
} }
SharedRingBuffer::~SharedRingBuffer() {
MutexFactory::instance()->deleteMutex(mutex);
}
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) { void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
this->fifoDepth = fifoDepth; this->fifoDepth = fifoDepth;

View File

@ -26,6 +26,18 @@ public:
*/ */
SharedRingBuffer(object_id_t objectId, const size_t size, SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes); bool overwriteOld, size_t maxExcessBytes);
/**
* This constructor takes an external buffer with the specified size.
* @param buffer
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
*/
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
bool overwriteOld, size_t maxExcessBytes);
virtual~ SharedRingBuffer();
/** /**
* @brief This function can be used to add an optional FIFO to the class * @brief This function can be used to add an optional FIFO to the class
@ -37,16 +49,7 @@ public:
*/ */
void setToUseReceiveSizeFIFO(size_t fifoDepth); void setToUseReceiveSizeFIFO(size_t fifoDepth);
/**
* This constructor takes an external buffer with the specified size.
* @param buffer
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
*/
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
bool overwriteOld, size_t maxExcessBytes);
/** /**
* Unless a read-only constant value is read, all operations on the * Unless a read-only constant value is read, all operations on the
@ -66,7 +69,7 @@ public:
/** /**
* The mutex handle can be accessed directly, for example to perform * The mutex handle can be accessed directly, for example to perform
* the lock with the #MutexHelper for a RAII compliant lock operation. * the lock with the #MutexGuard for a RAII compliant lock operation.
* @return * @return
*/ */
MutexIF* getMutexHandle() const; MutexIF* getMutexHandle() const;

View File

@ -17,14 +17,6 @@ ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t ExtendedControllerBase::initializeLocalDataPool(
localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
/* Needs to be overriden and implemented by child class. */
return HasReturnvaluesIF::RETURN_OK;
}
object_id_t ExtendedControllerBase::getObjectId() const { object_id_t ExtendedControllerBase::getObjectId() const {
return SystemObject::getObjectId(); return SystemObject::getObjectId();
} }
@ -107,14 +99,6 @@ MessageQueueId_t ExtendedControllerBase::getCommandQueue() const {
return commandQueue->getId(); return commandQueue->getId();
} }
LocalPoolDataSetBase* ExtendedControllerBase::getDataSetHandle(sid_t sid) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ExtendedControllerBase::getDataSetHandle: No child "
<< " implementation provided, returning nullptr!" << std::endl;
#endif
return nullptr;
}
LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() { LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() {
return &poolManager; return &poolManager;
} }

View File

@ -61,11 +61,11 @@ protected:
/* HasLocalDatapoolIF overrides */ /* HasLocalDatapoolIF overrides */
virtual LocalDataPoolManager* getHkManagerHandle() override; virtual LocalDataPoolManager* getHkManagerHandle() override;
virtual object_id_t getObjectId() const override; virtual object_id_t getObjectId() const override;
virtual ReturnValue_t initializeLocalDataPool(
localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
virtual uint32_t getPeriodicOperationFrequency() const override; virtual uint32_t getPeriodicOperationFrequency() const override;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override = 0;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
}; };

View File

@ -7,7 +7,7 @@ HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) :
} }
HkSwitchHelper::~HkSwitchHelper() { HkSwitchHelper::~HkSwitchHelper() {
// TODO Auto-generated destructor stub QueueFactory::instance()->deleteMessageQueue(actionQueue);
} }
ReturnValue_t HkSwitchHelper::initialize() { ReturnValue_t HkSwitchHelper::initialize() {

View File

@ -8,13 +8,16 @@
PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray, PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
const size_t maxFillCount): const size_t maxFillCount):
registeredVariables(registeredVariablesArray), registeredVariables(registeredVariablesArray),
maxFillCount(maxFillCount) { maxFillCount(maxFillCount) {}
}
PoolDataSetBase::~PoolDataSetBase() {} PoolDataSetBase::~PoolDataSetBase() {}
ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF *variable) { ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF *variable) {
if(registeredVariables == nullptr) {
/* Underlying container invalid */
return HasReturnvaluesIF::RETURN_FAILED;
}
if (state != States::STATE_SET_UNINITIALISED) { if (state != States::STATE_SET_UNINITIALISED) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl; sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl;
@ -61,11 +64,11 @@ ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType,
} }
else { else {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::read(): Call made in wrong position. Don't forget to commit" sif::warning << "PoolDataSetBase::read: Call made in wrong position. Don't forget to "
" member datasets!" << std::endl; "commit member datasets!" << std::endl;
#else #else
sif::printError("DataSet::read(): Call made in wrong position. Don't forget to commit" sif::printWarning("PoolDataSetBase::read: Call made in wrong position. Don't forget to "
" member datasets!\n"); "commit member datasets!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
result = SET_WAS_ALREADY_READ; result = SET_WAS_ALREADY_READ;
} }

View File

@ -9,8 +9,8 @@
* and unlock a data pool and read/commit semantics. * and unlock a data pool and read/commit semantics.
*/ */
class PoolDataSetIF: class PoolDataSetIF:
public DataSetIF, virtual public DataSetIF,
public ReadCommitIF { virtual public ReadCommitIF {
public: public:
virtual~ PoolDataSetIF() {}; virtual~ PoolDataSetIF() {};

View File

@ -7,7 +7,7 @@
template <typename T> template <typename T>
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid ): PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid ):
length(initValue.size()), valid(setValid) { length(static_cast<uint8_t>(initValue.size())), valid(setValid) {
this->address = new T[this->length]; this->address = new T[this->length];
if(initValue.size() == 0) { if(initValue.size() == 0) {
std::memset(this->address, 0, this->getByteSize()); std::memset(this->address, 0, this->getByteSize());

View File

@ -1,13 +1,15 @@
#ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ #ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
#define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ #define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
#include "PoolDataSetIF.h" #include "PoolDataSetIF.h"
class SharedDataSetIF: public PoolDataSetIF { class SharedDataSetIF {
public: public:
virtual ~SharedDataSetIF() {}; virtual ~SharedDataSetIF() {};
private: private:
virtual ReturnValue_t lockDataset(dur_millis_t mutexTimeout) = 0; virtual ReturnValue_t lockDataset(MutexIF::TimeoutType timeoutType,
dur_millis_t mutexTimeout) = 0;
virtual ReturnValue_t unlockDataset() = 0; virtual ReturnValue_t unlockDataset() = 0;
}; };

View File

@ -65,34 +65,45 @@ public:
* usually be the period the pool owner performs its periodic operation. * usually be the period the pool owner performs its periodic operation.
* @return * @return
*/ */
virtual uint32_t getPeriodicOperationFrequency() const = 0; virtual dur_millis_t getPeriodicOperationFrequency() const = 0;
/** /**
* @brief This function will be called by the manager if an update * @brief This function will be called by the manager if an update
* notification is received. * notification is received.
* @details HasLocalDataPoolIF * @details HasLocalDataPoolIF
* Can be overriden by the child class to handle changed datasets. * Can be overriden by the child class to handle changed datasets.
* @param sid * @param sid SID of the updated set
* @param storeId If a snapshot was requested, data will be located inside * @param storeId If a snapshot was requested, data will be located inside
* the IPC store with this store ID. * the IPC store with this store ID.
* @param clearMessage If this is set to true, the pool manager will take care of
* clearing the store automatically
*/ */
virtual void handleChangedDataset(sid_t sid, virtual void handleChangedDataset(sid_t sid,
store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { store_address_t storeId = storeId::INVALID_STORE_ADDRESS,
return; bool* clearMessage = nullptr) {
if(clearMessage != nullptr) {
*clearMessage = true;
}
} }
/** /**
* @brief This function will be called by the manager if an update * @brief This function will be called by the manager if an update
* notification is received. * notification is received.
* @details * @details
* Can be overriden by the child class to handle changed pool IDs. * Can be overriden by the child class to handle changed pool variables.
* @param sid * @param gpid GPID of the updated variable.
* @param storeId If a snapshot was requested, data will be located inside * @param storeId If a snapshot was requested, data will be located inside
* the IPC store with this store ID. * the IPC store with this store ID.
* @param clearMessage Relevant for snapshots. If the boolean this points to is set to true,
* the pool manager will take care of clearing the store automatically
* after the callback.
*/ */
virtual void handleChangedPoolVariable(gp_id_t globPoolId, virtual void handleChangedPoolVariable(gp_id_t gpid,
store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { store_address_t storeId = storeId::INVALID_STORE_ADDRESS,
return; bool* clearMessage = nullptr) {
if(clearMessage != nullptr) {
*clearMessage = true;
}
} }
/** /**

View File

@ -10,7 +10,7 @@
#include "../housekeeping/AcceptsHkPacketsIF.h" #include "../housekeeping/AcceptsHkPacketsIF.h"
#include "../timemanager/CCSDSTime.h" #include "../timemanager/CCSDSTime.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
#include "../ipc/MutexHelper.h" #include "../ipc/MutexGuard.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include <array> #include <array>
@ -38,7 +38,11 @@ LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQue
hkQueue = queueToUse; hkQueue = queueToUse;
} }
LocalDataPoolManager::~LocalDataPoolManager() {} LocalDataPoolManager::~LocalDataPoolManager() {
if(mutex != nullptr) {
MutexFactory::instance()->deleteMutex(mutex);
}
}
ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
if(queueToUse == nullptr) { if(queueToUse == nullptr) {
@ -132,13 +136,16 @@ ReturnValue_t LocalDataPoolManager::performHkOperation() {
ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver, ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver,
ReturnValue_t& status) { ReturnValue_t& status) {
if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) {
// Update packets shall only be generated from datasets. /* Update packets shall only be generated from datasets. */
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner,
receiver.dataId.sid); receiver.dataId.sid);
if(dataSet == nullptr) {
return DATASET_NOT_FOUND;
}
if(dataSet->hasChanged()) { if(dataSet->hasChanged()) {
// prepare and send update notification /* Prepare and send update notification */
ReturnValue_t result = generateHousekeepingPacket( ReturnValue_t result = generateHousekeepingPacket(
receiver.dataId.sid, dataSet, true); receiver.dataId.sid, dataSet, true);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
@ -328,7 +335,7 @@ void LocalDataPoolManager::handleChangeResetLogic(
toReset->setChanged(false); toReset->setChanged(false);
} }
/* All recipients have been notified, reset the changed flag */ /* All recipients have been notified, reset the changed flag */
if(changeInfo.currentUpdateCounter <= 1) { else if(changeInfo.currentUpdateCounter <= 1) {
toReset->setChanged(false); toReset->setChanged(false);
changeInfo.currentUpdateCounter = 0; changeInfo.currentUpdateCounter = 0;
} }
@ -372,7 +379,7 @@ ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid,
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting); LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting);
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics);
LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval, LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval,
owner->getPeriodicOperationFrequency(), isDiagnostics); owner->getPeriodicOperationFrequency());
} }
hkReceivers.push_back(hkReceiver); hkReceivers.push_back(hkReceiver);
@ -398,7 +405,6 @@ ReturnValue_t LocalDataPoolManager::subscribeForUpdatePacket(sid_t sid,
hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); hkReceiver.destinationQueue = hkReceiverObject->getHkQueue();
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
//LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid);
if(dataSet != nullptr) { if(dataSet != nullptr) {
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true); LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true);
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics);
@ -516,11 +522,19 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(
} }
case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): { case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): {
return generateSetStructurePacket(sid, true); result = generateSetStructurePacket(sid, true);
if(result == HasReturnvaluesIF::RETURN_OK) {
return result;
}
break;
} }
case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): { case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): {
return generateSetStructurePacket(sid, false); result = generateSetStructurePacket(sid, false);
if(result == HasReturnvaluesIF::RETURN_OK) {
return result;
}
break;
} }
case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL): case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL):
case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): { case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): {
@ -540,14 +554,15 @@ 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);
//LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid);
if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT
and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
return WRONG_HK_PACKET_TYPE; result = WRONG_HK_PACKET_TYPE;
break;
} }
else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT
and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
return WRONG_HK_PACKET_TYPE; result = WRONG_HK_PACKET_TYPE;
break;
} }
return generateHousekeepingPacket(HousekeepingMessage::getSid(message), return generateHousekeepingPacket(HousekeepingMessage::getSid(message),
dataSet, true); dataSet, true);
@ -566,14 +581,22 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(
case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): {
store_address_t storeId; store_address_t storeId;
HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId); HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId);
owner->handleChangedDataset(sid, storeId); bool clearMessage = true;
owner->handleChangedDataset(sid, storeId, &clearMessage);
if(clearMessage) {
message->clear();
}
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): {
store_address_t storeId; store_address_t storeId;
gp_id_t globPoolId = HousekeepingMessage::getUpdateSnapshotVariableCommand(message, gp_id_t globPoolId = HousekeepingMessage::getUpdateSnapshotVariableCommand(message,
&storeId); &storeId);
owner->handleChangedPoolVariable(globPoolId, storeId); bool clearMessage = true;
owner->handleChangedPoolVariable(globPoolId, storeId, &clearMessage);
if(clearMessage) {
message->clear();
}
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -616,7 +639,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
LocalPoolDataSetBase* dataSet, bool forDownlink, LocalPoolDataSetBase* dataSet, bool forDownlink,
MessageQueueId_t destination) { MessageQueueId_t destination) {
if(dataSet == nullptr) { if(dataSet == nullptr) {
// Configuration error. /* Configuration error. */
printWarningOrError(sif::OutputTypes::OUT_WARNING, printWarningOrError(sif::OutputTypes::OUT_WARNING,
"generateHousekeepingPacket", "generateHousekeepingPacket",
DATASET_NOT_FOUND); DATASET_NOT_FOUND);
@ -632,7 +655,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
return result; return result;
} }
// and now we set a HK message and send it the HK packet destination. /* Now we set a HK message and send it the HK packet destination. */
CommandMessage hkMessage; CommandMessage hkMessage;
if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId);
@ -642,7 +665,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
} }
if(hkQueue == nullptr) { if(hkQueue == nullptr) {
// error, no queue available to send packet with. /* Error, no queue available to send packet with. */
printWarningOrError(sif::OutputTypes::OUT_WARNING, printWarningOrError(sif::OutputTypes::OUT_WARNING,
"generateHousekeepingPacket", "generateHousekeepingPacket",
QUEUE_OR_DESTINATION_INVALID); QUEUE_OR_DESTINATION_INVALID);
@ -650,7 +673,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
} }
if(destination == MessageQueueIF::NO_QUEUE) { if(destination == MessageQueueIF::NO_QUEUE) {
if(hkDestinationId == MessageQueueIF::NO_QUEUE) { if(hkDestinationId == MessageQueueIF::NO_QUEUE) {
// error, all destinations invalid /* Error, all destinations invalid */
printWarningOrError(sif::OutputTypes::OUT_WARNING, printWarningOrError(sif::OutputTypes::OUT_WARNING,
"generateHousekeepingPacket", "generateHousekeepingPacket",
QUEUE_OR_DESTINATION_INVALID); QUEUE_OR_DESTINATION_INVALID);
@ -729,6 +752,12 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid,
bool enable, bool isDiagnostics) { bool enable, bool isDiagnostics) {
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "togglePeriodicGeneration",
DATASET_NOT_FOUND);
return DATASET_NOT_FOUND;
}
if((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or if((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or
(not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) { (not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) {
return WRONG_HK_PACKET_TYPE; return WRONG_HK_PACKET_TYPE;
@ -746,6 +775,12 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid,
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
float newCollectionInterval, bool isDiagnostics) { float newCollectionInterval, bool isDiagnostics) {
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval",
DATASET_NOT_FOUND);
return DATASET_NOT_FOUND;
}
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
if((targetIsDiagnostics and not isDiagnostics) or if((targetIsDiagnostics and not isDiagnostics) or
(not targetIsDiagnostics and isDiagnostics)) { (not targetIsDiagnostics and isDiagnostics)) {
@ -756,7 +791,7 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);
if(periodicHelper == nullptr) { if(periodicHelper == nullptr) {
// config error /* Configuration error, set might not have a corresponding pool manager */
return PERIODIC_HELPER_INVALID; return PERIODIC_HELPER_INVALID;
} }
@ -766,13 +801,11 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid,
bool isDiagnostics) { bool isDiagnostics) {
// Get and check dataset first. /* Get and check dataset first. */
//LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid);
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet == nullptr) { if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, printWarningOrError(sif::OutputTypes::OUT_WARNING,
"performPeriodicHkGeneration", "performPeriodicHkGeneration", DATASET_NOT_FOUND);
DATASET_NOT_FOUND);
return DATASET_NOT_FOUND; return DATASET_NOT_FOUND;
} }
@ -831,6 +864,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid,
void LocalDataPoolManager::clearReceiversList() { void LocalDataPoolManager::clearReceiversList() {
/* Clear the vector completely and releases allocated memory. */ /* Clear the vector completely and releases allocated memory. */
HkReceivers().swap(hkReceivers); HkReceivers().swap(hkReceivers);
/* Also clear the reset helper if it exists */
if(hkUpdateResetList != nullptr) {
HkUpdateResetList().swap(*hkUpdateResetList);
}
} }
MutexIF* LocalDataPoolManager::getLocalPoolMutex() { MutexIF* LocalDataPoolManager::getLocalPoolMutex() {
@ -843,6 +880,7 @@ object_id_t LocalDataPoolManager::getCreatorObjectId() const {
void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType, void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
const char* functionName, ReturnValue_t error, const char* errorPrint) { const char* functionName, ReturnValue_t error, const char* errorPrint) {
#if FSFW_VERBOSE_LEVEL >= 1
if(errorPrint == nullptr) { if(errorPrint == nullptr) {
if(error == DATASET_NOT_FOUND) { if(error == DATASET_NOT_FOUND) {
errorPrint = "Dataset not found"; errorPrint = "Dataset not found";
@ -871,33 +909,32 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
errorPrint = "Unknown error"; errorPrint = "Unknown error";
} }
} }
object_id_t objectId = 0xffffffff;
if(owner != nullptr) {
objectId = owner->getObjectId();
}
if(outputType == sif::OutputTypes::OUT_WARNING) { if(outputType == sif::OutputTypes::OUT_WARNING) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalDataPoolManager::" << functionName sif::warning << "LocalDataPoolManager::" << functionName << ": Object ID 0x" <<
<< ": Object ID 0x" << std::setw(8) << std::setfill('0') std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint <<
<< std::hex << owner->getObjectId() << " | " << errorPrint std::dec << std::setfill(' ') << std::endl;
<< std::dec << std::setfill(' ') << std::endl;
#else #else
sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
functionName, owner->getObjectId(), errorPrint); functionName, objectId, errorPrint);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
} }
else if(outputType == sif::OutputTypes::OUT_ERROR) { else if(outputType == sif::OutputTypes::OUT_ERROR) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalDataPoolManager::" << functionName sif::error << "LocalDataPoolManager::" << functionName << ": Object ID 0x" <<
<< ": Object ID 0x" << std::setw(8) << std::setfill('0') std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint <<
<< std::hex << owner->getObjectId() << " | " << errorPrint std::dec << std::setfill(' ') << std::endl;
<< std::dec << std::setfill(' ') << std::endl;
#else #else
sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
functionName, owner->getObjectId(), errorPrint); functionName, objectId, errorPrint);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
} }
#endif /* #if FSFW_VERBOSE_LEVEL >= 1 */
} }
LocalDataPoolManager* LocalDataPoolManager::getPoolManagerHandle() { LocalDataPoolManager* LocalDataPoolManager::getPoolManagerHandle() {

View File

@ -14,7 +14,7 @@
#include "../ipc/MutexIF.h" #include "../ipc/MutexIF.h"
#include "../ipc/CommandMessage.h" #include "../ipc/CommandMessage.h"
#include "../ipc/MessageQueueIF.h" #include "../ipc/MessageQueueIF.h"
#include "../ipc/MutexHelper.h" #include "../ipc/MutexGuard.h"
#include <map> #include <map>
#include <vector> #include <vector>
@ -391,6 +391,10 @@ protected:
template<class T> inline template<class T> inline
ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, PoolEntry<T> **poolEntry) { ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, PoolEntry<T> **poolEntry) {
if(poolEntry == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
auto poolIter = localPoolMap.find(localPoolId); auto poolIter = localPoolMap.find(localPoolId);
if (poolIter == localPoolMap.end()) { if (poolIter == localPoolMap.end()) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry", printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry",

View File

@ -44,7 +44,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->get<HasLocalDataPoolIF>(
sid.objectId); sid.objectId);
if(hkOwner != nullptr) { if(hkOwner != nullptr) {
@ -58,8 +58,7 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registere
this->sid = sid; this->sid = sid;
} }
LocalPoolDataSetBase::LocalPoolDataSetBase( LocalPoolDataSetBase::LocalPoolDataSetBase(PoolVariableIF **registeredVariablesArray,
PoolVariableIF **registeredVariablesArray,
const size_t maxNumberOfVariables, bool protectEveryReadCommitCall): const size_t maxNumberOfVariables, bool protectEveryReadCommitCall):
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
this->setReadCommitProtectionBehaviour(protectEveryReadCommitCall); this->setReadCommitProtectionBehaviour(protectEveryReadCommitCall);
@ -95,14 +94,23 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer
size_t *size, size_t maxSize, size_t *size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const { SerializeIF::Endianness streamEndianness) const {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount)/8.0); const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount)/8.0);
uint8_t validityMask[validityMaskSize] = {}; uint8_t* validityPtr = nullptr;
#ifdef _MSC_VER
/* Use a std::vector here because MSVC will (rightly) not create a fixed size array
with a non constant size specifier */
std::vector<uint8_t> validityMask(validityMaskSize);
validityPtr = validityMask.data();
#else
uint8_t validityMask[validityMaskSize] = {0};
validityPtr = validityMask;
#endif
uint8_t validBufferIndex = 0; uint8_t validBufferIndex = 0;
uint8_t validBufferIndexBit = 0; uint8_t validBufferIndexBit = 0;
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
if(registeredVariables[count]->isValid()) { if(registeredVariables[count]->isValid()) {
/* Set bit at correct position */ /* Set bit at correct position */
bitutil::bitSet(validityMask + validBufferIndex, validBufferIndexBit); bitutil::bitSet(validityPtr + validBufferIndex, validBufferIndexBit);
} }
if(validBufferIndexBit == 7) { if(validBufferIndexBit == 7) {
validBufferIndex ++; validBufferIndex ++;
@ -123,7 +131,7 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer
return SerializeIF::BUFFER_TOO_SHORT; return SerializeIF::BUFFER_TOO_SHORT;
} }
// copy validity buffer to end // copy validity buffer to end
std::memcpy(*buffer, validityMask, validityMaskSize); std::memcpy(*buffer, validityPtr, validityMaskSize);
*size += validityMaskSize; *size += validityMaskSize;
return result; return result;
} }
@ -262,11 +270,9 @@ bool LocalPoolDataSetBase::getReportingEnabled() const {
return reportingEnabled; return reportingEnabled;
} }
void LocalPoolDataSetBase::initializePeriodicHelper( void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
float collectionInterval, dur_millis_t minimumPeriodicInterval, dur_millis_t minimumPeriodicInterval, uint8_t nonDiagIntervalFactor) {
bool isDiagnostics, uint8_t nonDiagIntervalFactor) { periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor);
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval,
isDiagnostics, nonDiagIntervalFactor);
} }
void LocalPoolDataSetBase::setChanged(bool changed) { void LocalPoolDataSetBase::setChanged(bool changed) {
@ -306,3 +312,12 @@ void LocalPoolDataSetBase::setAllVariablesReadOnly() {
registeredVariables[idx]->setReadWriteMode(pool_rwm_t::VAR_READ); registeredVariables[idx]->setReadWriteMode(pool_rwm_t::VAR_READ);
} }
} }
float LocalPoolDataSetBase::getCollectionInterval() const {
if(periodicHelper != nullptr) {
return periodicHelper->getCollectionIntervalInSeconds();
}
else {
return 0.0;
}
}

View File

@ -166,6 +166,16 @@ public:
object_id_t getCreatorObjectId(); object_id_t getCreatorObjectId();
bool getReportingEnabled() const;
/**
* Returns the current periodic HK generation interval this set
* belongs to a HK manager and the interval is not 0. Otherwise,
* returns 0.0
* @return
*/
float getCollectionInterval() const;
protected: protected:
sid_t sid; sid_t sid;
//! This mutex is used if the data is created by one object only. //! This mutex is used if the data is created by one object only.
@ -180,11 +190,9 @@ protected:
*/ */
bool reportingEnabled = false; bool reportingEnabled = false;
void setReportingEnabled(bool enabled); void setReportingEnabled(bool enabled);
bool getReportingEnabled() const;
void initializePeriodicHelper(float collectionInterval, void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
dur_millis_t minimumPeriodicInterval, uint8_t nonDiagIntervalFactor = 5);
bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5);
/** /**
* If the valid state of a dataset is always relevant to the whole * If the valid state of a dataset is always relevant to the whole

View File

@ -25,7 +25,7 @@ inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId,
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::read( inline ReturnValue_t LocalPoolVector<T, vectorSize>::read(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
return readWithoutLock(); return readWithoutLock();
} }
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
@ -64,7 +64,7 @@ inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(bool valid,
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit( inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
return commitWithoutLock(); return commitWithoutLock();
} }

View File

@ -1,16 +1,37 @@
#include "SharedLocalDataSet.h" #include "SharedLocalDataSet.h"
SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId, sid_t sid, SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId, sid_t sid,
const size_t maxSize): SystemObject(objectId), const size_t maxSize): SystemObject(objectId),
LocalPoolDataSetBase(sid, nullptr, maxSize) { LocalPoolDataSetBase(sid, nullptr, maxSize), poolVarVector(maxSize) {
this->setContainer(poolVarVector.data()); this->setContainer(poolVarVector.data());
datasetLock = MutexFactory::instance()->createMutex(); datasetLock = MutexFactory::instance()->createMutex();
} }
ReturnValue_t SharedLocalDataSet::lockDataset(dur_millis_t mutexTimeout) { SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId,
return datasetLock->lockMutex(MutexIF::TimeoutType::WAITING, mutexTimeout); HasLocalDataPoolIF *owner, uint32_t setId,
const size_t maxSize): SystemObject(objectId),
LocalPoolDataSetBase(owner, setId, nullptr, maxSize), poolVarVector(maxSize) {
this->setContainer(poolVarVector.data());
datasetLock = MutexFactory::instance()->createMutex();
}
ReturnValue_t SharedLocalDataSet::lockDataset(MutexIF::TimeoutType timeoutType,
dur_millis_t mutexTimeout) {
if(datasetLock != nullptr) {
return datasetLock->lockMutex(timeoutType, mutexTimeout);
}
return HasReturnvaluesIF::RETURN_FAILED;
}
SharedLocalDataSet::~SharedLocalDataSet() {
MutexFactory::instance()->deleteMutex(datasetLock);
} }
ReturnValue_t SharedLocalDataSet::unlockDataset() { ReturnValue_t SharedLocalDataSet::unlockDataset() {
return datasetLock->unlockMutex(); if(datasetLock != nullptr) {
return datasetLock->unlockMutex();
}
return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -11,16 +11,22 @@
* multiple threads. It provides a lock in addition to all other functionalities provided * multiple threads. It provides a lock in addition to all other functionalities provided
* by the LocalPoolDataSetBase class. * by the LocalPoolDataSetBase class.
* *
* TODO: override and protect read, commit and some other calls used by pool manager. * The user is completely responsible for lockingand unlocking the dataset when using the
* shared dataset.
*/ */
class SharedLocalDataSet: class SharedLocalDataSet:
public SystemObject, public SystemObject,
public LocalPoolDataSetBase, public LocalPoolDataSetBase,
public SharedDataSetIF { public SharedDataSetIF {
public: public:
SharedLocalDataSet(object_id_t objectId, sid_t sid, SharedLocalDataSet(object_id_t objectId, HasLocalDataPoolIF* owner, uint32_t setId,
const size_t maxSize); const size_t maxSize);
ReturnValue_t lockDataset(dur_millis_t mutexTimeout) override; SharedLocalDataSet(object_id_t objectId, sid_t sid, const size_t maxSize);
virtual~ SharedLocalDataSet();
ReturnValue_t lockDataset(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
dur_millis_t mutexTimeout = 20) override;
ReturnValue_t unlockDataset() override; ReturnValue_t unlockDataset() override;
private: private:

View File

@ -0,0 +1,12 @@
#ifndef FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
#define FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
/* Collected related headers */
#include "LocalPoolVariable.h"
#include "LocalPoolVector.h"
#include "StaticLocalDataSet.h"
#include "LocalDataSet.h"
#include "SharedLocalDataSet.h"
#endif /* FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ */

View File

@ -14,9 +14,8 @@ private:
} }
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval, static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
uint32_t minimumPeriodicIntervalMs, uint32_t minimumPeriodicIntervalMs, uint8_t nonDiagIntervalFactor = 5) {
bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5) { set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs,
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs, isDiagnostics,
nonDiagIntervalFactor); nonDiagIntervalFactor);
} }

View File

@ -96,11 +96,11 @@ union gp_id_t {
return raw == INVALID_GPID; return raw == INVALID_GPID;
} }
bool operator==(const sid_t& other) const { bool operator==(const gp_id_t& other) const {
return raw == other.raw; return raw == other.raw;
} }
bool operator!=(const sid_t& other) const { bool operator!=(const gp_id_t& other) const {
return not (raw == other.raw); return not (raw == other.raw);
} }
}; };

View File

@ -40,6 +40,13 @@
//! Specify whether a special mode store is used for Subsystem components. //! Specify whether a special mode store is used for Subsystem components.
#define FSFW_USE_MODESTORE 0 #define FSFW_USE_MODESTORE 0
//! Defines if the real time scheduler for linux should be used.
//! If set to 0, this will also disable priority settings for linux
//! as most systems will not allow to set nice values without privileges
//! For embedded linux system set this to 1.
//! If set to 1 the binary needs "cap_sys_nice=eip" privileges to run
#define FSFW_USE_REALTIME_FOR_LINUX 1
namespace fsfwconfig { namespace fsfwconfig {
//! Default timestamp size. The default timestamp will be an eight byte CDC //! Default timestamp size. The default timestamp will be an eight byte CDC
//! short timestamp. //! short timestamp.
@ -52,11 +59,12 @@ static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
//! Defines the FIFO depth of each commanding service base which //! Defines the FIFO depth of each commanding service base which
//! also determines how many commands a CSB service can handle in one cycle //! also determines how many commands a CSB service can handle in one cycle
//! simulataneously. This will increase the required RAM for //! simultaneously. This will increase the required RAM for
//! each CSB service ! //! each CSB service !
static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; 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;
} }
#endif /* CONFIG_FSFWCONFIG_H_ */ #endif /* CONFIG_FSFWCONFIG_H_ */

View File

@ -1483,7 +1483,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) { if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) {
errorPrint = "Initialization error"; errorPrint = "Initialization error";
} }
if(errorCode == HasReturnvaluesIF::RETURN_FAILED) { else if(errorCode == HasReturnvaluesIF::RETURN_FAILED) {
if(errorType == sif::OutputTypes::OUT_WARNING) { if(errorType == sif::OutputTypes::OUT_WARNING) {
errorPrint = "Generic Warning"; errorPrint = "Generic Warning";
} }
@ -1495,6 +1495,9 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
errorPrint = "Unknown error"; errorPrint = "Unknown error";
} }
} }
if(functionName == nullptr) {
functionName = "unknown function";
}
if(errorType == sif::OutputTypes::OUT_WARNING) { if(errorType == sif::OutputTypes::OUT_WARNING) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -1504,7 +1507,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
<< std::setfill(' ') << std::endl; << std::setfill(' ') << std::endl;
#else #else
sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
this->getObjectId(), errorPrint); functionName, this->getObjectId(), errorPrint);
#endif #endif
} }
else if(errorType == sif::OutputTypes::OUT_ERROR) { else if(errorType == sif::OutputTypes::OUT_ERROR) {
@ -1515,7 +1518,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
<< std::setfill(' ') << std::endl; << std::setfill(' ') << std::endl;
#else #else
sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
this->getObjectId(), errorPrint); functionName, this->getObjectId(), errorPrint);
#endif #endif
} }

View File

@ -119,7 +119,7 @@ public:
DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
lp_id_t thermalRequestPoolId = lp_id_t thermalRequestPoolId =
DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID, DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID,
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID); uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID);
/** /**
* @brief Helper function to ease device handler development. * @brief Helper function to ease device handler development.
* This will instruct the transition to MODE_ON immediately * This will instruct the transition to MODE_ON immediately

View File

@ -16,9 +16,9 @@ ReturnValue_t HealthDevice::performOperation(uint8_t opCode) {
CommandMessage command; CommandMessage command;
ReturnValue_t result = commandQueue->receiveMessage(&command); ReturnValue_t result = commandQueue->receiveMessage(&command);
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
healthHelper.handleHealthCommand(&command); result = healthHelper.handleHealthCommand(&command);
} }
return HasReturnvaluesIF::RETURN_OK; return result;
} }
ReturnValue_t HealthDevice::initialize() { ReturnValue_t HealthDevice::initialize() {

View File

@ -109,6 +109,6 @@ bool EventMessage::isClearedEventMessage() {
return getEvent() == INVALID_EVENT; return getEvent() == INVALID_EVENT;
} }
size_t EventMessage::getMinimumMessageSize() { size_t EventMessage::getMinimumMessageSize() const {
return EVENT_MESSAGE_SIZE; return EVENT_MESSAGE_SIZE;
} }

View File

@ -45,7 +45,7 @@ public:
protected: protected:
static const Event INVALID_EVENT = 0; static const Event INVALID_EVENT = 0;
virtual size_t getMinimumMessageSize(); virtual size_t getMinimumMessageSize() const override;
}; };

View File

@ -51,7 +51,7 @@ void arrayprinter::printHex(const uint8_t *data, size_t size,
#else #else
// General format: 0x01, 0x02, 0x03 so it is number of chars times 6 // General format: 0x01, 0x02, 0x03 so it is number of chars times 6
// plus line break plus small safety margin. // plus line break plus small safety margin.
char printBuffer[(size + 1) * 7 + 1]; char printBuffer[(size + 1) * 7 + 1] = {};
size_t currentPos = 0; size_t currentPos = 0;
for(size_t i = 0; i < size; i++) { for(size_t i = 0; i < size; i++) {
// To avoid buffer overflows. // To avoid buffer overflows.
@ -67,7 +67,9 @@ void arrayprinter::printHex(const uint8_t *data, size_t size,
} }
} }
} }
#if FSFW_DISABLE_PRINTOUT == 0
printf("[%s]\n", printBuffer); printf("[%s]\n", printBuffer);
#endif /* FSFW_DISABLE_PRINTOUT == 0 */
#endif #endif
} }
@ -92,7 +94,7 @@ void arrayprinter::printDec(const uint8_t *data, size_t size,
#else #else
// General format: 32, 243, -12 so it is number of chars times 5 // General format: 32, 243, -12 so it is number of chars times 5
// plus line break plus small safety margin. // plus line break plus small safety margin.
char printBuffer[(size + 1) * 5 + 1]; char printBuffer[(size + 1) * 5 + 1] = {};
size_t currentPos = 0; size_t currentPos = 0;
for(size_t i = 0; i < size; i++) { for(size_t i = 0; i < size; i++) {
// To avoid buffer overflows. // To avoid buffer overflows.
@ -108,7 +110,9 @@ void arrayprinter::printDec(const uint8_t *data, size_t size,
} }
} }
} }
#if FSFW_DISABLE_PRINTOUT == 0
printf("[%s]\n", printBuffer); printf("[%s]\n", printBuffer);
#endif /* FSFW_DISABLE_PRINTOUT == 0 */
#endif #endif
} }

View File

@ -1,5 +1,5 @@
#include "HealthTable.h" #include "HealthTable.h"
#include "../ipc/MutexHelper.h" #include "../ipc/MutexGuard.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
#include "../serialize/SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
@ -31,7 +31,7 @@ ReturnValue_t HealthTable::registerObject(object_id_t object,
void HealthTable::setHealth(object_id_t object, void HealthTable::setHealth(object_id_t object,
HasHealthIF::HealthState newState) { HasHealthIF::HealthState newState) {
MutexHelper(mutex, timeoutType, mutexTimeoutMs); MutexGuard(mutex, timeoutType, mutexTimeoutMs);
HealthMap::iterator iter = healthMap.find(object); HealthMap::iterator iter = healthMap.find(object);
if (iter != healthMap.end()) { if (iter != healthMap.end()) {
iter->second = newState; iter->second = newState;
@ -40,7 +40,7 @@ void HealthTable::setHealth(object_id_t object,
HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) { HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) {
HasHealthIF::HealthState state = HasHealthIF::HEALTHY; HasHealthIF::HealthState state = HasHealthIF::HEALTHY;
MutexHelper(mutex, timeoutType, mutexTimeoutMs); MutexGuard(mutex, timeoutType, mutexTimeoutMs);
HealthMap::iterator iter = healthMap.find(object); HealthMap::iterator iter = healthMap.find(object);
if (iter != healthMap.end()) { if (iter != healthMap.end()) {
state = iter->second; state = iter->second;
@ -49,7 +49,7 @@ HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) {
} }
bool HealthTable::hasHealth(object_id_t object) { bool HealthTable::hasHealth(object_id_t object) {
MutexHelper(mutex, timeoutType, mutexTimeoutMs); MutexGuard(mutex, timeoutType, mutexTimeoutMs);
HealthMap::iterator iter = healthMap.find(object); HealthMap::iterator iter = healthMap.find(object);
if (iter != healthMap.end()) { if (iter != healthMap.end()) {
return true; return true;
@ -58,35 +58,51 @@ bool HealthTable::hasHealth(object_id_t object) {
} }
size_t HealthTable::getPrintSize() { size_t HealthTable::getPrintSize() {
MutexHelper(mutex, timeoutType, mutexTimeoutMs); MutexGuard(mutex, timeoutType, mutexTimeoutMs);
uint32_t size = healthMap.size() * sizeof(object_id_t) + uint32_t size = healthMap.size() * sizeof(object_id_t) +
sizeof(HasHealthIF::HealthState) + sizeof(uint16_t); sizeof(HasHealthIF::HealthState) + sizeof(uint16_t);
return size; return size;
} }
void HealthTable::printAll(uint8_t* pointer, size_t maxSize) { void HealthTable::printAll(uint8_t* pointer, size_t maxSize) {
MutexHelper(mutex, timeoutType, mutexTimeoutMs); MutexGuard(mutex, timeoutType, mutexTimeoutMs);
size_t size = 0; size_t size = 0;
uint16_t count = healthMap.size(); uint16_t count = healthMap.size();
SerializeAdapter::serialize(&count, ReturnValue_t result = SerializeAdapter::serialize(&count,
&pointer, &size, maxSize, SerializeIF::Endianness::BIG); &pointer, &size, maxSize, SerializeIF::Endianness::BIG);
if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "HealthTable::printAll: Serialization of health table failed" << std::endl;
#else
sif::printWarning("HealthTable::printAll: Serialization of health table failed\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return;
}
for (const auto& health: healthMap) { for (const auto& health: healthMap) {
SerializeAdapter::serialize(&health.first, result = SerializeAdapter::serialize(&health.first,
&pointer, &size, maxSize, SerializeIF::Endianness::BIG); &pointer, &size, maxSize, SerializeIF::Endianness::BIG);
if(result != HasReturnvaluesIF::RETURN_OK) {
return;
}
uint8_t healthValue = health.second; uint8_t healthValue = health.second;
SerializeAdapter::serialize(&healthValue, &pointer, &size, result = SerializeAdapter::serialize(&healthValue, &pointer, &size,
maxSize, SerializeIF::Endianness::BIG); maxSize, SerializeIF::Endianness::BIG);
if(result != HasReturnvaluesIF::RETURN_OK) {
return;
}
} }
} }
ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) { ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
MutexHelper(mutex, timeoutType, mutexTimeoutMs); MutexGuard(mutex, timeoutType, mutexTimeoutMs);
if (reset) { if (reset) {
mapIterator = healthMap.begin(); mapIterator = healthMap.begin();
} }
if (mapIterator == healthMap.end()) { if (mapIterator == healthMap.end()) {
result = HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
*value = *mapIterator; *value = *mapIterator;
mapIterator++; mapIterator++;

View File

@ -84,15 +84,21 @@ void HousekeepingMessage::setCollectionIntervalModificationCommand(
else { else {
command->setCommand(MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL); command->setCommand(MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL);
} }
command->setParameter3(collectionInterval);
/* Raw storage of the float in the message. Do not use setParameter3, does
implicit conversion to integer type! */
std::memcpy(command->getData() + 2 * sizeof(uint32_t), &collectionInterval,
sizeof(collectionInterval));
setSid(command, sid); setSid(command, sid);
} }
sid_t HousekeepingMessage::getCollectionIntervalModificationCommand( sid_t HousekeepingMessage::getCollectionIntervalModificationCommand(
const CommandMessage* command, float* newCollectionInterval) { const CommandMessage* command, float* newCollectionInterval) {
if(newCollectionInterval != nullptr) { if(newCollectionInterval != nullptr) {
*newCollectionInterval = command->getParameter3(); std::memcpy(newCollectionInterval, command->getData() + 2 * sizeof(uint32_t),
sizeof(*newCollectionInterval));
} }
return getSid(command); return getSid(command);
@ -151,7 +157,8 @@ void HousekeepingMessage::clear(CommandMessage* message) {
case(DIAGNOSTICS_REPORT): case(DIAGNOSTICS_REPORT):
case(HK_DEFINITIONS_REPORT): case(HK_DEFINITIONS_REPORT):
case(DIAGNOSTICS_DEFINITION_REPORT): case(DIAGNOSTICS_DEFINITION_REPORT):
case(UPDATE_SNAPSHOT_SET): { case(UPDATE_SNAPSHOT_SET):
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->get<StorageManagerIF>(

View File

@ -11,7 +11,8 @@
* @brief This helper class will be used to serialize and deserialize update housekeeping packets * @brief This helper class will be used to serialize and deserialize update housekeeping packets
* into the store. * into the store.
*/ */
class HousekeepingSnapshot: public SerializeIF { class HousekeepingSnapshot:
public SerializeIF {
public: public:
/** /**
@ -36,6 +37,17 @@ public:
timeStamp(timeStamp), timeStampSize(timeStampSize), timeStamp(timeStamp), timeStampSize(timeStampSize),
updateData(dataSetPtr) {}; updateData(dataSetPtr) {};
/**
* Update packet constructor for pool variables.
* @param timeStamp
* @param timeStampSize
* @param dataSetPtr
*/
HousekeepingSnapshot(CCSDSTime::CDS_short* cdsShort, LocalPoolObjectBase* dataSetPtr):
timeStamp(reinterpret_cast<uint8_t*>(cdsShort)),
timeStampSize(sizeof(CCSDSTime::CDS_short)), updateData(dataSetPtr) {};
/** /**
* Update packet constructor for pool variables. * Update packet constructor for pool variables.
* @param timeStamp * @param timeStamp
@ -47,8 +59,8 @@ public:
timeStamp(timeStamp), timeStampSize(timeStampSize), timeStamp(timeStamp), timeStampSize(timeStampSize),
updateData(dataSetPtr) {}; updateData(dataSetPtr) {};
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
size_t maxSize, Endianness streamEndianness) const { Endianness streamEndianness) const {
if(timeStamp != nullptr) { if(timeStamp != nullptr) {
/* Endianness will always be MACHINE, so we can simply use memcpy /* Endianness will always be MACHINE, so we can simply use memcpy
here. */ here. */

View File

@ -4,46 +4,87 @@
#include <cmath> #include <cmath>
PeriodicHousekeepingHelper::PeriodicHousekeepingHelper( PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(
LocalPoolDataSetBase* owner): owner(owner) {} LocalPoolDataSetBase* owner): owner(owner) {}
void PeriodicHousekeepingHelper::initialize(float collectionInterval, void PeriodicHousekeepingHelper::initialize(float collectionInterval,
dur_millis_t minimumPeriodicInterval, bool isDiagnostics, dur_millis_t minimumPeriodicInterval, uint8_t nonDiagIntervalFactor) {
uint8_t nonDiagIntervalFactor) { this->minimumPeriodicInterval = minimumPeriodicInterval;
this->minimumPeriodicInterval = minimumPeriodicInterval; this->nonDiagIntervalFactor = nonDiagIntervalFactor;
if(not isDiagnostics) { collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval);
this->minimumPeriodicInterval = this->minimumPeriodicInterval * /* This will cause a checkOpNecessary call to be true immediately. I think it's okay
nonDiagIntervalFactor; if a HK packet is generated immediately instead of waiting one generation cycle. */
} internalTickCounter = collectionIntervalTicks;
collectionIntervalTicks = intervalSecondsToInterval(collectionInterval);
} }
float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() { float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() const {
return intervalToIntervalSeconds(collectionIntervalTicks); return intervalTicksToSeconds(collectionIntervalTicks);
} }
bool PeriodicHousekeepingHelper::checkOpNecessary() { bool PeriodicHousekeepingHelper::checkOpNecessary() {
if(internalTickCounter >= collectionIntervalTicks) { if(internalTickCounter >= collectionIntervalTicks) {
internalTickCounter = 1; internalTickCounter = 1;
return true; return true;
} }
internalTickCounter++; internalTickCounter++;
return false; return false;
} }
uint32_t PeriodicHousekeepingHelper::intervalSecondsToInterval( uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks(
float collectionIntervalSeconds) { float collectionIntervalSeconds) {
return std::ceil(collectionIntervalSeconds * 1000 if(owner == nullptr) {
/ minimumPeriodicInterval); return 0;
}
bool isDiagnostics = owner->isDiagnostics();
/* Avoid division by zero */
if(minimumPeriodicInterval == 0) {
if(isDiagnostics) {
/* Perform operation each cycle */
return 1;
}
else {
return nonDiagIntervalFactor;
}
}
else {
dur_millis_t intervalInMs = collectionIntervalSeconds * 1000;
uint32_t divisor = minimumPeriodicInterval;
if(not isDiagnostics) {
/* We need to multiply the divisor because non-diagnostics only
allow a multiple of the minimum periodic interval */
divisor *= nonDiagIntervalFactor;
}
uint32_t ticks = std::ceil(static_cast<float>(intervalInMs) / divisor);
if(not isDiagnostics) {
/* Now we need to multiply the calculated ticks with the factor as as well
because the minimum tick count to generate a non-diagnostic is the factor itself.
Example calculation for non-diagnostic with
0.4 second interval and 0.2 second task interval.
Resultant tick count of 5 is equal to operation each second.
Examle calculation for non-diagnostic with 2.0 second interval and 0.2 second
task interval.
Resultant tick count of 10 is equal to operatin every 2 seconds.
Example calculation for diagnostic with 0.4 second interval and 0.3
second task interval. Resulting tick count of 2 is equal to operation
every 0.6 seconds. */
ticks *= nonDiagIntervalFactor;
}
return ticks;
}
} }
float PeriodicHousekeepingHelper::intervalToIntervalSeconds( float PeriodicHousekeepingHelper::intervalTicksToSeconds(
uint32_t collectionInterval) { uint32_t collectionInterval) const {
return static_cast<float>(collectionInterval * /* Number of ticks times the minimum interval is in milliseconds, so we divide by 1000 to get
minimumPeriodicInterval); the value in seconds */
return static_cast<float>(collectionInterval * minimumPeriodicInterval / 1000.0);
} }
void PeriodicHousekeepingHelper::changeCollectionInterval( void PeriodicHousekeepingHelper::changeCollectionInterval(
float newIntervalSeconds) { float newIntervalSeconds) {
collectionIntervalTicks = intervalSecondsToInterval(newIntervalSeconds); collectionIntervalTicks = intervalSecondsToIntervalTicks(newIntervalSeconds);
} }

View File

@ -10,18 +10,19 @@ class PeriodicHousekeepingHelper {
public: public:
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner); PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
void initialize(float collectionInterval, void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval,
dur_millis_t minimumPeriodicInterval, bool isDiagnostics, uint8_t nonDiagIntervalFactor);
uint8_t nonDiagIntervalFactor);
void changeCollectionInterval(float newInterval); void changeCollectionInterval(float newInterval);
float getCollectionIntervalInSeconds(); float getCollectionIntervalInSeconds() const;
bool checkOpNecessary(); bool checkOpNecessary();
private: private:
LocalPoolDataSetBase* owner = nullptr; LocalPoolDataSetBase* owner = nullptr;
uint8_t nonDiagIntervalFactor = 0;
uint32_t intervalSecondsToInterval(float collectionIntervalSeconds); uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds);
float intervalToIntervalSeconds(uint32_t collectionInterval); float intervalTicksToSeconds(uint32_t collectionInterval) const;
dur_millis_t minimumPeriodicInterval = 0; dur_millis_t minimumPeriodicInterval = 0;
uint32_t internalTickCounter = 1; uint32_t internalTickCounter = 1;

View File

@ -3,19 +3,20 @@
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
#include "../serviceinterface/ServiceInterface.h" #include "../serviceinterface/ServiceInterface.h"
#include "../datapool/PoolReadGuard.h"
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId,
uint32_t messageQueueDepth): SystemObject(setObjectId), uint32_t messageQueueDepth): SystemObject(setObjectId),
commandQueue(QueueFactory::instance()-> commandQueue(QueueFactory::instance()->
createMessageQueue(messageQueueDepth)), createMessageQueue(messageQueueDepth)),
poolManager(this, commandQueue), poolManager(this, commandQueue),
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
internalErrorDataset(this) { internalErrorDataset(this) {
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
} }
InternalErrorReporter::~InternalErrorReporter() { InternalErrorReporter::~InternalErrorReporter() {
MutexFactory::instance()->deleteMutex(mutex); MutexFactory::instance()->deleteMutex(mutex);
} }
void InternalErrorReporter::setDiagnosticPrintout(bool enable) { void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
@ -23,126 +24,128 @@ void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
} }
ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
internalErrorDataset.read(timeoutType, timeoutMs); CommandMessage message;
ReturnValue_t result = commandQueue->receiveMessage(&message);
if(result != MessageQueueIF::EMPTY) {
poolManager.handleHousekeepingMessage(&message);
}
uint32_t newQueueHits = getAndResetQueueHits(); uint32_t newQueueHits = getAndResetQueueHits();
uint32_t newTmHits = getAndResetTmHits(); uint32_t newTmHits = getAndResetTmHits();
uint32_t newStoreHits = getAndResetStoreHits(); uint32_t newStoreHits = getAndResetStoreHits();
#if FSFW_VERBOSE_LEVEL == 1 #if FSFW_VERBOSE_LEVEL >= 1
if(diagnosticPrintout) { if(diagnosticPrintout) {
if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) { if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "InternalErrorReporter::performOperation: Errors " sif::debug << "InternalErrorReporter::performOperation: Errors "
<< "occured!" << std::endl; << "occured!" << std::endl;
sif::debug << "Queue errors: " << newQueueHits << std::endl; sif::debug << "Queue errors: " << newQueueHits << std::endl;
sif::debug << "TM errors: " << newTmHits << std::endl; sif::debug << "TM errors: " << newTmHits << std::endl;
sif::debug << "Store errors: " << newStoreHits << std::endl; sif::debug << "Store errors: " << newStoreHits << std::endl;
#else #else
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n"); sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits)); sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits)); sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits)); sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
#endif #endif
} }
} }
#endif #endif
internalErrorDataset.queueHits.value += newQueueHits; {
internalErrorDataset.storeHits.value += newStoreHits; PoolReadGuard readGuard(&internalErrorDataset);
internalErrorDataset.tmHits.value += newTmHits; if(readGuard.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
internalErrorDataset.setValidity(true, true); internalErrorDataset.queueHits.value += newQueueHits;
internalErrorDataset.commit(timeoutType, timeoutMs); internalErrorDataset.storeHits.value += newStoreHits;
internalErrorDataset.tmHits.value += newTmHits;
internalErrorDataset.setValidity(true, true);
}
}
poolManager.performHkOperation(); poolManager.performHkOperation();
return HasReturnvaluesIF::RETURN_OK;
CommandMessage message;
ReturnValue_t result = commandQueue->receiveMessage(&message);
if(result != MessageQueueIF::EMPTY) {
poolManager.handleHousekeepingMessage(&message);
}
return HasReturnvaluesIF::RETURN_OK;
} }
void InternalErrorReporter::queueMessageNotSent() { void InternalErrorReporter::queueMessageNotSent() {
incrementQueueHits(); incrementQueueHits();
} }
void InternalErrorReporter::lostTm() { void InternalErrorReporter::lostTm() {
incrementTmHits(); incrementTmHits();
} }
uint32_t InternalErrorReporter::getAndResetQueueHits() { uint32_t InternalErrorReporter::getAndResetQueueHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
value = queueHits; value = queueHits;
queueHits = 0; queueHits = 0;
mutex->unlockMutex(); mutex->unlockMutex();
return value; return value;
} }
uint32_t InternalErrorReporter::getQueueHits() { uint32_t InternalErrorReporter::getQueueHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
value = queueHits; value = queueHits;
mutex->unlockMutex(); mutex->unlockMutex();
return value; return value;
} }
void InternalErrorReporter::incrementQueueHits() { void InternalErrorReporter::incrementQueueHits() {
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
queueHits++; queueHits++;
mutex->unlockMutex(); mutex->unlockMutex();
} }
uint32_t InternalErrorReporter::getAndResetTmHits() { uint32_t InternalErrorReporter::getAndResetTmHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
value = tmHits; value = tmHits;
tmHits = 0; tmHits = 0;
mutex->unlockMutex(); mutex->unlockMutex();
return value; return value;
} }
uint32_t InternalErrorReporter::getTmHits() { uint32_t InternalErrorReporter::getTmHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
value = tmHits; value = tmHits;
mutex->unlockMutex(); mutex->unlockMutex();
return value; return value;
} }
void InternalErrorReporter::incrementTmHits() { void InternalErrorReporter::incrementTmHits() {
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
tmHits++; tmHits++;
mutex->unlockMutex(); mutex->unlockMutex();
} }
void InternalErrorReporter::storeFull() { void InternalErrorReporter::storeFull() {
incrementStoreHits(); incrementStoreHits();
} }
uint32_t InternalErrorReporter::getAndResetStoreHits() { uint32_t InternalErrorReporter::getAndResetStoreHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
value = storeHits; value = storeHits;
storeHits = 0; storeHits = 0;
mutex->unlockMutex(); mutex->unlockMutex();
return value; return value;
} }
uint32_t InternalErrorReporter::getStoreHits() { uint32_t InternalErrorReporter::getStoreHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
value = storeHits; value = storeHits;
mutex->unlockMutex(); mutex->unlockMutex();
return value; return value;
} }
void InternalErrorReporter::incrementStoreHits() { void InternalErrorReporter::incrementStoreHits() {
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
storeHits++; storeHits++;
mutex->unlockMutex(); mutex->unlockMutex();
} }
object_id_t InternalErrorReporter::getObjectId() const { object_id_t InternalErrorReporter::getObjectId() const {
@ -155,14 +158,11 @@ MessageQueueId_t InternalErrorReporter::getCommandQueue() const {
ReturnValue_t InternalErrorReporter::initializeLocalDataPool( ReturnValue_t InternalErrorReporter::initializeLocalDataPool(
localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(errorPoolIds::TM_HITS, localDataPoolMap.emplace(errorPoolIds::TM_HITS, new PoolEntry<uint32_t>());
new PoolEntry<uint32_t>()); localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, new PoolEntry<uint32_t>());
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, localDataPoolMap.emplace(errorPoolIds::STORE_HITS, new PoolEntry<uint32_t>());
new PoolEntry<uint32_t>()); poolManager.subscribeForPeriodicPacket(internalErrorSid, false, getPeriodicOperationFrequency(),
localDataPoolMap.emplace(errorPoolIds::STORE_HITS, true);
new PoolEntry<uint32_t>());
poolManager.subscribeForPeriodicPacket(internalErrorSid, false,
getPeriodicOperationFrequency(), true);
internalErrorDataset.setValidity(true, true); internalErrorDataset.setValidity(true, true);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -192,9 +192,9 @@ ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() {
} }
void InternalErrorReporter::setMutexTimeout(MutexIF::TimeoutType timeoutType, void InternalErrorReporter::setMutexTimeout(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) { uint32_t timeoutMs) {
this->timeoutType = timeoutType; this->timeoutType = timeoutType;
this->timeoutMs = timeoutMs; this->timeoutMs = timeoutMs;
} }
LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() { LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() {

View File

@ -17,77 +17,78 @@
* All functions were kept virtual so this class can be extended easily * All functions were kept virtual so this class can be extended easily
* to store custom internal errors (e.g. communication interface errors). * to store custom internal errors (e.g. communication interface errors).
*/ */
class InternalErrorReporter: public SystemObject, class InternalErrorReporter:
public ExecutableObjectIF, public SystemObject,
public InternalErrorReporterIF, public ExecutableObjectIF,
public HasLocalDataPoolIF { public InternalErrorReporterIF,
public HasLocalDataPoolIF {
public: public:
InternalErrorReporter(object_id_t setObjectId, InternalErrorReporter(object_id_t setObjectId,
uint32_t messageQueueDepth = 5); uint32_t messageQueueDepth = 5);
/** /**
* Enable diagnostic printout. Please note that this feature will * Enable diagnostic printout. Please note that this feature will
* only work if DEBUG has been supplied to the build defines. * only work if DEBUG has been supplied to the build defines.
* @param enable * @param enable
*/ */
void setDiagnosticPrintout(bool enable); void setDiagnosticPrintout(bool enable);
void setMutexTimeout(MutexIF::TimeoutType timeoutType, void setMutexTimeout(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs); uint32_t timeoutMs);
virtual ~InternalErrorReporter(); virtual ~InternalErrorReporter();
virtual object_id_t getObjectId() const override; virtual object_id_t getObjectId() const override;
virtual MessageQueueId_t getCommandQueue() const override; virtual MessageQueueId_t getCommandQueue() const override;
virtual ReturnValue_t initializeLocalDataPool( virtual ReturnValue_t initializeLocalDataPool(
localpool::DataPool& localDataPoolMap, localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override; LocalDataPoolManager& poolManager) override;
virtual dur_millis_t getPeriodicOperationFrequency() const override; virtual dur_millis_t getPeriodicOperationFrequency() const override;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
LocalDataPoolManager* getHkManagerHandle() override; LocalDataPoolManager* getHkManagerHandle() override;
virtual ReturnValue_t initialize() override; virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override; virtual ReturnValue_t initializeAfterTaskCreation() override;
virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual void queueMessageNotSent(); virtual void queueMessageNotSent();
virtual void lostTm(); virtual void lostTm();
virtual void storeFull(); virtual void storeFull();
virtual void setTaskIF(PeriodicTaskIF* task) override; virtual void setTaskIF(PeriodicTaskIF* task) override;
protected: protected:
MessageQueueIF* commandQueue; MessageQueueIF* commandQueue;
LocalDataPoolManager poolManager; LocalDataPoolManager poolManager;
PeriodicTaskIF* executingTask = nullptr; PeriodicTaskIF* executingTask = nullptr;
MutexIF* mutex = nullptr; MutexIF* mutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 20; uint32_t timeoutMs = 20;
sid_t internalErrorSid; sid_t internalErrorSid;
InternalErrorDataset internalErrorDataset; InternalErrorDataset internalErrorDataset;
bool diagnosticPrintout = true; bool diagnosticPrintout = true;
uint32_t queueHits = 0; uint32_t queueHits = 0;
uint32_t tmHits = 0; uint32_t tmHits = 0;
uint32_t storeHits = 0; uint32_t storeHits = 0;
uint32_t getAndResetQueueHits(); uint32_t getAndResetQueueHits();
uint32_t getQueueHits(); uint32_t getQueueHits();
void incrementQueueHits(); void incrementQueueHits();
uint32_t getAndResetTmHits(); uint32_t getAndResetTmHits();
uint32_t getTmHits(); uint32_t getTmHits();
void incrementTmHits(); void incrementTmHits();
uint32_t getAndResetStoreHits(); uint32_t getAndResetStoreHits();
uint32_t getStoreHits(); uint32_t getStoreHits();
void incrementStoreHits(); void incrementStoreHits();
}; };

View File

@ -27,7 +27,7 @@ public:
//! Returned if a reply method was called without partner //! Returned if a reply method was called without partner
static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3); static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3);
//! Returned if the target destination is invalid. //! Returned if the target destination is invalid.
static constexpr ReturnValue_t DESTINVATION_INVALID = MAKE_RETURN_CODE(4); static constexpr ReturnValue_t DESTINATION_INVALID = MAKE_RETURN_CODE(4);
virtual ~MessageQueueIF() {} virtual ~MessageQueueIF() {}
/** /**

View File

@ -86,3 +86,7 @@ size_t MessageQueueMessage::getMaximumMessageSize() const {
return this->MAX_MESSAGE_SIZE; return this->MAX_MESSAGE_SIZE;
} }
size_t MessageQueueMessage::getMaximumDataSize() const {
return this->MAX_DATA_SIZE;
}

View File

@ -139,6 +139,7 @@ public:
virtual void setMessageSize(size_t messageSize) override; virtual void setMessageSize(size_t messageSize) override;
virtual size_t getMinimumMessageSize() const override; virtual size_t getMinimumMessageSize() const override;
virtual size_t getMaximumMessageSize() const override; virtual size_t getMaximumMessageSize() const override;
virtual size_t getMaximumDataSize() const override;
/** /**
* @brief This is a debug method that prints the content. * @brief This is a debug method that prints the content.

View File

@ -72,6 +72,7 @@ public:
virtual void setMessageSize(size_t messageSize) = 0; virtual void setMessageSize(size_t messageSize) = 0;
virtual size_t getMinimumMessageSize() const = 0; virtual size_t getMinimumMessageSize() const = 0;
virtual size_t getMaximumMessageSize() const = 0; virtual size_t getMaximumMessageSize() const = 0;
virtual size_t getMaximumDataSize() const = 0;
}; };

60
ipc/MutexGuard.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef FRAMEWORK_IPC_MUTEXGUARD_H_
#define FRAMEWORK_IPC_MUTEXGUARD_H_
#include "MutexFactory.h"
#include "../serviceinterface/ServiceInterface.h"
class MutexGuard {
public:
MutexGuard(MutexIF* mutex, MutexIF::TimeoutType timeoutType =
MutexIF::TimeoutType::BLOCKING, uint32_t timeoutMs = 0):
internalMutex(mutex) {
if(mutex == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexGuard: Passed mutex is invalid!" << std::endl;
#else
sif::printError("MutexGuard: Passed mutex is invalid!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return;
}
result = mutex->lockMutex(timeoutType,
timeoutMs);
#if FSFW_VERBOSE_LEVEL >= 1
if(result == MutexIF::MUTEX_TIMEOUT) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexGuard: Lock of mutex failed with timeout of "
<< timeoutMs << " milliseconds!" << std::endl;
#else
sif::printError("MutexGuard: Lock of mutex failed with timeout of %lu milliseconds\n",
timeoutMs);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
else if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexGuard: Lock of Mutex failed with code " << result << std::endl;
#else
sif::printError("MutexGuard: Lock of Mutex failed with code %d\n", result);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
#else
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
}
ReturnValue_t getLockResult() const {
return result;
}
~MutexGuard() {
if(internalMutex != nullptr) {
internalMutex->unlockMutex();
}
}
private:
MutexIF* internalMutex;
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
};
#endif /* FRAMEWORK_IPC_MUTEXGUARD_H_ */

View File

@ -1,57 +0,0 @@
#ifndef FRAMEWORK_IPC_MUTEXHELPER_H_
#define FRAMEWORK_IPC_MUTEXHELPER_H_
#include "MutexFactory.h"
#include "../serviceinterface/ServiceInterface.h"
class MutexHelper {
public:
MutexHelper(MutexIF* mutex, MutexIF::TimeoutType timeoutType =
MutexIF::TimeoutType::BLOCKING, uint32_t timeoutMs = 0):
internalMutex(mutex) {
if(mutex == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexHelper: Passed mutex is invalid!" << std::endl;
#else
sif::printError("MutexHelper: Passed mutex is invalid!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return;
}
ReturnValue_t status = mutex->lockMutex(timeoutType,
timeoutMs);
#if FSFW_VERBOSE_LEVEL >= 1
if(status == MutexIF::MUTEX_TIMEOUT) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexHelper: Lock of mutex failed with timeout of "
<< timeoutMs << " milliseconds!" << std::endl;
#else
sif::printError("MutexHelper: Lock of mutex failed with timeout of %lu milliseconds\n",
timeoutMs);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
else if(status != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexHelper: Lock of Mutex failed with code " << status << std::endl;
#else
sif::printError("MutexHelper: Lock of Mutex failed with code %d\n", status);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
#else
/* To avoid unused variable warning */
static_cast<void>(status);
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
}
~MutexHelper() {
if(internalMutex != nullptr) {
internalMutex->unlockMutex();
}
}
private:
MutexIF* internalMutex;
};
#endif /* FRAMEWORK_IPC_MUTEXHELPER_H_ */

View File

@ -1,34 +1,35 @@
# Check the OS_FSFW variable # Check the OS_FSFW variable
if(${OS_FSFW} STREQUAL "freertos") if(${OS_FSFW} STREQUAL "freertos")
add_subdirectory(FreeRTOS) add_subdirectory(FreeRTOS)
elseif(${OS_FSFW} STREQUAL "rtems") elseif(${OS_FSFW} STREQUAL "rtems")
add_subdirectory(rtems) add_subdirectory(rtems)
elseif(${OS_FSFW} STREQUAL "linux") elseif(${OS_FSFW} STREQUAL "linux")
add_subdirectory(linux) add_subdirectory(linux)
elseif(${OS_FSFW} STREQUAL "host") elseif(${OS_FSFW} STREQUAL "host")
add_subdirectory(host) add_subdirectory(host)
if (WIN32) if (WIN32)
add_subdirectory(windows) add_subdirectory(windows)
elseif(UNIX) elseif(UNIX)
target_sources(${LIB_FSFW_NAME} # We still need to pull in some Linux specific sources
PUBLIC target_sources(${LIB_FSFW_NAME} PUBLIC
linux/TcUnixUdpPollingTask.cpp linux/tcpipHelpers.cpp
linux/TmTcUnixUdpBridge.cpp )
) endif ()
endif ()
else() else()
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..") message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
# Not set. Assumuing this is a host build, try to determine host OS # Not set. Assumuing this is a host build, try to determine host OS
if (WIN32) if (WIN32)
add_subdirectory(host) add_subdirectory(host)
add_subdirectory(windows) add_subdirectory(windows)
elseif (UNIX) elseif (UNIX)
add_subdirectory(linux) add_subdirectory(linux)
else () else ()
# MacOS or other OSes have not been tested yet / are not supported. # MacOS or other OSes have not been tested yet / are not supported.
message(FATAL_ERROR "The host OS could not be determined! Aborting.") message(FATAL_ERROR "The host OS could not be determined! Aborting.")
endif() endif()
endif() endif()
add_subdirectory(common)

View File

@ -111,7 +111,7 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) { timeval* to) {
struct tm time_tm; struct tm time_tm = {};
time_tm.tm_year = from->year - 1900; time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1; time_tm.tm_mon = from->month - 1;

View File

@ -135,7 +135,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
QueueHandle_t destination = nullptr; QueueHandle_t destination = nullptr;
if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) { if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) {
return MessageQueueIF::DESTINVATION_INVALID; return MessageQueueIF::DESTINATION_INVALID;
} }
else { else {
destination = reinterpret_cast<QueueHandle_t>(sendTo); destination = reinterpret_cast<QueueHandle_t>(sendTo);

View File

@ -0,0 +1,16 @@
if(DEFINED WIN32 OR DEFINED UNIX)
target_sources(${LIB_FSFW_NAME} PRIVATE
tcpipCommon.cpp
TcpIpBase.cpp
UdpTcPollingTask.cpp
UdpTmTcBridge.cpp
TcpTmTcServer.cpp
)
endif()
if(WIN32)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
wsock32
ws2_32
)
endif()

54
osal/common/TcpIpBase.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "TcpIpBase.h"
#ifdef __unix__
#include <errno.h>
#include <unistd.h>
#endif
TcpIpBase::TcpIpBase() {
}
ReturnValue_t TcpIpBase::initialize() {
#ifdef _WIN32
/* Initiates Winsock DLL. */
WSAData wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable Winsock DLL. */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: WSAStartup failed with error: " <<
err << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
#endif
return HasReturnvaluesIF::RETURN_OK;
}
TcpIpBase::~TcpIpBase() {
closeSocket(serverSocket);
#ifdef _WIN32
WSACleanup();
#endif
}
int TcpIpBase::closeSocket(socket_t socket) {
#ifdef _WIN32
return closesocket(socket);
#elif defined(__unix__)
return close(socket);
#endif
}
int TcpIpBase::getLastSocketError() {
#ifdef _WIN32
return WSAGetLastError();
#elif defined(__unix__)
return errno;
#endif
}

50
osal/common/TcpIpBase.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef FSFW_OSAL_COMMON_TCPIPIF_H_
#define FSFW_OSAL_COMMON_TCPIPIF_H_
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#ifdef _WIN32
#include <winsock2.h>
#elif defined(__unix__)
#include <sys/socket.h>
#endif
class TcpIpBase {
protected:
#ifdef _WIN32
static constexpr int SHUT_RECV = SD_RECEIVE;
static constexpr int SHUT_SEND = SD_SEND;
static constexpr int SHUT_BOTH = SD_BOTH;
using socket_t = SOCKET;
#elif defined(__unix__)
using socket_t = int;
static constexpr int INVALID_SOCKET = -1;
static constexpr int SOCKET_ERROR = -1;
static constexpr int SHUT_RECV = SHUT_RD;
static constexpr int SHUT_SEND = SHUT_WR;
static constexpr int SHUT_BOTH = SHUT_RDWR;
#endif
TcpIpBase();
virtual ~TcpIpBase();
ReturnValue_t initialize();
int closeSocket(socket_t socket);
int getLastSocketError();
socket_t serverSocket = 0;
};
#endif /* FSFW_OSAL_COMMON_TCPIPIF_H_ */

View File

@ -0,0 +1,132 @@
#include "TcpTmTcServer.h"
#include "tcpipHelpers.h"
#include "../../serviceinterface/ServiceInterface.h"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#elif defined(__unix__)
#include <netdb.h>
#endif
const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7301";
const std::string TcpTmTcServer::DEFAULT_TCP_CLIENT_PORT = "7302";
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
std::string customTcpServerPort):
SystemObject(objectId), tcpPort(customTcpServerPort) {
if(tcpPort == "") {
tcpPort = DEFAULT_TCP_SERVER_PORT;
}
}
ReturnValue_t TcpTmTcServer::initialize() {
using namespace tcpip;
ReturnValue_t result = TcpIpBase::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
int retval = 0;
struct addrinfo *addrResult = nullptr;
struct addrinfo hints = {};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult);
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);
return HasReturnvaluesIF::RETURN_FAILED;
}
/* Open TCP (stream) socket */
listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype,
addrResult->ai_protocol);
if(listenerTcpSocket == INVALID_SOCKET) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcWinTcpServer: Socket creation failed!" << std::endl;
#endif
freeaddrinfo(addrResult);
handleError(Protocol::TCP, ErrorSources::SOCKET_CALL);
return HasReturnvaluesIF::RETURN_FAILED;
}
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
if(retval == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcpTmTcServer: Binding socket failed!" <<
std::endl;
#endif
freeaddrinfo(addrResult);
handleError(Protocol::TCP, ErrorSources::BIND_CALL);
return HasReturnvaluesIF::RETURN_FAILED;
}
freeaddrinfo(addrResult);
return HasReturnvaluesIF::RETURN_OK;
}
TcpTmTcServer::~TcpTmTcServer() {
closeSocket(listenerTcpSocket);
}
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
using namespace tcpip;
/* If a connection is accepted, the corresponding socket will be assigned to the new socket */
socket_t clientSocket = 0;
sockaddr clientSockAddr = {};
socklen_t connectorSockAddrLen = 0;
int retval = 0;
/* Listen for connection requests permanently for lifetime of program */
while(true) {
retval = listen(listenerTcpSocket, currentBacklog);
if(retval == SOCKET_ERROR) {
handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500);
continue;
}
clientSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
if(clientSocket == INVALID_SOCKET) {
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
closeSocket(clientSocket);
continue;
};
retval = recv(clientSocket, reinterpret_cast<char*>(receptionBuffer.data()),
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) {
}
else {
}
/* Done, shut down connection */
retval = shutdown(clientSocket, SHUT_SEND);
closeSocket(clientSocket);
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,53 @@
#ifndef FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_
#define FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_
#include "TcpIpBase.h"
#include "../../objectmanager/SystemObject.h"
#include "../../tasks/ExecutableObjectIF.h"
#ifdef __unix__
#include <sys/socket.h>
#endif
#include <string>
#include <vector>
//! Debugging preprocessor define.
#define FSFW_TCP_RCV_WIRETAPPING_ENABLED 0
/**
* @brief Windows TCP server used to receive telecommands on a Windows Host
* @details
* Based on: https://docs.microsoft.com/en-us/windows/win32/winsock/complete-server-code
*/
class TcpTmTcServer:
public SystemObject,
public TcpIpBase,
public ExecutableObjectIF {
public:
/* 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_CLIENT_PORT;
TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
std::string customTcpServerPort = "");
virtual~ TcpTmTcServer();
ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t opCode) override;
private:
std::string tcpPort;
socket_t listenerTcpSocket = 0;
struct sockaddr tcpAddress;
int tcpAddrLen = sizeof(tcpAddress);
int currentBacklog = 3;
std::vector<uint8_t> receptionBuffer;
int tcpSockOpt = 0;
};
#endif /* FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ */

View File

@ -0,0 +1,180 @@
#include "UdpTcPollingTask.h"
#include "tcpipHelpers.h"
#include "../../globalfunctions/arrayprinter.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#endif
//! Debugging preprocessor define.
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t maxRecvSize,
double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) {
if(frameSize > 0) {
this->frameSize = frameSize;
}
else {
this->frameSize = DEFAULT_MAX_RECV_SIZE;
}
/* Set up reception buffer with specified frame size.
For now, it is assumed that only one frame is held in the buffer! */
receptionBuffer.reserve(this->frameSize);
receptionBuffer.resize(this->frameSize);
if(timeoutSeconds == -1) {
receptionTimeout = DEFAULT_TIMEOUT;
}
else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
UdpTcPollingTask::~UdpTcPollingTask() {}
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
/* Sender Address is cached here. */
struct sockaddr senderAddress;
socklen_t senderAddressSize = sizeof(senderAddress);
/* Poll for new UDP datagrams in permanent loop. */
while(true) {
int bytesReceived = recvfrom(
this->serverSocket,
reinterpret_cast<char*>(receptionBuffer.data()),
frameSize,
receptionFlags,
&senderAddress,
&senderAddressSize
);
if(bytesReceived == SOCKET_ERROR) {
/* Handle error */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UdpTcPollingTask::performOperation: Reception error." << std::endl;
#endif
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::RECVFROM_CALL, 1000);
continue;
}
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "UdpTcPollingTask::performOperation: " << bytesReceived <<
" bytes received" << std::endl;
#else
#endif
#endif /* FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1 */
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if(result != HasReturnvaluesIF::RETURN_FAILED) {
}
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
store_address_t storeId;
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
arrayprinter::print(receptionBuffer.data(), bytesRead);
#endif
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning<< "UdpTcPollingTask::transferPusToSoftwareBus: Data storage failed." <<
std::endl;
sif::warning << "Packet size: " << bytesRead << std::endl;
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return HasReturnvaluesIF::RETURN_FAILED;
}
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;
}
ReturnValue_t UdpTcPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UdpTcPollingTask::initialize: TC store uninitialized!" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<UdpTmTcBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UdpTcPollingTask::initialize: Invalid TMTC bridge object!" <<
std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
ReturnValue_t result = TcpIpBase::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t UdpTcPollingTask::initializeAfterTaskCreation() {
/* Initialize the destination after task creation. This ensures
that the destination has already been set in the TMTC bridge. */
targetTcDestination = tmtcBridge->getRequestQueue();
/* The server socket is set up in the bridge intialization. Calling this function here
ensures that it is set up regardless of which class was initialized first */
this->serverSocket = tmtcBridge->serverSocket;
return HasReturnvaluesIF::RETURN_OK;
}
void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
#ifdef _WIN32
DWORD timeoutMs = timeoutSeconds * 1000.0;
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
if(result == -1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
#endif
}
#elif defined(__unix__)
timeval tval;
tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
&tval, sizeof(receptionTimeout));
if(result == -1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
#endif
}
#endif
}

View File

@ -1,7 +1,7 @@
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ #ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ #define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
#include "TmTcWinUdpBridge.h" #include "UdpTmTcBridge.h"
#include "../../objectmanager/SystemObject.h" #include "../../objectmanager/SystemObject.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
#include "../../storagemanager/StorageManagerIF.h" #include "../../storagemanager/StorageManagerIF.h"
@ -9,25 +9,22 @@
#include <vector> #include <vector>
/** /**
* @brief This class can be used to implement the polling of a Unix socket, * @brief This class should be used with the UdpTmTcBridge to implement a UDP server
* using UDP for now. * for receiving and sending PUS TMTC.
* @details
* The task will be blocked while the specified number of bytes has not been
* received, so TC reception is handled inside a separate task.
* This class caches the IP address of the sender. It is assumed there
* is only one sender for now.
*/ */
class TcWinUdpPollingTask: public SystemObject, class UdpTcPollingTask:
public TcpIpBase,
public SystemObject,
public ExecutableObjectIF { public ExecutableObjectIF {
friend class TmTcWinUdpBridge; friend class TmTcWinUdpBridge;
public: public:
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048; static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
//! 0.5 default milliseconds timeout for now. //! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500}; static constexpr timeval DEFAULT_TIMEOUT = {0, 500};
TcWinUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
size_t frameSize = 0, double timeoutSeconds = -1); size_t maxRecvSize = 0, double timeoutSeconds = -1);
virtual~ TcWinUdpPollingTask(); virtual~ UdpTcPollingTask();
/** /**
* Turn on optional timeout for UDP polling. In the default mode, * Turn on optional timeout for UDP polling. In the default mode,
@ -46,14 +43,11 @@ protected:
private: private:
//! TMTC bridge is cached. //! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT; object_id_t tmtcBridgeId = objects::NO_OBJECT;
TmTcWinUdpBridge* tmtcBridge = nullptr; UdpTmTcBridge* tmtcBridge = nullptr;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
//! Reception flags: https://linux.die.net/man/2/recvfrom.
int receptionFlags = 0;
//! Server socket, which is member of TMTC bridge and is assigned in //! See: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom
//! constructor int receptionFlags = 0;
SOCKET serverUdpSocket = 0;
std::vector<uint8_t> receptionBuffer; std::vector<uint8_t> receptionBuffer;
@ -61,7 +55,6 @@ private:
timeval receptionTimeout; timeval receptionTimeout;
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
void handleReadError();
}; };
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */ #endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */

View File

@ -0,0 +1,174 @@
#include "tcpipHelpers.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/ipc/MutexGuard.h>
#include <fsfw/osal/common/UdpTmTcBridge.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#elif defined(__unix__)
#include <netdb.h>
#include <arpa/inet.h>
#endif
//! Debugging preprocessor define.
#define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0
const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
if(udpServerPort == "") {
this->udpServerPort = DEFAULT_UDP_SERVER_PORT;
}
else {
this->udpServerPort = udpServerPort;
}
mutex = MutexFactory::instance()->createMutex();
communicationLinkUp = false;
}
ReturnValue_t UdpTmTcBridge::initialize() {
ReturnValue_t result = TmTcBridge::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::initialize: TmTcBridge initialization failed!"
<< std::endl;
#endif
return result;
}
#ifdef _WIN32
/* Initiates Winsock DLL. */
WSAData wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: " <<
err << std::endl;
#else
sif::printError("TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: %d\n",
err);
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
#endif
struct addrinfo *addrResult = nullptr;
struct addrinfo hints = {};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE;
/* Set up UDP socket:
https://en.wikipedia.org/wiki/Getaddrinfo
Passing nullptr as the first parameter and specifying AI_PASSIVE in hints will cause
getaddrinfo to assign the address 0.0.0.0 (any address) */
int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult);
if (retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Retrieving address info failed!" <<
std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol);
if(serverSocket == INVALID_SOCKET) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Could not open UDP socket!" <<
std::endl;
#endif
freeaddrinfo(addrResult);
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL);
return HasReturnvaluesIF::RETURN_FAILED;
}
#if FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
tcpip::printAddress(addrResult->ai_addr);
#endif
retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
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);
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL);
return HasReturnvaluesIF::RETURN_FAILED;
}
freeaddrinfo(addrResult);
return HasReturnvaluesIF::RETURN_OK;
}
UdpTmTcBridge::~UdpTmTcBridge() {
if(mutex != nullptr) {
MutexFactory::instance()->deleteMutex(mutex);
}
}
ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
/* The target address can be set by different threads so this lock ensures thread-safety */
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
#if FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
tcpip::printAddress(&clientAddress);
#endif
int bytesSent = sendto(
serverSocket,
reinterpret_cast<const char*>(data),
dataLen,
flags,
&clientAddress,
clientAddressLen
);
if(bytesSent == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcUdpBridge::sendTm: Send operation failed." << std::endl;
#endif
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL);
}
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent << " bytes were"
" sent." << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK;
}
void UdpTmTcBridge::checkAndSetClientAddress(sockaddr& newAddress) {
/* The target address can be set by different threads so this lock ensures thread-safety */
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
#if FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
tcpip::printAddress(&newAddress);
tcpip::printAddress(&clientAddress);
#endif
registerCommConnect();
/* Set new IP address to reply to */
clientAddress = newAddress;
clientAddressLen = sizeof(clientAddress);
}
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType,
dur_millis_t timeoutMs) {
this->timeoutType = timeoutType;
this->mutexTimeoutMs = timeoutMs;
}

View File

@ -0,0 +1,60 @@
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_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 UdpTcPollingTask to implement a UDP server
* for receiving and sending PUS TMTC.
*/
class UdpTmTcBridge:
public TmTcBridge,
public TcpIpBase {
friend class UdpTcPollingTask;
public:
/* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_UDP_SERVER_PORT;
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort = "");
virtual~ UdpTmTcBridge();
/**
* Set properties of internal mutex.
*/
void setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs);
ReturnValue_t initialize() override;
void checkAndSetClientAddress(sockaddr& clientAddress);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
std::string udpServerPort;
struct sockaddr clientAddress;
socklen_t clientAddressLen = 0;
//! Access to the client address is mutex protected as it is set by another task.
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
dur_millis_t mutexTimeoutMs = 20;
MutexIF* mutex;
};
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */

View File

@ -0,0 +1,75 @@
#include "tcpipCommon.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#endif
void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string &protStr,
std::string &srcString) {
if(protocol == Protocol::TCP) {
protStr = "TCP";
}
else if(protocol == Protocol::UDP) {
protStr = "UDP";
}
else {
protStr = "Unknown protocol";
}
if(errorSrc == ErrorSources::SETSOCKOPT_CALL) {
srcString = "setsockopt call";
}
else if(errorSrc == ErrorSources::SOCKET_CALL) {
srcString = "socket call";
}
else if(errorSrc == ErrorSources::LISTEN_CALL) {
srcString = "listen call";
}
else if(errorSrc == ErrorSources::ACCEPT_CALL) {
srcString = "accept call";
}
else if(errorSrc == ErrorSources::RECVFROM_CALL) {
srcString = "recvfrom call";
}
else if(errorSrc == ErrorSources::GETADDRINFO_CALL) {
srcString = "getaddrinfo call";
}
else {
srcString = "unknown call";
}
}
void tcpip::printAddress(struct sockaddr* addr) {
char ipAddress[INET6_ADDRSTRLEN] = {};
const char* stringPtr = NULL;
switch(addr->sa_family) {
case AF_INET: {
struct sockaddr_in *addrIn = reinterpret_cast<struct sockaddr_in*>(addr);
stringPtr = inet_ntop(AF_INET, &(addrIn->sin_addr), ipAddress, INET_ADDRSTRLEN);
break;
}
case AF_INET6: {
struct sockaddr_in6 *addrIn = reinterpret_cast<struct sockaddr_in6*>(addr);
stringPtr = inet_ntop(AF_INET6, &(addrIn->sin6_addr), ipAddress, INET6_ADDRSTRLEN);
break;
}
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
if(stringPtr == NULL) {
sif::debug << "Could not convert IP address to text representation, error code "
<< errno << std::endl;
}
else {
sif::debug << "IP Address Sender: " << ipAddress << std::endl;
}
#else
if(stringPtr == NULL) {
sif::printDebug("Could not convert IP address to text representation, error code %d\n",
errno);
}
else {
sif::printDebug("IP Address Sender: %s\n", ipAddress);
}
#endif
}

42
osal/common/tcpipCommon.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef FSFW_OSAL_COMMON_TCPIPCOMMON_H_
#define FSFW_OSAL_COMMON_TCPIPCOMMON_H_
#include "../../timemanager/clockDefinitions.h"
#include <string>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <netdb.h>
#include <arpa/inet.h>
#endif
namespace tcpip {
const char* const DEFAULT_SERVER_PORT = "7301";
enum class Protocol {
UDP,
TCP
};
enum class ErrorSources {
GETADDRINFO_CALL,
SOCKET_CALL,
SETSOCKOPT_CALL,
BIND_CALL,
RECV_CALL,
RECVFROM_CALL,
LISTEN_CALL,
ACCEPT_CALL,
SENDTO_CALL
};
void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr,
std::string& srcString);
void printAddress(struct sockaddr* addr);
}
#endif /* FSFW_OSAL_COMMON_TCPIPCOMMON_H_ */

View File

@ -0,0 +1,15 @@
#ifndef FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_
#define FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_
#include "../../timemanager/clockDefinitions.h"
#include "tcpipCommon.h"
namespace tcpip {
void handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration = 0);
}
#endif /* FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_ */

View File

@ -10,6 +10,7 @@ target_sources(${LIB_FSFW_NAME}
QueueMapManager.cpp QueueMapManager.cpp
SemaphoreFactory.cpp SemaphoreFactory.cpp
TaskFactory.cpp TaskFactory.cpp
taskHelpers.cpp
) )
if(UNIX) if(UNIX)

View File

@ -1,10 +1,9 @@
#include "taskHelpers.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 "../../serviceinterface/ServiceInterface.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
#include <thread> #include <thread>
@ -12,6 +11,7 @@
#if defined(WIN32) #if defined(WIN32)
#include <windows.h> #include <windows.h>
#include "../windows/winTaskHelpers.h"
#elif defined(LINUX) #elif defined(LINUX)
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -24,34 +24,12 @@ FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
// It is propably possible to set task priorities by using the native // It is propably possible to set task priorities by using the native
// task handles for Windows / Linux // task handles for Windows / Linux
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this); mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
#if defined(WIN32) #if defined(_WIN32)
/* List of possible priority classes: tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ #elif defined(__unix__)
* nf-processthreadsapi-setpriorityclass // TODO: We could reuse existing code here.
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
#elif defined(LINUX)
// TODO: we can just copy and paste the code from the linux OSAL here.
#endif #endif
tasks::insertTaskName(mainThread.get_id(), taskName);
} }
FixedTimeslotTask::~FixedTimeslotTask(void) { FixedTimeslotTask::~FixedTimeslotTask(void) {
@ -60,7 +38,6 @@ FixedTimeslotTask::~FixedTimeslotTask(void) {
if(mainThread.joinable()) { if(mainThread.joinable()) {
mainThread.join(); mainThread.join();
} }
delete this;
} }
void FixedTimeslotTask::taskEntryPoint(void* argument) { void FixedTimeslotTask::taskEntryPoint(void* argument) {
@ -141,8 +118,11 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
} }
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Component " << std::hex << componentId << sif::error << "Component " << std::hex << "0x" << componentId << "not found, "
" not found, not adding it to pst" << std::endl; "not adding it to PST.." << std::dec << std::endl;
#else
sif::printError("Component 0x%08x not found, not adding it to PST..\n",
static_cast<unsigned int>(componentId));
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -3,7 +3,7 @@
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h" #include "../../ipc/MutexGuard.h"
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
messageSize(maxMessageSize), messageDepth(messageDepth) { messageSize(maxMessageSize), messageDepth(messageDepth) {
@ -63,12 +63,9 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(messageQueue.empty()) { if(messageQueue.empty()) {
return MessageQueueIF::EMPTY; return MessageQueueIF::EMPTY;
} }
// not sure this will work.. MutexGuard mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20);
//*message = std::move(messageQueue.front()); std::copy(messageQueue.front().data(), messageQueue.front().data() + messageSize,
MutexHelper mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20); message->getBuffer());
MessageQueueMessage* currentMessage = &messageQueue.front();
std::copy(currentMessage->getBuffer(),
currentMessage->getBuffer() + messageSize, message->getBuffer());
messageQueue.pop(); messageQueue.pop();
// The last partner is the first uint32_t field in the message // The last partner is the first uint32_t field in the message
this->lastPartner = message->getSender(); this->lastPartner = message->getSender();
@ -82,7 +79,7 @@ MessageQueueId_t MessageQueue::getLastPartner() const {
ReturnValue_t MessageQueue::flush(uint32_t* count) { ReturnValue_t MessageQueue::flush(uint32_t* count) {
*count = messageQueue.size(); *count = messageQueue.size();
// Clears the queue. // Clears the queue.
messageQueue = std::queue<MessageQueueMessage>(); messageQueue = std::queue<std::vector<uint8_t>>();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -108,6 +105,9 @@ bool MessageQueue::isDefaultDestinationSet() const {
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault) {
if(message == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
message->setSender(sentFrom); message->setSender(sentFrom);
if(message->getMessageSize() > message->getMaximumMessageSize()) { if(message->getMessageSize() > message->getMaximumMessageSize()) {
// Actually, this should never happen or an error will be emitted // Actually, this should never happen or an error will be emitted
@ -130,21 +130,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) { if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
MutexHelper mutexLock(targetQueue->queueLock, MutexGuard mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20);
MutexIF::TimeoutType::WAITING, 20); targetQueue->messageQueue.push(std::vector<uint8_t>(message->getMaximumMessageSize()));
// not ideal, works for now though. memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(),
MessageQueueMessage* mqmMessage = message->getMaximumMessageSize());
dynamic_cast<MessageQueueMessage*>(message);
if(message != nullptr) {
targetQueue->messageQueue.push(*mqmMessage);
}
else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message"
"is not MessageQueueMessage!" << std::endl;
#endif
}
} }
else { else {
return MessageQueueIF::FULL; return MessageQueueIF::FULL;

View File

@ -212,7 +212,7 @@ protected:
//static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); //static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private: private:
std::queue<MessageQueueMessage> messageQueue; std::queue<std::vector<uint8_t>> messageQueue;
/** /**
* @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.

View File

@ -24,5 +24,7 @@ MutexIF* MutexFactory::createMutex() {
} }
void MutexFactory::deleteMutex(MutexIF* mutex) { void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex; if(mutex != nullptr) {
delete mutex;
}
} }

View File

@ -1,5 +1,6 @@
#include "Mutex.h" #include "Mutex.h"
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include "taskHelpers.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
@ -10,7 +11,8 @@
#if defined(WIN32) #if defined(WIN32)
#include <processthreadsapi.h> #include <processthreadsapi.h>
#elif defined(LINUX) #include <fsfw/osal/windows/winTaskHelpers.h>
#elif defined(__unix__)
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -19,37 +21,15 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
void (*setDeadlineMissedFunc)()) : void (*setDeadlineMissedFunc)()) :
started(false), taskName(name), period(setPeriod), started(false), taskName(name), period(setPeriod),
deadlineMissedFunc(setDeadlineMissedFunc) { deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably 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(_WIN32)
/* List of possible priority classes: tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ #elif defined(__unix__)
* nf-processthreadsapi-setpriorityclass // TODO: We could reuse existing code here.
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif #endif
tasks::insertTaskName(mainThread.get_id(), taskName);
} }
PeriodicTask::~PeriodicTask(void) { PeriodicTask::~PeriodicTask(void) {
@ -58,7 +38,6 @@ PeriodicTask::~PeriodicTask(void) {
if(mainThread.joinable()) { if(mainThread.joinable()) {
mainThread.join(); mainThread.join();
} }
delete this;
} }
void PeriodicTask::taskEntryPoint(void* argument) { void PeriodicTask::taskEntryPoint(void* argument) {

View File

@ -2,7 +2,7 @@
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h" #include "../../ipc/MutexGuard.h"
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr; QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
@ -10,6 +10,10 @@ QueueMapManager::QueueMapManager() {
mapLock = MutexFactory::instance()->createMutex(); mapLock = MutexFactory::instance()->createMutex();
} }
QueueMapManager::~QueueMapManager() {
MutexFactory::instance()->deleteMutex(mapLock);
}
QueueMapManager* QueueMapManager::instance() { QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){ if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager(); mqManagerInstance = new QueueMapManager();
@ -43,7 +47,7 @@ ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* QueueMapManager::getMessageQueue( MessageQueueIF* QueueMapManager::getMessageQueue(
MessageQueueId_t messageQueueId) const { MessageQueueId_t messageQueueId) const {
MutexHelper(mapLock, MutexIF::TimeoutType::WAITING, 50); 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;

View File

@ -36,6 +36,8 @@ public:
private: private:
//! External instantiation is forbidden. //! External instantiation is forbidden.
QueueMapManager(); QueueMapManager();
~QueueMapManager();
uint32_t queueCounter = 0; uint32_t queueCounter = 0;
MutexIF* mapLock; MutexIF* mapLock;
QueueMap queueMap; QueueMap queueMap;

View File

@ -1,7 +1,5 @@
#include "../../tasks/SemaphoreFactory.h" #include "../../tasks/SemaphoreFactory.h"
#include "../../osal/linux/BinarySemaphore.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;

View File

@ -1,14 +1,16 @@
#include "taskHelpers.h"
#include "../../tasks/TaskFactory.h"
#include "../../osal/host/FixedTimeslotTask.h" #include "../../osal/host/FixedTimeslotTask.h"
#include "../../osal/host/PeriodicTask.h" #include "../../osal/host/PeriodicTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/PeriodicTaskIF.h" #include "../../tasks/PeriodicTaskIF.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <chrono> #include <chrono>
TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
// Will propably not be used for hosted implementation // Not used for the host implementation for now because C++ thread abstraction is used
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() { TaskFactory::TaskFactory() {
@ -49,8 +51,12 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
} }
void TaskFactory::printMissedDeadline() { void TaskFactory::printMissedDeadline() {
/* TODO: Implement */ std::string name = tasks::getTaskName(std::this_thread::get_id());
return; #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TaskFactory::printMissedDeadline: " << name << std::endl;
#else
sif::printWarning("TaskFactory::printMissedDeadline: %s\n", name);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
} }

27
osal/host/taskHelpers.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "taskHelpers.h"
#include <map>
#include <mutex>
std::mutex nameMapLock;
std::map<std::thread::id, std::string> taskNameMap;
ReturnValue_t tasks::insertTaskName(std::thread::id threadId, std::string taskName) {
std::lock_guard<std::mutex> lg(nameMapLock);
auto returnPair = taskNameMap.emplace(threadId, taskName);
if(not returnPair.second) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
std::string tasks::getTaskName(std::thread::id threadId) {
std::lock_guard<std::mutex> lg(nameMapLock);
auto resultIter = taskNameMap.find(threadId);
if(resultIter != taskNameMap.end()) {
return resultIter->second;
}
else {
return "Unknown task";
}
}

16
osal/host/taskHelpers.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef FSFW_OSAL_HOST_TASKHELPERS_H_
#define FSFW_OSAL_HOST_TASKHELPERS_H_
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <thread>
namespace tasks {
ReturnValue_t insertTaskName(std::thread::id threadId, std::string taskName);
std::string getTaskName(std::thread::id threadId);
}
#endif /* FSFW_OSAL_HOST_TASKHELPERS_H_ */

View File

@ -13,9 +13,8 @@ target_sources(${LIB_FSFW_NAME}
QueueFactory.cpp QueueFactory.cpp
SemaphoreFactory.cpp SemaphoreFactory.cpp
TaskFactory.cpp TaskFactory.cpp
TcUnixUdpPollingTask.cpp
TmTcUnixUdpBridge.cpp
Timer.cpp Timer.cpp
tcpipHelpers.cpp
) )
find_package(Threads REQUIRED) find_package(Threads REQUIRED)

View File

@ -190,13 +190,15 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
}else if(status==0){ }
else if (status==0) {
//Success but no message received //Success but no message received
return MessageQueueIF::EMPTY; return MessageQueueIF::EMPTY;
} else { }
else {
//No message was received. Keep lastPartner anyway, I might send //No message was received. Keep lastPartner anyway, I might send
//something later. But still, delete packet content. //something later. But still, delete packet content.
memset(message->getData(), 0, message->getMaximumMessageSize()); memset(message->getData(), 0, message->getMaximumDataSize());
switch(errno){ switch(errno){
case EAGAIN: case EAGAIN:
//O_NONBLOCK or MQ_NONBLOCK was set and there are no messages //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages
@ -371,7 +373,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
<<"mq_send to: " << sendTo << " sent from " <<"mq_send to: " << sendTo << " sent from "
<< sentFrom << std::endl; << sentFrom << std::endl;
#endif #endif
return DESTINVATION_INVALID; return DESTINATION_INVALID;
} }
case EINTR: case EINTR:
//The call was interrupted by a signal. //The call was interrupted by a signal.

View File

@ -6,7 +6,7 @@
#include <errno.h> #include <errno.h>
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_): PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):
thread(0),priority(priority_),stackSize(stackSize_) { thread(0), priority(priority_), stackSize(stackSize_) {
name[0] = '\0'; name[0] = '\0';
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1); std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
} }
@ -75,18 +75,18 @@ bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms,
if (currentTime_ms < *prevoiusWakeTime_ms) { if (currentTime_ms < *prevoiusWakeTime_ms) {
/* The tick count has overflowed since this function was /* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed, actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */ is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
&& (nextTimeToWake_ms > currentTime_ms)) { && (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true; shouldDelay = true;
} }
} else { } else {
/* The tick time has not overflowed. In this case we will /* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */ tick time is less than the wake time. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
|| (nextTimeToWake_ms > currentTime_ms)) { || (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true; shouldDelay = true;
@ -184,8 +184,11 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
strerror(status) << std::endl; strerror(status) << std::endl;
#endif #endif
} }
#ifndef FSFW_USE_REALTIME_FOR_LINUX
// TODO FIFO -> This needs root privileges for the process #error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1"
#endif
#if FSFW_USE_REALTIME_FOR_LINUX == 1
// 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 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -203,7 +206,7 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
strerror(status) << std::endl; 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
sigset_t waitSignal; sigset_t waitSignal;
sigemptyset(&waitSignal); sigemptyset(&waitSignal);
@ -220,8 +223,16 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
status = pthread_create(&thread,&attributes,fnc_,arg_); status = pthread_create(&thread,&attributes,fnc_,arg_);
if(status != 0){ if(status != 0){
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Posix Thread create failed with: " << sif::error << "PosixThread::createTask: Failed with: " <<
strerror(status) << std::endl; strerror(status) << std::endl;
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 "
"/etc/security/limit.conf" << std::endl;
#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 "
"\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set "
"/etc/security/limit.conf\n");
#endif #endif
} }

View File

@ -2,6 +2,7 @@
#include "PeriodicPosixTask.h" #include "PeriodicPosixTask.h"
#include "../../tasks/TaskFactory.h" #include "../../tasks/TaskFactory.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? //TODO: Different variant than the lazy loading in QueueFactory. What's better and why?

View File

@ -1,158 +0,0 @@
#include "TcUnixUdpPollingTask.h"
#include "../../globalfunctions/arrayprinter.h"
#include <errno.h>
TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t frameSize,
double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) {
if(frameSize > 0) {
this->frameSize = frameSize;
}
else {
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
}
// Set up reception buffer with specified frame size.
// For now, it is assumed that only one frame is held in the buffer!
receptionBuffer.reserve(this->frameSize);
receptionBuffer.resize(this->frameSize);
if(timeoutSeconds == -1) {
receptionTimeout = DEFAULT_TIMEOUT;
}
else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {}
ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
// Poll for new UDP datagrams in permanent loop.
while(1) {
//! Sender Address is cached here.
struct sockaddr_in senderAddress;
socklen_t senderSockLen = sizeof(senderAddress);
ssize_t bytesReceived = recvfrom(serverUdpSocket,
receptionBuffer.data(), frameSize, receptionFlags,
reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen);
if(bytesReceived < 0) {
// handle error
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSocketPollingTask::performOperation: Reception"
"error." << std::endl;
#endif
handleReadError();
continue;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived
// << " bytes received" << std::endl;
#endif
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if(result != HasReturnvaluesIF::RETURN_FAILED) {
}
tmtcBridge->registerCommConnect();
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId,
receptionBuffer.data(), bytesRead);
// arrayprinter::print(receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
"storage failed" << std::endl;
sif::error << "Packet size: " << bytesRead << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Serial Polling: Sending message to queue failed"
<< std::endl;
#endif
tcStore->deleteData(storeId);
}
return result;
}
ReturnValue_t TcUnixUdpPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
<< std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<TmTcUnixUdpBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
" TMTC bridge object!" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
serverUdpSocket = tmtcBridge->serverSocket;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() {
// Initialize the destination after task creation. This ensures
// that the destination will be set in the TMTC bridge.
targetTcDestination = tmtcBridge->getRequestQueue();
return HasReturnvaluesIF::RETURN_OK;
}
void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) {
timeval tval;
tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
&tval, sizeof(receptionTimeout));
if(result == -1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
#endif
}
}
// TODO: sleep after error detection to prevent spam
void TcUnixUdpPollingTask::handleReadError() {
switch(errno) {
case(EAGAIN): {
// todo: When working in timeout mode, this will occur more often
// and is not an error.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout."
<< std::endl;
#endif
break;
}
default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcUnixUdpPollingTask::handleReadError: "
<< strerror(errno) << std::endl;
#endif
}
}
}

View File

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

View File

@ -1,206 +0,0 @@
#include "TmTcUnixUdpBridge.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../ipc/MutexHelper.h"
#include <errno.h>
#include <arpa/inet.h>
TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId,
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort, uint16_t clientPort):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
if(serverPort != 0xFFFF) {
setServerPort = serverPort;
}
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
if(clientPort != 0xFFFF) {
setClientPort = clientPort;
}
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(serverSocket < 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open"
" UDP socket!" << std::endl;
#endif
handleSocketError();
return;
}
serverAddress.sin_family = AF_INET;
// Accept packets from any interface.
//serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0");
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(setServerPort);
serverAddressLen = sizeof(serverAddress);
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions,
sizeof(serverSocketOptions));
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddress.sin_port = htons(setClientPort);
clientAddressLen = sizeof(clientAddress);
int result = bind(serverSocket,
reinterpret_cast<struct sockaddr*>(&serverAddress),
serverAddressLen);
if(result == -1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind "
"local port " << setServerPort << " to server socket!"
<< std::endl;
#endif
handleBindError();
return;
}
}
TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
}
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
if(ipAddrAnySet){
clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
//clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1");
clientAddressLen = sizeof(serverAddress);
}
// char ipAddress [15];
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
#endif
ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags,
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
if(bytesSent < 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed."
<< std::endl;
#endif
handleSendError();
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
// " sent." << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK;
}
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
// char ipAddress [15];
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
#endif
// Set new IP address if it has changed.
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
clientAddressLen = sizeof(clientAddress);
}
}
void TmTcUnixUdpBridge::handleSocketError() {
// See: https://man7.org/linux/man-pages/man2/socket.2.html
switch(errno) {
case(EACCES):
case(EINVAL):
case(EMFILE):
case(ENFILE):
case(EAFNOSUPPORT):
case(ENOBUFS):
case(ENOMEM):
case(EPROTONOSUPPORT):
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
#endif
break;
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleSocketError: Unknown error"
<< std::endl;
#endif
break;
}
}
void TmTcUnixUdpBridge::handleBindError() {
// See: https://man7.org/linux/man-pages/man2/bind.2.html
switch(errno) {
case(EACCES): {
/*
Ephermeral ports can be shown with following command:
sysctl -A | grep ip_local_port_range
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleBindError: Port access issue."
"Ports 1-1024 are reserved on UNIX systems and require root "
"rights while ephermeral ports should not be used as well."
<< std::endl;
#endif
}
break;
case(EADDRINUSE):
case(EBADF):
case(EINVAL):
case(ENOTSOCK):
case(EADDRNOTAVAIL):
case(EFAULT):
case(ELOOP):
case(ENAMETOOLONG):
case(ENOENT):
case(ENOMEM):
case(ENOTDIR):
case(EROFS): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
#endif
break;
}
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleBindError: Unknown error"
<< std::endl;
#endif
break;
}
}
void TmTcUnixUdpBridge::handleSendError() {
switch(errno) {
default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleSendError: "
<< strerror(errno) << std::endl;
#else
sif::printError("TmTcUnixBridge::handleSendError: %s\n",
strerror(errno));
#endif
}
}
}
void TmTcUnixUdpBridge::setClientAddressToAny(bool ipAddrAnySet){
this->ipAddrAnySet = ipAddrAnySet;
}

View File

@ -1,51 +0,0 @@
#ifndef FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#define FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#include "../../tmtcservices/AcceptsTelecommandsIF.h"
#include "../../tmtcservices/TmTcBridge.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
class TmTcUnixUdpBridge: public TmTcBridge {
friend class TcUnixUdpPollingTask;
public:
// The ports chosen here should not be used by any other process.
// List of used ports on Linux: /etc/services
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
virtual~ TmTcUnixUdpBridge();
void checkAndSetClientAddress(sockaddr_in& clientAddress);
void setClientAddressToAny(bool ipAddrAnySet);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
int serverSocket = 0;
const int serverSocketOptions = 0;
struct sockaddr_in clientAddress;
socklen_t clientAddressLen = 0;
struct sockaddr_in serverAddress;
socklen_t serverAddressLen = 0;
bool ipAddrAnySet = false;
//! Access to the client address is mutex protected as it is set
//! by another task.
MutexIF* mutex;
void handleSocketError();
void handleBindError();
void handleSendError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */

109
osal/linux/tcpipHelpers.cpp Normal file
View File

@ -0,0 +1,109 @@
#include "../common/tcpipHelpers.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../tasks/TaskFactory.h"
#include <errno.h>
#include <string>
void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration) {
int errCode = errno;
std::string protocolString;
std::string errorSrcString;
determineErrorStrings(protocol, errorSrc, protocolString, errorSrcString);
std::string infoString;
switch(errCode) {
case(EACCES): {
infoString = "EACCES";
break;
}
case(EINVAL): {
infoString = "EINVAL";
break;
}
case(EAGAIN): {
infoString = "EAGAIN";
break;
}
case(EMFILE): {
infoString = "EMFILE";
break;
}
case(ENFILE): {
infoString = "ENFILE";
break;
}
case(EAFNOSUPPORT): {
infoString = "EAFNOSUPPORT";
break;
}
case(ENOBUFS): {
infoString = "ENOBUFS";
break;
}
case(ENOMEM): {
infoString = "ENOMEM";
break;
}
case(EPROTONOSUPPORT): {
infoString = "EPROTONOSUPPORT";
break;
}
case(EADDRINUSE): {
infoString = "EADDRINUSE";
break;
}
case(EBADF): {
infoString = "EBADF";
break;
}
case(ENOTSOCK): {
infoString = "ENOTSOCK";
break;
}
case(EADDRNOTAVAIL): {
infoString = "EADDRNOTAVAIL";
break;
}
case(EFAULT): {
infoString = "EFAULT";
break;
}
case(ELOOP): {
infoString = "ELOOP";
break;
}
case(ENAMETOOLONG): {
infoString = "ENAMETOOLONG";
break;
}
case(ENOENT): {
infoString = "ENOENT";
break;
}
case(ENOTDIR): {
infoString = "ENOTDIR";
break;
}
case(EROFS): {
infoString = "EROFS";
break;
}
default: {
infoString = "Error code: " + std::to_string(errCode);
}
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
" | " << infoString << std::endl;
#else
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString.c_str(),
errorSrcString.c_str(), infoString.c_str());
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
if(sleepDuration > 0) {
TaskFactory::instance()->delayTask(sleepDuration);
}
}

View File

@ -1,7 +1,7 @@
#include "RtemsBasic.h" #include "RtemsBasic.h"
#include "../../timemanager/Clock.h" #include "../../timemanager/Clock.h"
#include "../../ipc/MutexHelper.h" #include "../../ipc/MutexGuard.h"
#include <rtems/score/todimpl.h> #include <rtems/score/todimpl.h>
#include <rtems/rtems/clockimpl.h> #include <rtems/rtems/clockimpl.h>
@ -183,7 +183,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
MutexHelper helper(timeMutex); MutexGuard helper(timeMutex);
leapSeconds = leapSeconds_; leapSeconds = leapSeconds_;
@ -196,7 +196,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex==nullptr){ if(timeMutex==nullptr){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
MutexHelper helper(timeMutex); MutexGuard helper(timeMutex);
*leapSeconds_ = leapSeconds; *leapSeconds_ = leapSeconds;

View File

@ -61,7 +61,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
} else { } else {
//No message was received. Keep lastPartner anyway, I might send something later. //No message was received. Keep lastPartner anyway, I might send something later.
//But still, delete packet content. //But still, delete packet content.
memset(message->getData(), 0, message->getMaximumMessageSize()); memset(message->getData(), 0, message->getMaximumDataSize());
} }
return convertReturnCode(status); return convertReturnCode(status);
} }

View File

@ -1,11 +1,4 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE tcpipHelpers.cpp
TcWinUdpPollingTask.cpp winTaskHelpers.cpp
TmTcWinUdpBridge.cpp
) )
target_link_libraries(${LIB_FSFW_NAME}
PRIVATE
wsock32
ws2_32
)

View File

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

View File

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

View File

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

View File

@ -0,0 +1,63 @@
#include "../common/tcpipHelpers.h"
#include <FSFWConfig.h>
#include "../../tasks/TaskFactory.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <winsock2.h>
#include <string>
void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration) {
#if FSFW_VERBOSE_LEVEL >= 1
int errCode = WSAGetLastError();
std::string protocolString;
std::string errorSrcString;
determineErrorStrings(protocol, errorSrc, protocolString, errorSrcString);
std::string infoString;
switch(errCode) {
case(WSANOTINITIALISED): {
infoString = "WSANOTINITIALISED";
break;
}
case(WSAEADDRINUSE): {
infoString = "WSAEADDRINUSE";
break;
}
case(WSAEFAULT): {
infoString = "WSAEFAULT";
break;
}
case(WSAEADDRNOTAVAIL): {
infoString = "WSAEADDRNOTAVAIL";
break;
}
case(WSAEINVAL): {
infoString = "WSAEINVAL";
break;
}
default: {
/*
https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
*/
infoString = "Error code: " + std::to_string(errCode);
break;
}
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
" | " << infoString << std::endl;
#else
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString,
errorSrcString, infoString);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
if(sleepDuration > 0) {
TaskFactory::instance()->delayTask(sleepDuration);
}
}

View File

@ -0,0 +1,107 @@
#include <fsfw/osal/windows/winTaskHelpers.h>
#include <mutex>
TaskPriority tasks::makeWinPriority(PriorityClass prioClass, PriorityNumber prioNumber) {
return (static_cast<uint16_t>(prioClass) << 16) | static_cast<uint16_t> (prioNumber);
}
void tasks::getWinPriorityParameters(TaskPriority priority,
DWORD& priorityClass, int& priorityNumber) {
PriorityClass classInternal = static_cast<PriorityClass>(priority >> 16 & 0xff);
PriorityNumber numberInternal = static_cast<PriorityNumber>(priority & 0xff);
switch(classInternal) {
case(CLASS_IDLE): {
priorityClass = IDLE_PRIORITY_CLASS;
break;
}
case(CLASS_BELOW_NORMAL): {
priorityClass = BELOW_NORMAL_PRIORITY_CLASS;
break;
}
case(CLASS_NORMAL): {
priorityClass = NORMAL_PRIORITY_CLASS;
break;
}
case(CLASS_ABOVE_NORMAL): {
priorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
break;
}
case(CLASS_HIGH): {
priorityClass = HIGH_PRIORITY_CLASS;
break;
}
case(CLASS_REALTIME): {
priorityClass = REALTIME_PRIORITY_CLASS;
break;
}
default: {
priorityClass = NORMAL_PRIORITY_CLASS;
}
}
switch(numberInternal) {
case(IDLE): {
priorityNumber = THREAD_PRIORITY_IDLE;
break;
}
case(LOWEST): {
priorityNumber = THREAD_PRIORITY_LOWEST;
break;
}
case(BELOW_NORMAL): {
priorityNumber = THREAD_PRIORITY_BELOW_NORMAL;
break;
}
case(NORMAL): {
priorityNumber = THREAD_PRIORITY_NORMAL;
break;
}
case(ABOVE_NORMAL): {
priorityNumber = THREAD_PRIORITY_ABOVE_NORMAL;
break;
}
case(HIGHEST): {
priorityNumber = THREAD_PRIORITY_HIGHEST;
break;
}
case(CRITICAL): {
priorityNumber = THREAD_PRIORITY_TIME_CRITICAL;
break;
}
default: {
priorityNumber = THREAD_PRIORITY_NORMAL;
}
}
}
ReturnValue_t tasks::setTaskPriority(HANDLE nativeHandle, TaskPriority priority) {
/* List of possible priority classes:
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setpriorityclass
And respective thread priority numbers:
https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
*/
DWORD dwPriorityClass = 0;
int nPriorityNumber = 0;
tasks::getWinPriorityParameters(priority, dwPriorityClass, nPriorityNumber);
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(nativeHandle),
dwPriorityClass);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(nativeHandle),
nPriorityNumber);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,37 @@
#include "../../tasks/TaskFactory.h"
#include <thread>
#include <map>
#ifdef _WIN32
namespace tasks {
enum PriorityClass: uint16_t {
CLASS_IDLE,
CLASS_BELOW_NORMAL,
CLASS_NORMAL,
CLASS_ABOVE_NORMAL,
CLASS_HIGH,
CLASS_REALTIME
};
enum PriorityNumber: uint16_t {
IDLE,
LOWEST,
BELOW_NORMAL,
NORMAL,
ABOVE_NORMAL,
HIGHEST,
CRITICAL
};
TaskPriority makeWinPriority(PriorityClass prioClass = PriorityClass::CLASS_NORMAL,
PriorityNumber prioNumber = PriorityNumber::NORMAL);
void getWinPriorityParameters(TaskPriority priority, DWORD& priorityClass,
int& priorityNumber);
ReturnValue_t setTaskPriority(HANDLE nativeHandle, TaskPriority priority);
}
#endif

View File

@ -1,6 +1,7 @@
#include "PowerComponent.h" #include "PowerComponent.h"
#include "../serialize/SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF), PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF),
doIHaveTwoSwitches(false) { doIHaveTwoSwitches(false) {
} }
@ -8,23 +9,23 @@ PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF),
PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min, PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min,
float max, uint8_t switchId1, bool twoSwitches, uint8_t switchId2) : float max, uint8_t switchId1, bool twoSwitches, uint8_t switchId2) :
deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2), deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2),
doIHaveTwoSwitches(twoSwitches), min(min), max(max), doIHaveTwoSwitches(twoSwitches), minPower(min), maxPower(max),
moduleId(moduleId) { moduleId(moduleId) {
} }
ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size, ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const { size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(&min, buffer, ReturnValue_t result = SerializeAdapter::serialize(&minPower, buffer,
size, maxSize, streamEndianness); size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return SerializeAdapter::serialize(&max, buffer, size, maxSize, return SerializeAdapter::serialize(&maxPower, buffer, size, maxSize,
streamEndianness); streamEndianness);
} }
size_t PowerComponent::getSerializedSize() const { size_t PowerComponent::getSerializedSize() const {
return sizeof(min) + sizeof(max); return sizeof(minPower) + sizeof(maxPower);
} }
object_id_t PowerComponent::getDeviceObjectId() { object_id_t PowerComponent::getDeviceObjectId() {
@ -44,21 +45,21 @@ bool PowerComponent::hasTwoSwitches() {
} }
float PowerComponent::getMin() { float PowerComponent::getMin() {
return min; return minPower;
} }
float PowerComponent::getMax() { float PowerComponent::getMax() {
return max; return maxPower;
} }
ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, size_t* size, ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) { Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::deSerialize(&min, buffer, ReturnValue_t result = SerializeAdapter::deSerialize(&minPower, buffer,
size, streamEndianness); size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return SerializeAdapter::deSerialize(&max, buffer, size, streamEndianness); return SerializeAdapter::deSerialize(&maxPower, buffer, size, streamEndianness);
} }
ReturnValue_t PowerComponent::getParameter(uint8_t domainId, uint8_t uniqueId, ReturnValue_t PowerComponent::getParameter(uint8_t domainId, uint8_t uniqueId,
@ -69,10 +70,10 @@ ReturnValue_t PowerComponent::getParameter(uint8_t domainId, uint8_t uniqueId,
} }
switch (uniqueId) { switch (uniqueId) {
case 0: case 0:
parameterWrapper->set<>(min); parameterWrapper->set<>(minPower);
break; break;
case 1: case 1:
parameterWrapper->set<>(max); parameterWrapper->set<>(maxPower);
break; break;
default: default:
return INVALID_IDENTIFIER_ID; return INVALID_IDENTIFIER_ID;

View File

@ -9,7 +9,7 @@
class PowerComponent: public PowerComponentIF { class PowerComponent: public PowerComponentIF {
public: public:
PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, PowerComponent(object_id_t setId, uint8_t moduleId, float minPower, float maxPower,
uint8_t switchId1, bool twoSwitches = false, uint8_t switchId1, bool twoSwitches = false,
uint8_t switchId2 = 0xFF); uint8_t switchId2 = 0xFF);
@ -41,8 +41,8 @@ private:
const bool doIHaveTwoSwitches; const bool doIHaveTwoSwitches;
float min = 0.0; float minPower = 0.0;
float max = 0.0; float maxPower = 0.0;
uint8_t moduleId = 0; uint8_t moduleId = 0;

View File

@ -61,8 +61,7 @@ ReturnValue_t CService200ModeCommanding::prepareCommand(
return result; return result;
} }
ModeMessage::setModeMessage(dynamic_cast<CommandMessage*>(message), ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(),
ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(),
modeCommandPacket.getSubmode()); modeCommandPacket.getSubmode());
return result; return result;
} }

View File

@ -15,7 +15,9 @@ Service1TelecommandVerification::Service1TelecommandVerification(
tmQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); tmQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
} }
Service1TelecommandVerification::~Service1TelecommandVerification() {} Service1TelecommandVerification::~Service1TelecommandVerification() {
QueueFactory::instance()->deleteMessageQueue(tmQueue);
}
MessageQueueId_t Service1TelecommandVerification::getVerificationQueue(){ MessageQueueId_t Service1TelecommandVerification::getVerificationQueue(){
return tmQueue->getId(); return tmQueue->getId();

View File

@ -75,9 +75,8 @@ ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue
#else #else
sif::printError("Service20ParameterManagement::checkInterfaceAndAcquire" sif::printError("Service20ParameterManagement::checkInterfaceAndAcquire"
"MessageQueue: Can't access object\n"); "MessageQueue: Can't access object\n");
sif::printError("Object ID: 0x%08x\n", objectId); sif::printError("Object ID: 0x%08x\n", *objectId);
sif::printError("Make sure it implements " sif::printError("Make sure it implements ReceivesParameterMessagesIF!\n");
"ReceivesParameterMessagesIF!\n");
#endif #endif
return CommandingServiceBase::INVALID_OBJECT; return CommandingServiceBase::INVALID_OBJECT;

View File

@ -159,7 +159,7 @@ ReturnValue_t Service3Housekeeping::prepareCollectionIntervalModificationCommand
CommandMessage *command, object_id_t objectId, bool isDiagnostics, CommandMessage *command, object_id_t objectId, bool isDiagnostics,
const uint8_t *tcData, size_t tcDataLen) { const uint8_t *tcData, size_t tcDataLen) {
if(tcDataLen < sizeof(sid_t) + sizeof(float)) { if(tcDataLen < sizeof(sid_t) + sizeof(float)) {
// SID plus the size of the new collection intervL. /* SID plus the size of the new collection interval. */
return CommandingServiceBase::INVALID_TC; return CommandingServiceBase::INVALID_TC;
} }

View File

@ -15,7 +15,9 @@ Service5EventReporting::Service5EventReporting(object_id_t objectId,
eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
} }
Service5EventReporting::~Service5EventReporting(){} Service5EventReporting::~Service5EventReporting() {
QueueFactory::instance()->deleteMessageQueue(eventQueue);
}
ReturnValue_t Service5EventReporting::performService() { ReturnValue_t Service5EventReporting::performService() {
EventMessage message; EventMessage message;

View File

@ -53,12 +53,14 @@ ReturnValue_t Service8FunctionManagement::checkInterfaceAndAcquireMessageQueue(
ReturnValue_t Service8FunctionManagement::prepareCommand( ReturnValue_t Service8FunctionManagement::prepareCommand(
CommandMessage* message, uint8_t subservice, const uint8_t* tcData, CommandMessage* message, uint8_t subservice, const uint8_t* tcData,
size_t tcDataLen, uint32_t* state, object_id_t objectId) { size_t tcDataLen, uint32_t* state, object_id_t objectId) {
return prepareDirectCommand(dynamic_cast<CommandMessage*>(message), return prepareDirectCommand(message, tcData, tcDataLen);
tcData, tcDataLen);
} }
ReturnValue_t Service8FunctionManagement::prepareDirectCommand( ReturnValue_t Service8FunctionManagement::prepareDirectCommand(
CommandMessage *message, const uint8_t *tcData, size_t tcDataLen) { CommandMessage *message, const uint8_t *tcData, size_t tcDataLen) {
if(message == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
if(tcDataLen < sizeof(object_id_t) + sizeof(ActionId_t)) { if(tcDataLen < sizeof(object_id_t) + sizeof(ActionId_t)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Service8FunctionManagement::prepareDirectCommand:" sif::debug << "Service8FunctionManagement::prepareDirectCommand:"

View File

@ -43,8 +43,8 @@ public:
private: private:
DirectCommand(const DirectCommand &command); DirectCommand(const DirectCommand &command);
object_id_t objectId; object_id_t objectId = 0;
ActionId_t actionId; ActionId_t actionId = 0;
uint32_t parametersSize; //!< [EXPORT] : [IGNORE] uint32_t parametersSize; //!< [EXPORT] : [IGNORE]
const uint8_t * parameterBuffer; //!< [EXPORT] : [MAXSIZE] 65535 Bytes const uint8_t * parameterBuffer; //!< [EXPORT] : [MAXSIZE] 65535 Bytes

View File

@ -25,7 +25,7 @@ public:
} }
SerializeElement() : SerializeElement() :
LinkedElement<SerializeIF>(this) { LinkedElement<SerializeIF>(this), entry() {
} }
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,

View File

@ -15,7 +15,7 @@ PoolManager::~PoolManager(void) {
ReturnValue_t PoolManager::reserveSpace(const size_t size, ReturnValue_t PoolManager::reserveSpace(const size_t size,
store_address_t* address, bool ignoreFault) { store_address_t* address, bool ignoreFault) {
MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING,
mutexTimeoutMs); mutexTimeoutMs);
ReturnValue_t status = LocalPool::reserveSpace(size, ReturnValue_t status = LocalPool::reserveSpace(size,
address,ignoreFault); address,ignoreFault);
@ -32,7 +32,7 @@ ReturnValue_t PoolManager::deleteData(
". id is "<< storeId.packetIndex << std::endl; ". id is "<< storeId.packetIndex << std::endl;
#endif #endif
#endif #endif
MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING,
mutexTimeoutMs); mutexTimeoutMs);
return LocalPool::deleteData(storeId); return LocalPool::deleteData(storeId);
} }
@ -40,7 +40,7 @@ ReturnValue_t PoolManager::deleteData(
ReturnValue_t PoolManager::deleteData(uint8_t* buffer, ReturnValue_t PoolManager::deleteData(uint8_t* buffer,
size_t size, store_address_t* storeId) { size_t size, store_address_t* storeId) {
MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20);
ReturnValue_t status = LocalPool::deleteData(buffer, ReturnValue_t status = LocalPool::deleteData(buffer,
size, storeId); size, storeId);
return status; return status;

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