diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b0917fd2..8ba6a187e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,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) # Options to exclude parts of the FSFW from compilation. option(FSFW_USE_RMAP "Compile with RMAP" ON) @@ -26,15 +34,22 @@ if(NOT OS_FSFW) endif() +set(FSFW_OSAL_DEFINITION FSFW_HOST) + if(${OS_FSFW} STREQUAL host) set(OS_FSFW_NAME "Host") elseif(${OS_FSFW} STREQUAL linux) set(OS_FSFW_NAME "Linux") + set(FSFW_OSAL_DEFINITION FSFW_LINUX) elseif(${OS_FSFW} STREQUAL 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) set(OS_FSFW_NAME "RTEMS") + set(FSFW_OSAL_DEFINITION FSFW_RTEMS) else() message(WARNING "Invalid operating system for FSFW specified! Setting to host.." @@ -43,6 +58,14 @@ else() set(OS_FSFW "host") 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.") add_subdirectory(action) @@ -88,6 +111,7 @@ add_subdirectory(timemanager) add_subdirectory(tmstorage) add_subdirectory(tmtcpacket) add_subdirectory(tmtcservices) +add_subdirectory(unittest) # 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. @@ -107,6 +131,21 @@ else() ) 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(NOT DEFINED FSFW_WARNING_FLAGS) set(FSFW_WARNING_FLAGS @@ -117,7 +156,20 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") -Wno-psabi ) 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) list(APPEND WARNING_FLAGS "-Wshadow=local") endif() @@ -132,6 +184,7 @@ endif() target_include_directories(${LIB_FSFW_NAME} INTERFACE ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE} + ${FSFW_ADD_INC_PATHS_ABS} ) # 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 ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE} + ${FSFW_ADD_INC_PATHS_ABS} ) target_compile_options(${LIB_FSFW_NAME} PRIVATE ${FSFW_WARNING_FLAGS} ${COMPILER_FLAGS} ) + +target_link_libraries(${LIB_FSFW_NAME} PRIVATE + ${FSFW_ADDITIONAL_LINK_LIBS} +) \ No newline at end of file diff --git a/FSFWVersion.h b/FSFWVersion.h index 11a608919..df2d49a51 100644 --- a/FSFWVersion.h +++ b/FSFWVersion.h @@ -3,9 +3,9 @@ const char* const FSFW_VERSION_NAME = "ASTP"; -#define FSFW_VERSION 0 -#define FSFW_SUBVERSION 0 -#define FSFW_REVISION 1 +#define FSFW_VERSION 1 +#define FSFW_SUBVERSION 0 +#define FSFW_REVISION 0 diff --git a/action/ActionHelper.cpp b/action/ActionHelper.cpp index 4b64a40ca..b2374ed69 100644 --- a/action/ActionHelper.cpp +++ b/action/ActionHelper.cpp @@ -147,11 +147,6 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, return result; } - if (result != HasReturnvaluesIF::RETURN_OK) { - ipcStore->deleteData(storeAddress); - return result; - } - /* We don't need to report the objectId, as we receive REQUESTED data before the completion success message. True aperiodic replies need to be reported with another dedicated message. */ ActionMessage::setDataReply(&reply, replyId, storeAddress); diff --git a/container/FixedArrayList.h b/container/FixedArrayList.h index 89b76388a..7af636b67 100644 --- a/container/FixedArrayList.h +++ b/container/FixedArrayList.h @@ -8,7 +8,9 @@ */ template class FixedArrayList: public ArrayList { - 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: T data[MAX_SIZE]; public: diff --git a/container/SharedRingBuffer.cpp b/container/SharedRingBuffer.cpp index 1681325d0..fe36341dd 100644 --- a/container/SharedRingBuffer.cpp +++ b/container/SharedRingBuffer.cpp @@ -1,6 +1,6 @@ #include "SharedRingBuffer.h" #include "../ipc/MutexFactory.h" -#include "../ipc/MutexHelper.h" +#include "../ipc/MutexGuard.h" SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size, bool overwriteOld, size_t maxExcessBytes): @@ -17,6 +17,9 @@ SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer, mutex = MutexFactory::instance()->createMutex(); } +SharedRingBuffer::~SharedRingBuffer() { + MutexFactory::instance()->deleteMutex(mutex); +} void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) { this->fifoDepth = fifoDepth; diff --git a/container/SharedRingBuffer.h b/container/SharedRingBuffer.h index 43ab6e8fe..9d6ea56c2 100644 --- a/container/SharedRingBuffer.h +++ b/container/SharedRingBuffer.h @@ -26,6 +26,18 @@ public: */ SharedRingBuffer(object_id_t objectId, const size_t size, 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 @@ -37,16 +49,7 @@ public: */ 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 @@ -66,7 +69,7 @@ public: /** * 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 */ MutexIF* getMutexHandle() const; diff --git a/controller/ExtendedControllerBase.cpp b/controller/ExtendedControllerBase.cpp index 95ba012eb..b5b8c6601 100644 --- a/controller/ExtendedControllerBase.cpp +++ b/controller/ExtendedControllerBase.cpp @@ -17,14 +17,6 @@ ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId, 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 { return SystemObject::getObjectId(); } @@ -107,14 +99,6 @@ MessageQueueId_t ExtendedControllerBase::getCommandQueue() const { 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() { return &poolManager; } diff --git a/controller/ExtendedControllerBase.h b/controller/ExtendedControllerBase.h index f069819bc..d5d43933b 100644 --- a/controller/ExtendedControllerBase.h +++ b/controller/ExtendedControllerBase.h @@ -61,11 +61,11 @@ protected: /* HasLocalDatapoolIF overrides */ virtual LocalDataPoolManager* getHkManagerHandle() 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 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; }; diff --git a/datapool/HkSwitchHelper.cpp b/datapool/HkSwitchHelper.cpp index 1a2a25eb9..21e37f59d 100644 --- a/datapool/HkSwitchHelper.cpp +++ b/datapool/HkSwitchHelper.cpp @@ -7,7 +7,7 @@ HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) : } HkSwitchHelper::~HkSwitchHelper() { - // TODO Auto-generated destructor stub + QueueFactory::instance()->deleteMessageQueue(actionQueue); } ReturnValue_t HkSwitchHelper::initialize() { diff --git a/datapool/PoolDataSetBase.cpp b/datapool/PoolDataSetBase.cpp index bdca22c3d..1bd586986 100644 --- a/datapool/PoolDataSetBase.cpp +++ b/datapool/PoolDataSetBase.cpp @@ -8,13 +8,16 @@ PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray, const size_t maxFillCount): registeredVariables(registeredVariablesArray), - maxFillCount(maxFillCount) { -} + maxFillCount(maxFillCount) {} PoolDataSetBase::~PoolDataSetBase() {} ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF *variable) { + if(registeredVariables == nullptr) { + /* Underlying container invalid */ + return HasReturnvaluesIF::RETURN_FAILED; + } if (state != States::STATE_SET_UNINITIALISED) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl; @@ -61,11 +64,11 @@ ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType, } else { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "DataSet::read(): Call made in wrong position. Don't forget to commit" - " member datasets!" << std::endl; + sif::warning << "PoolDataSetBase::read: Call made in wrong position. Don't forget to " + "commit member datasets!" << std::endl; #else - sif::printError("DataSet::read(): Call made in wrong position. Don't forget to commit" - " member datasets!\n"); + sif::printWarning("PoolDataSetBase::read: Call made in wrong position. Don't forget to " + "commit member datasets!\n"); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ result = SET_WAS_ALREADY_READ; } diff --git a/datapool/PoolDataSetIF.h b/datapool/PoolDataSetIF.h index 9151f2f8e..f905cc4d7 100644 --- a/datapool/PoolDataSetIF.h +++ b/datapool/PoolDataSetIF.h @@ -9,8 +9,8 @@ * and unlock a data pool and read/commit semantics. */ class PoolDataSetIF: - public DataSetIF, - public ReadCommitIF { + virtual public DataSetIF, + virtual public ReadCommitIF { public: virtual~ PoolDataSetIF() {}; diff --git a/datapool/PoolEntry.cpp b/datapool/PoolEntry.cpp index a5867222b..6504e20c5 100644 --- a/datapool/PoolEntry.cpp +++ b/datapool/PoolEntry.cpp @@ -7,7 +7,7 @@ template PoolEntry::PoolEntry(std::initializer_list initValue, bool setValid ): - length(initValue.size()), valid(setValid) { + length(static_cast(initValue.size())), valid(setValid) { this->address = new T[this->length]; if(initValue.size() == 0) { std::memset(this->address, 0, this->getByteSize()); diff --git a/datapool/SharedDataSetIF.h b/datapool/SharedDataSetIF.h index b8d98794d..4d23f87f5 100644 --- a/datapool/SharedDataSetIF.h +++ b/datapool/SharedDataSetIF.h @@ -1,13 +1,15 @@ #ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ #define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ + #include "PoolDataSetIF.h" -class SharedDataSetIF: public PoolDataSetIF { +class SharedDataSetIF { public: virtual ~SharedDataSetIF() {}; 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; }; diff --git a/datapoollocal/HasLocalDataPoolIF.h b/datapoollocal/HasLocalDataPoolIF.h index d52c72b6c..74e372c9e 100644 --- a/datapoollocal/HasLocalDataPoolIF.h +++ b/datapoollocal/HasLocalDataPoolIF.h @@ -65,34 +65,45 @@ public: * usually be the period the pool owner performs its periodic operation. * @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 * notification is received. * @details HasLocalDataPoolIF * Can be overriden by the child class to handle changed datasets. - * @param sid - * @param storeId If a snapshot was requested, data will be located inside + * @param sid SID of the updated set + * @param storeId If a snapshot was requested, data will be located inside * 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, - store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { - return; + store_address_t storeId = storeId::INVALID_STORE_ADDRESS, + bool* clearMessage = nullptr) { + if(clearMessage != nullptr) { + *clearMessage = true; + } } /** * @brief This function will be called by the manager if an update * notification is received. * @details - * Can be overriden by the child class to handle changed pool IDs. - * @param sid - * @param storeId If a snapshot was requested, data will be located inside + * Can be overriden by the child class to handle changed pool variables. + * @param gpid GPID of the updated variable. + * @param storeId If a snapshot was requested, data will be located inside * 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, - store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { - return; + virtual void handleChangedPoolVariable(gp_id_t gpid, + store_address_t storeId = storeId::INVALID_STORE_ADDRESS, + bool* clearMessage = nullptr) { + if(clearMessage != nullptr) { + *clearMessage = true; + } } /** diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp index 72873d993..dbe68ff14 100644 --- a/datapoollocal/LocalDataPoolManager.cpp +++ b/datapoollocal/LocalDataPoolManager.cpp @@ -10,7 +10,7 @@ #include "../housekeeping/AcceptsHkPacketsIF.h" #include "../timemanager/CCSDSTime.h" #include "../ipc/MutexFactory.h" -#include "../ipc/MutexHelper.h" +#include "../ipc/MutexGuard.h" #include "../ipc/QueueFactory.h" #include @@ -38,7 +38,11 @@ LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQue hkQueue = queueToUse; } -LocalDataPoolManager::~LocalDataPoolManager() {} +LocalDataPoolManager::~LocalDataPoolManager() { + if(mutex != nullptr) { + MutexFactory::instance()->deleteMutex(mutex); + } +} ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { if(queueToUse == nullptr) { @@ -132,13 +136,16 @@ ReturnValue_t LocalDataPoolManager::performHkOperation() { ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver, ReturnValue_t& status) { 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; } LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, receiver.dataId.sid); + if(dataSet == nullptr) { + return DATASET_NOT_FOUND; + } if(dataSet->hasChanged()) { - // prepare and send update notification + /* Prepare and send update notification */ ReturnValue_t result = generateHousekeepingPacket( receiver.dataId.sid, dataSet, true); if(result != HasReturnvaluesIF::RETURN_OK) { @@ -328,7 +335,7 @@ void LocalDataPoolManager::handleChangeResetLogic( toReset->setChanged(false); } /* All recipients have been notified, reset the changed flag */ - if(changeInfo.currentUpdateCounter <= 1) { + else if(changeInfo.currentUpdateCounter <= 1) { toReset->setChanged(false); changeInfo.currentUpdateCounter = 0; } @@ -372,7 +379,7 @@ ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid, LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting); LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval, - owner->getPeriodicOperationFrequency(), isDiagnostics); + owner->getPeriodicOperationFrequency()); } hkReceivers.push_back(hkReceiver); @@ -398,7 +405,6 @@ ReturnValue_t LocalDataPoolManager::subscribeForUpdatePacket(sid_t sid, hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); - //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); if(dataSet != nullptr) { LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true); LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); @@ -516,11 +522,19 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( } 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): { - 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_PARAMETER_REPORT_COLLECTION_INTERVAL): { @@ -540,14 +554,15 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { LocalPoolDataSetBase* dataSet =HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); - //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { - return WRONG_HK_PACKET_TYPE; + result = WRONG_HK_PACKET_TYPE; + break; } else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { - return WRONG_HK_PACKET_TYPE; + result = WRONG_HK_PACKET_TYPE; + break; } return generateHousekeepingPacket(HousekeepingMessage::getSid(message), dataSet, true); @@ -566,14 +581,22 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { store_address_t 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; } case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { store_address_t storeId; gp_id_t globPoolId = HousekeepingMessage::getUpdateSnapshotVariableCommand(message, &storeId); - owner->handleChangedPoolVariable(globPoolId, storeId); + bool clearMessage = true; + owner->handleChangedPoolVariable(globPoolId, storeId, &clearMessage); + if(clearMessage) { + message->clear(); + } return HasReturnvaluesIF::RETURN_OK; } @@ -616,7 +639,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, LocalPoolDataSetBase* dataSet, bool forDownlink, MessageQueueId_t destination) { if(dataSet == nullptr) { - // Configuration error. + /* Configuration error. */ printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateHousekeepingPacket", DATASET_NOT_FOUND); @@ -632,7 +655,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, 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; if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); @@ -642,7 +665,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, } if(hkQueue == nullptr) { - // error, no queue available to send packet with. + /* Error, no queue available to send packet with. */ printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateHousekeepingPacket", QUEUE_OR_DESTINATION_INVALID); @@ -650,7 +673,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, } if(destination == MessageQueueIF::NO_QUEUE) { if(hkDestinationId == MessageQueueIF::NO_QUEUE) { - // error, all destinations invalid + /* Error, all destinations invalid */ printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateHousekeepingPacket", QUEUE_OR_DESTINATION_INVALID); @@ -729,6 +752,12 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool enable, bool isDiagnostics) { 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 (not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) { return WRONG_HK_PACKET_TYPE; @@ -746,6 +775,12 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float newCollectionInterval, bool isDiagnostics) { 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); if((targetIsDiagnostics and not isDiagnostics) or (not targetIsDiagnostics and isDiagnostics)) { @@ -756,7 +791,7 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); if(periodicHelper == nullptr) { - // config error + /* Configuration error, set might not have a corresponding pool manager */ return PERIODIC_HELPER_INVALID; } @@ -766,13 +801,11 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool isDiagnostics) { - // Get and check dataset first. - //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + /* Get and check dataset first. */ LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); if(dataSet == nullptr) { printWarningOrError(sif::OutputTypes::OUT_WARNING, - "performPeriodicHkGeneration", - DATASET_NOT_FOUND); + "performPeriodicHkGeneration", DATASET_NOT_FOUND); return DATASET_NOT_FOUND; } @@ -831,6 +864,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, void LocalDataPoolManager::clearReceiversList() { /* Clear the vector completely and releases allocated memory. */ HkReceivers().swap(hkReceivers); + /* Also clear the reset helper if it exists */ + if(hkUpdateResetList != nullptr) { + HkUpdateResetList().swap(*hkUpdateResetList); + } } MutexIF* LocalDataPoolManager::getLocalPoolMutex() { @@ -843,6 +880,7 @@ object_id_t LocalDataPoolManager::getCreatorObjectId() const { void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType, const char* functionName, ReturnValue_t error, const char* errorPrint) { +#if FSFW_VERBOSE_LEVEL >= 1 if(errorPrint == nullptr) { if(error == DATASET_NOT_FOUND) { errorPrint = "Dataset not found"; @@ -871,33 +909,32 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType, errorPrint = "Unknown error"; } } + object_id_t objectId = 0xffffffff; + if(owner != nullptr) { + objectId = owner->getObjectId(); + } if(outputType == sif::OutputTypes::OUT_WARNING) { -#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalDataPoolManager::" << functionName - << ": Object ID 0x" << std::setw(8) << std::setfill('0') - << std::hex << owner->getObjectId() << " | " << errorPrint - << std::dec << std::setfill(' ') << std::endl; + sif::warning << "LocalDataPoolManager::" << functionName << ": Object ID 0x" << + std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint << + std::dec << std::setfill(' ') << std::endl; #else 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_VERBOSE_LEVEL >= 1 */ } else if(outputType == sif::OutputTypes::OUT_ERROR) { -#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalDataPoolManager::" << functionName - << ": Object ID 0x" << std::setw(8) << std::setfill('0') - << std::hex << owner->getObjectId() << " | " << errorPrint - << std::dec << std::setfill(' ') << std::endl; + sif::error << "LocalDataPoolManager::" << functionName << ": Object ID 0x" << + std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint << + std::dec << std::setfill(' ') << std::endl; #else 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_VERBOSE_LEVEL >= 1 */ } +#endif /* #if FSFW_VERBOSE_LEVEL >= 1 */ } LocalDataPoolManager* LocalDataPoolManager::getPoolManagerHandle() { diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h index ff6edb95d..2ec81f1cf 100644 --- a/datapoollocal/LocalDataPoolManager.h +++ b/datapoollocal/LocalDataPoolManager.h @@ -14,7 +14,7 @@ #include "../ipc/MutexIF.h" #include "../ipc/CommandMessage.h" #include "../ipc/MessageQueueIF.h" -#include "../ipc/MutexHelper.h" +#include "../ipc/MutexGuard.h" #include #include @@ -391,6 +391,10 @@ protected: template inline ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, PoolEntry **poolEntry) { + if(poolEntry == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + auto poolIter = localPoolMap.find(localPoolId); if (poolIter == localPoolMap.end()) { printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry", diff --git a/datapoollocal/LocalPoolDataSetBase.cpp b/datapoollocal/LocalPoolDataSetBase.cpp index e5ea15983..a72e9db11 100644 --- a/datapoollocal/LocalPoolDataSetBase.cpp +++ b/datapoollocal/LocalPoolDataSetBase.cpp @@ -44,7 +44,7 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, const size_t maxNumberOfVariables): - PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { + PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { HasLocalDataPoolIF* hkOwner = objectManager->get( sid.objectId); if(hkOwner != nullptr) { @@ -58,8 +58,7 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registere this->sid = sid; } -LocalPoolDataSetBase::LocalPoolDataSetBase( - PoolVariableIF **registeredVariablesArray, +LocalPoolDataSetBase::LocalPoolDataSetBase(PoolVariableIF **registeredVariablesArray, const size_t maxNumberOfVariables, bool protectEveryReadCommitCall): PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { this->setReadCommitProtectionBehaviour(protectEveryReadCommitCall); @@ -95,14 +94,23 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer size_t *size, size_t maxSize, SerializeIF::Endianness streamEndianness) const { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - uint8_t validityMaskSize = std::ceil(static_cast(fillCount)/8.0); - uint8_t validityMask[validityMaskSize] = {}; + const uint8_t validityMaskSize = std::ceil(static_cast(fillCount)/8.0); + 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 validityMask(validityMaskSize); + validityPtr = validityMask.data(); +#else + uint8_t validityMask[validityMaskSize] = {0}; + validityPtr = validityMask; +#endif uint8_t validBufferIndex = 0; uint8_t validBufferIndexBit = 0; for (uint16_t count = 0; count < fillCount; count++) { if(registeredVariables[count]->isValid()) { /* Set bit at correct position */ - bitutil::bitSet(validityMask + validBufferIndex, validBufferIndexBit); + bitutil::bitSet(validityPtr + validBufferIndex, validBufferIndexBit); } if(validBufferIndexBit == 7) { validBufferIndex ++; @@ -123,7 +131,7 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer return SerializeIF::BUFFER_TOO_SHORT; } // copy validity buffer to end - std::memcpy(*buffer, validityMask, validityMaskSize); + std::memcpy(*buffer, validityPtr, validityMaskSize); *size += validityMaskSize; return result; } @@ -262,11 +270,9 @@ bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; } -void LocalPoolDataSetBase::initializePeriodicHelper( - float collectionInterval, dur_millis_t minimumPeriodicInterval, - bool isDiagnostics, uint8_t nonDiagIntervalFactor) { - periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, - isDiagnostics, nonDiagIntervalFactor); +void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval, + dur_millis_t minimumPeriodicInterval, uint8_t nonDiagIntervalFactor) { + periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor); } void LocalPoolDataSetBase::setChanged(bool changed) { @@ -306,3 +312,12 @@ void LocalPoolDataSetBase::setAllVariablesReadOnly() { registeredVariables[idx]->setReadWriteMode(pool_rwm_t::VAR_READ); } } + +float LocalPoolDataSetBase::getCollectionInterval() const { + if(periodicHelper != nullptr) { + return periodicHelper->getCollectionIntervalInSeconds(); + } + else { + return 0.0; + } +} diff --git a/datapoollocal/LocalPoolDataSetBase.h b/datapoollocal/LocalPoolDataSetBase.h index 404509ae5..ab67dc3f9 100644 --- a/datapoollocal/LocalPoolDataSetBase.h +++ b/datapoollocal/LocalPoolDataSetBase.h @@ -166,6 +166,16 @@ public: 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: sid_t sid; //! This mutex is used if the data is created by one object only. @@ -180,11 +190,9 @@ protected: */ bool reportingEnabled = false; void setReportingEnabled(bool enabled); - bool getReportingEnabled() const; - void initializePeriodicHelper(float collectionInterval, - dur_millis_t minimumPeriodicInterval, - bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5); + void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval, + uint8_t nonDiagIntervalFactor = 5); /** * If the valid state of a dataset is always relevant to the whole diff --git a/datapoollocal/LocalPoolVector.tpp b/datapoollocal/LocalPoolVector.tpp index 5b2089b39..044b8fa72 100644 --- a/datapoollocal/LocalPoolVector.tpp +++ b/datapoollocal/LocalPoolVector.tpp @@ -25,7 +25,7 @@ inline LocalPoolVector::LocalPoolVector(gp_id_t globalPoolId, template inline ReturnValue_t LocalPoolVector::read( MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { - MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); + MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); return readWithoutLock(); } template @@ -64,7 +64,7 @@ inline ReturnValue_t LocalPoolVector::commit(bool valid, template inline ReturnValue_t LocalPoolVector::commit( MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { - MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); + MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); return commitWithoutLock(); } diff --git a/datapoollocal/SharedLocalDataSet.cpp b/datapoollocal/SharedLocalDataSet.cpp index dd1bdcc40..84c2d1c37 100644 --- a/datapoollocal/SharedLocalDataSet.cpp +++ b/datapoollocal/SharedLocalDataSet.cpp @@ -1,16 +1,37 @@ #include "SharedLocalDataSet.h" + SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId, sid_t sid, const size_t maxSize): SystemObject(objectId), - LocalPoolDataSetBase(sid, nullptr, maxSize) { + LocalPoolDataSetBase(sid, nullptr, maxSize), poolVarVector(maxSize) { this->setContainer(poolVarVector.data()); datasetLock = MutexFactory::instance()->createMutex(); } -ReturnValue_t SharedLocalDataSet::lockDataset(dur_millis_t mutexTimeout) { - return datasetLock->lockMutex(MutexIF::TimeoutType::WAITING, mutexTimeout); +SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId, + 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() { - return datasetLock->unlockMutex(); + if(datasetLock != nullptr) { + return datasetLock->unlockMutex(); + } + return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/datapoollocal/SharedLocalDataSet.h b/datapoollocal/SharedLocalDataSet.h index 83f2a72f1..8d12610a8 100644 --- a/datapoollocal/SharedLocalDataSet.h +++ b/datapoollocal/SharedLocalDataSet.h @@ -11,16 +11,22 @@ * multiple threads. It provides a lock in addition to all other functionalities provided * 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: public SystemObject, public LocalPoolDataSetBase, public SharedDataSetIF { public: - SharedLocalDataSet(object_id_t objectId, sid_t sid, + SharedLocalDataSet(object_id_t objectId, HasLocalDataPoolIF* owner, uint32_t setId, 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; private: diff --git a/datapoollocal/datapoollocal.h b/datapoollocal/datapoollocal.h new file mode 100644 index 000000000..c5c470788 --- /dev/null +++ b/datapoollocal/datapoollocal.h @@ -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_ */ diff --git a/datapoollocal/internal/LocalPoolDataSetAttorney.h b/datapoollocal/internal/LocalPoolDataSetAttorney.h index 7a34e9c8e..f81428cd1 100644 --- a/datapoollocal/internal/LocalPoolDataSetAttorney.h +++ b/datapoollocal/internal/LocalPoolDataSetAttorney.h @@ -14,9 +14,8 @@ private: } static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval, - uint32_t minimumPeriodicIntervalMs, - bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5) { - set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs, isDiagnostics, + uint32_t minimumPeriodicIntervalMs, uint8_t nonDiagIntervalFactor = 5) { + set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs, nonDiagIntervalFactor); } diff --git a/datapoollocal/localPoolDefinitions.h b/datapoollocal/localPoolDefinitions.h index af8ce7115..daab8b9c0 100644 --- a/datapoollocal/localPoolDefinitions.h +++ b/datapoollocal/localPoolDefinitions.h @@ -96,11 +96,11 @@ union gp_id_t { return raw == INVALID_GPID; } - bool operator==(const sid_t& other) const { + bool operator==(const gp_id_t& other) const { return raw == other.raw; } - bool operator!=(const sid_t& other) const { + bool operator!=(const gp_id_t& other) const { return not (raw == other.raw); } }; diff --git a/defaultcfg/fsfwconfig/FSFWConfig.h b/defaultcfg/fsfwconfig/FSFWConfig.h index ed86e6e1f..fe18a2f43 100644 --- a/defaultcfg/fsfwconfig/FSFWConfig.h +++ b/defaultcfg/fsfwconfig/FSFWConfig.h @@ -40,6 +40,13 @@ //! Specify whether a special mode store is used for Subsystem components. #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 { //! Default timestamp size. The default timestamp will be an eight byte CDC //! short timestamp. @@ -52,11 +59,12 @@ static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; //! Defines the FIFO depth of each commanding service base which //! also determines how many commands a CSB service can handle in one cycle -//! simulataneously. This will increase the required RAM for +//! simultaneously. This will increase the required RAM for //! each CSB service ! static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124; + } #endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 15eac11f4..531a0642b 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -1483,7 +1483,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) { errorPrint = "Initialization error"; } - if(errorCode == HasReturnvaluesIF::RETURN_FAILED) { + else if(errorCode == HasReturnvaluesIF::RETURN_FAILED) { if(errorType == sif::OutputTypes::OUT_WARNING) { errorPrint = "Generic Warning"; } @@ -1495,6 +1495,9 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, errorPrint = "Unknown error"; } } + if(functionName == nullptr) { + functionName = "unknown function"; + } if(errorType == sif::OutputTypes::OUT_WARNING) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -1504,7 +1507,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, << std::setfill(' ') << std::endl; #else sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", - this->getObjectId(), errorPrint); + functionName, this->getObjectId(), errorPrint); #endif } else if(errorType == sif::OutputTypes::OUT_ERROR) { @@ -1515,7 +1518,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, << std::setfill(' ') << std::endl; #else sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", - this->getObjectId(), errorPrint); + functionName, this->getObjectId(), errorPrint); #endif } diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index a19e2cbc0..d61b0407d 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -119,7 +119,7 @@ public: DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, lp_id_t thermalRequestPoolId = 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. * This will instruct the transition to MODE_ON immediately diff --git a/devicehandlers/HealthDevice.cpp b/devicehandlers/HealthDevice.cpp index 418ed2576..e23dd5b69 100644 --- a/devicehandlers/HealthDevice.cpp +++ b/devicehandlers/HealthDevice.cpp @@ -16,9 +16,9 @@ ReturnValue_t HealthDevice::performOperation(uint8_t opCode) { CommandMessage command; ReturnValue_t result = commandQueue->receiveMessage(&command); if (result == HasReturnvaluesIF::RETURN_OK) { - healthHelper.handleHealthCommand(&command); + result = healthHelper.handleHealthCommand(&command); } - return HasReturnvaluesIF::RETURN_OK; + return result; } ReturnValue_t HealthDevice::initialize() { diff --git a/events/EventMessage.cpp b/events/EventMessage.cpp index bbc41e100..548b4f0f3 100644 --- a/events/EventMessage.cpp +++ b/events/EventMessage.cpp @@ -109,6 +109,6 @@ bool EventMessage::isClearedEventMessage() { return getEvent() == INVALID_EVENT; } -size_t EventMessage::getMinimumMessageSize() { +size_t EventMessage::getMinimumMessageSize() const { return EVENT_MESSAGE_SIZE; } diff --git a/events/EventMessage.h b/events/EventMessage.h index 4d003bd7b..f2f5ffb50 100644 --- a/events/EventMessage.h +++ b/events/EventMessage.h @@ -45,7 +45,7 @@ public: protected: static const Event INVALID_EVENT = 0; - virtual size_t getMinimumMessageSize(); + virtual size_t getMinimumMessageSize() const override; }; diff --git a/globalfunctions/arrayprinter.cpp b/globalfunctions/arrayprinter.cpp index 7dc056b08..0423360b9 100644 --- a/globalfunctions/arrayprinter.cpp +++ b/globalfunctions/arrayprinter.cpp @@ -51,7 +51,7 @@ void arrayprinter::printHex(const uint8_t *data, size_t size, #else // General format: 0x01, 0x02, 0x03 so it is number of chars times 6 // plus line break plus small safety margin. - char printBuffer[(size + 1) * 7 + 1]; + char printBuffer[(size + 1) * 7 + 1] = {}; size_t currentPos = 0; for(size_t i = 0; i < size; i++) { // 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); +#endif /* FSFW_DISABLE_PRINTOUT == 0 */ #endif } @@ -92,7 +94,7 @@ void arrayprinter::printDec(const uint8_t *data, size_t size, #else // General format: 32, 243, -12 so it is number of chars times 5 // plus line break plus small safety margin. - char printBuffer[(size + 1) * 5 + 1]; + char printBuffer[(size + 1) * 5 + 1] = {}; size_t currentPos = 0; for(size_t i = 0; i < size; i++) { // 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); +#endif /* FSFW_DISABLE_PRINTOUT == 0 */ #endif } diff --git a/health/HealthTable.cpp b/health/HealthTable.cpp index 2b8b67127..3fed1deb1 100644 --- a/health/HealthTable.cpp +++ b/health/HealthTable.cpp @@ -1,5 +1,5 @@ #include "HealthTable.h" -#include "../ipc/MutexHelper.h" +#include "../ipc/MutexGuard.h" #include "../ipc/MutexFactory.h" #include "../serialize/SerializeAdapter.h" @@ -31,7 +31,7 @@ ReturnValue_t HealthTable::registerObject(object_id_t object, void HealthTable::setHealth(object_id_t object, HasHealthIF::HealthState newState) { - MutexHelper(mutex, timeoutType, mutexTimeoutMs); + MutexGuard(mutex, timeoutType, mutexTimeoutMs); HealthMap::iterator iter = healthMap.find(object); if (iter != healthMap.end()) { iter->second = newState; @@ -40,7 +40,7 @@ void HealthTable::setHealth(object_id_t object, HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) { HasHealthIF::HealthState state = HasHealthIF::HEALTHY; - MutexHelper(mutex, timeoutType, mutexTimeoutMs); + MutexGuard(mutex, timeoutType, mutexTimeoutMs); HealthMap::iterator iter = healthMap.find(object); if (iter != healthMap.end()) { state = iter->second; @@ -49,7 +49,7 @@ HasHealthIF::HealthState HealthTable::getHealth(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); if (iter != healthMap.end()) { return true; @@ -58,35 +58,51 @@ bool HealthTable::hasHealth(object_id_t object) { } size_t HealthTable::getPrintSize() { - MutexHelper(mutex, timeoutType, mutexTimeoutMs); + MutexGuard(mutex, timeoutType, mutexTimeoutMs); uint32_t size = healthMap.size() * sizeof(object_id_t) + sizeof(HasHealthIF::HealthState) + sizeof(uint16_t); return size; } void HealthTable::printAll(uint8_t* pointer, size_t maxSize) { - MutexHelper(mutex, timeoutType, mutexTimeoutMs); + MutexGuard(mutex, timeoutType, mutexTimeoutMs); size_t size = 0; uint16_t count = healthMap.size(); - SerializeAdapter::serialize(&count, + ReturnValue_t result = SerializeAdapter::serialize(&count, &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) { - SerializeAdapter::serialize(&health.first, + result = SerializeAdapter::serialize(&health.first, &pointer, &size, maxSize, SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK) { + return; + } uint8_t healthValue = health.second; - SerializeAdapter::serialize(&healthValue, &pointer, &size, + result = SerializeAdapter::serialize(&healthValue, &pointer, &size, maxSize, SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK) { + return; + } } } ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - MutexHelper(mutex, timeoutType, mutexTimeoutMs); + MutexGuard(mutex, timeoutType, mutexTimeoutMs); if (reset) { mapIterator = healthMap.begin(); } if (mapIterator == healthMap.end()) { - result = HasReturnvaluesIF::RETURN_FAILED; + return HasReturnvaluesIF::RETURN_FAILED; } *value = *mapIterator; mapIterator++; diff --git a/housekeeping/HousekeepingMessage.cpp b/housekeeping/HousekeepingMessage.cpp index d9803ef65..90ca73c8c 100644 --- a/housekeeping/HousekeepingMessage.cpp +++ b/housekeeping/HousekeepingMessage.cpp @@ -84,15 +84,21 @@ void HousekeepingMessage::setCollectionIntervalModificationCommand( else { 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); } sid_t HousekeepingMessage::getCollectionIntervalModificationCommand( const CommandMessage* command, float* newCollectionInterval) { + if(newCollectionInterval != nullptr) { - *newCollectionInterval = command->getParameter3(); + std::memcpy(newCollectionInterval, command->getData() + 2 * sizeof(uint32_t), + sizeof(*newCollectionInterval)); } return getSid(command); @@ -151,7 +157,8 @@ void HousekeepingMessage::clear(CommandMessage* message) { case(DIAGNOSTICS_REPORT): case(HK_DEFINITIONS_REPORT): case(DIAGNOSTICS_DEFINITION_REPORT): - case(UPDATE_SNAPSHOT_SET): { + case(UPDATE_SNAPSHOT_SET): + case(UPDATE_SNAPSHOT_VARIABLE): { store_address_t storeId; getHkDataReply(message, &storeId); StorageManagerIF *ipcStore = objectManager->get( diff --git a/housekeeping/HousekeepingSnapshot.h b/housekeeping/HousekeepingSnapshot.h index 50afd4af5..45b40d379 100644 --- a/housekeeping/HousekeepingSnapshot.h +++ b/housekeeping/HousekeepingSnapshot.h @@ -11,7 +11,8 @@ * @brief This helper class will be used to serialize and deserialize update housekeeping packets * into the store. */ -class HousekeepingSnapshot: public SerializeIF { +class HousekeepingSnapshot: + public SerializeIF { public: /** @@ -36,6 +37,17 @@ public: timeStamp(timeStamp), timeStampSize(timeStampSize), updateData(dataSetPtr) {}; + /** + * Update packet constructor for pool variables. + * @param timeStamp + * @param timeStampSize + * @param dataSetPtr + */ + HousekeepingSnapshot(CCSDSTime::CDS_short* cdsShort, LocalPoolObjectBase* dataSetPtr): + timeStamp(reinterpret_cast(cdsShort)), + timeStampSize(sizeof(CCSDSTime::CDS_short)), updateData(dataSetPtr) {}; + + /** * Update packet constructor for pool variables. * @param timeStamp @@ -47,8 +59,8 @@ public: timeStamp(timeStamp), timeStampSize(timeStampSize), updateData(dataSetPtr) {}; - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const { + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const { if(timeStamp != nullptr) { /* Endianness will always be MACHINE, so we can simply use memcpy here. */ diff --git a/housekeeping/PeriodicHousekeepingHelper.cpp b/housekeeping/PeriodicHousekeepingHelper.cpp index 365f00048..892eb354a 100644 --- a/housekeeping/PeriodicHousekeepingHelper.cpp +++ b/housekeeping/PeriodicHousekeepingHelper.cpp @@ -4,46 +4,87 @@ #include PeriodicHousekeepingHelper::PeriodicHousekeepingHelper( - LocalPoolDataSetBase* owner): owner(owner) {} - + LocalPoolDataSetBase* owner): owner(owner) {} void PeriodicHousekeepingHelper::initialize(float collectionInterval, - dur_millis_t minimumPeriodicInterval, bool isDiagnostics, - uint8_t nonDiagIntervalFactor) { - this->minimumPeriodicInterval = minimumPeriodicInterval; - if(not isDiagnostics) { - this->minimumPeriodicInterval = this->minimumPeriodicInterval * - nonDiagIntervalFactor; - } - collectionIntervalTicks = intervalSecondsToInterval(collectionInterval); + dur_millis_t minimumPeriodicInterval, uint8_t nonDiagIntervalFactor) { + this->minimumPeriodicInterval = minimumPeriodicInterval; + this->nonDiagIntervalFactor = nonDiagIntervalFactor; + collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval); + /* This will cause a checkOpNecessary call to be true immediately. I think it's okay + if a HK packet is generated immediately instead of waiting one generation cycle. */ + internalTickCounter = collectionIntervalTicks; } -float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() { - return intervalToIntervalSeconds(collectionIntervalTicks); +float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() const { + return intervalTicksToSeconds(collectionIntervalTicks); } bool PeriodicHousekeepingHelper::checkOpNecessary() { - if(internalTickCounter >= collectionIntervalTicks) { - internalTickCounter = 1; - return true; - } - internalTickCounter++; - return false; + if(internalTickCounter >= collectionIntervalTicks) { + internalTickCounter = 1; + return true; + } + internalTickCounter++; + return false; } -uint32_t PeriodicHousekeepingHelper::intervalSecondsToInterval( - float collectionIntervalSeconds) { - return std::ceil(collectionIntervalSeconds * 1000 - / minimumPeriodicInterval); +uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks( + float collectionIntervalSeconds) { + if(owner == nullptr) { + 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(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( - uint32_t collectionInterval) { - return static_cast(collectionInterval * - minimumPeriodicInterval); +float PeriodicHousekeepingHelper::intervalTicksToSeconds( + uint32_t collectionInterval) const { + /* Number of ticks times the minimum interval is in milliseconds, so we divide by 1000 to get + the value in seconds */ + return static_cast(collectionInterval * minimumPeriodicInterval / 1000.0); } void PeriodicHousekeepingHelper::changeCollectionInterval( - float newIntervalSeconds) { - collectionIntervalTicks = intervalSecondsToInterval(newIntervalSeconds); + float newIntervalSeconds) { + collectionIntervalTicks = intervalSecondsToIntervalTicks(newIntervalSeconds); } + diff --git a/housekeeping/PeriodicHousekeepingHelper.h b/housekeeping/PeriodicHousekeepingHelper.h index d96eae1d4..3256fbffa 100644 --- a/housekeeping/PeriodicHousekeepingHelper.h +++ b/housekeeping/PeriodicHousekeepingHelper.h @@ -10,18 +10,19 @@ class PeriodicHousekeepingHelper { public: PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner); - void initialize(float collectionInterval, - dur_millis_t minimumPeriodicInterval, bool isDiagnostics, - uint8_t nonDiagIntervalFactor); + void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval, + uint8_t nonDiagIntervalFactor); void changeCollectionInterval(float newInterval); - float getCollectionIntervalInSeconds(); + float getCollectionIntervalInSeconds() const; bool checkOpNecessary(); + private: LocalPoolDataSetBase* owner = nullptr; + uint8_t nonDiagIntervalFactor = 0; - uint32_t intervalSecondsToInterval(float collectionIntervalSeconds); - float intervalToIntervalSeconds(uint32_t collectionInterval); + uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds); + float intervalTicksToSeconds(uint32_t collectionInterval) const; dur_millis_t minimumPeriodicInterval = 0; uint32_t internalTickCounter = 1; diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index 7e5a316ca..786184484 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -3,19 +3,20 @@ #include "../ipc/QueueFactory.h" #include "../ipc/MutexFactory.h" #include "../serviceinterface/ServiceInterface.h" +#include "../datapool/PoolReadGuard.h" InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth): SystemObject(setObjectId), - commandQueue(QueueFactory::instance()-> - createMessageQueue(messageQueueDepth)), - poolManager(this, commandQueue), - internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), - internalErrorDataset(this) { - mutex = MutexFactory::instance()->createMutex(); + commandQueue(QueueFactory::instance()-> + createMessageQueue(messageQueueDepth)), + poolManager(this, commandQueue), + internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), + internalErrorDataset(this) { + mutex = MutexFactory::instance()->createMutex(); } InternalErrorReporter::~InternalErrorReporter() { - MutexFactory::instance()->deleteMutex(mutex); + MutexFactory::instance()->deleteMutex(mutex); } void InternalErrorReporter::setDiagnosticPrintout(bool enable) { @@ -23,126 +24,128 @@ void InternalErrorReporter::setDiagnosticPrintout(bool enable) { } 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 newTmHits = getAndResetTmHits(); - uint32_t newStoreHits = getAndResetStoreHits(); + uint32_t newQueueHits = getAndResetQueueHits(); + uint32_t newTmHits = getAndResetTmHits(); + uint32_t newStoreHits = getAndResetStoreHits(); -#if FSFW_VERBOSE_LEVEL == 1 - if(diagnosticPrintout) { - if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) { +#if FSFW_VERBOSE_LEVEL >= 1 + if(diagnosticPrintout) { + if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "InternalErrorReporter::performOperation: Errors " - << "occured!" << std::endl; - sif::debug << "Queue errors: " << newQueueHits << std::endl; - sif::debug << "TM errors: " << newTmHits << std::endl; - sif::debug << "Store errors: " << newStoreHits << std::endl; + sif::debug << "InternalErrorReporter::performOperation: Errors " + << "occured!" << std::endl; + sif::debug << "Queue errors: " << newQueueHits << std::endl; + sif::debug << "TM errors: " << newTmHits << std::endl; + sif::debug << "Store errors: " << newStoreHits << std::endl; #else - sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n"); - sif::printDebug("Queue errors: %lu\n", static_cast(newQueueHits)); - sif::printDebug("TM errors: %lu\n", static_cast(newTmHits)); - sif::printDebug("Store errors: %lu\n", static_cast(newStoreHits)); + sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n"); + sif::printDebug("Queue errors: %lu\n", static_cast(newQueueHits)); + sif::printDebug("TM errors: %lu\n", static_cast(newTmHits)); + sif::printDebug("Store errors: %lu\n", static_cast(newStoreHits)); #endif - } - } + } + } #endif - internalErrorDataset.queueHits.value += newQueueHits; - internalErrorDataset.storeHits.value += newStoreHits; - internalErrorDataset.tmHits.value += newTmHits; - internalErrorDataset.setValidity(true, true); - internalErrorDataset.commit(timeoutType, timeoutMs); + { + PoolReadGuard readGuard(&internalErrorDataset); + if(readGuard.getReadResult() == HasReturnvaluesIF::RETURN_OK) { + internalErrorDataset.queueHits.value += newQueueHits; + internalErrorDataset.storeHits.value += newStoreHits; + internalErrorDataset.tmHits.value += newTmHits; + internalErrorDataset.setValidity(true, true); + } + } - poolManager.performHkOperation(); - - CommandMessage message; - ReturnValue_t result = commandQueue->receiveMessage(&message); - if(result != MessageQueueIF::EMPTY) { - poolManager.handleHousekeepingMessage(&message); - } - return HasReturnvaluesIF::RETURN_OK; + poolManager.performHkOperation(); + return HasReturnvaluesIF::RETURN_OK; } void InternalErrorReporter::queueMessageNotSent() { - incrementQueueHits(); + incrementQueueHits(); } void InternalErrorReporter::lostTm() { - incrementTmHits(); + incrementTmHits(); } uint32_t InternalErrorReporter::getAndResetQueueHits() { - uint32_t value; - mutex->lockMutex(timeoutType, timeoutMs); - value = queueHits; - queueHits = 0; - mutex->unlockMutex(); - return value; + uint32_t value; + mutex->lockMutex(timeoutType, timeoutMs); + value = queueHits; + queueHits = 0; + mutex->unlockMutex(); + return value; } uint32_t InternalErrorReporter::getQueueHits() { - uint32_t value; - mutex->lockMutex(timeoutType, timeoutMs); - value = queueHits; - mutex->unlockMutex(); - return value; + uint32_t value; + mutex->lockMutex(timeoutType, timeoutMs); + value = queueHits; + mutex->unlockMutex(); + return value; } void InternalErrorReporter::incrementQueueHits() { - mutex->lockMutex(timeoutType, timeoutMs); - queueHits++; - mutex->unlockMutex(); + mutex->lockMutex(timeoutType, timeoutMs); + queueHits++; + mutex->unlockMutex(); } uint32_t InternalErrorReporter::getAndResetTmHits() { - uint32_t value; - mutex->lockMutex(timeoutType, timeoutMs); - value = tmHits; - tmHits = 0; - mutex->unlockMutex(); - return value; + uint32_t value; + mutex->lockMutex(timeoutType, timeoutMs); + value = tmHits; + tmHits = 0; + mutex->unlockMutex(); + return value; } uint32_t InternalErrorReporter::getTmHits() { - uint32_t value; - mutex->lockMutex(timeoutType, timeoutMs); - value = tmHits; - mutex->unlockMutex(); - return value; + uint32_t value; + mutex->lockMutex(timeoutType, timeoutMs); + value = tmHits; + mutex->unlockMutex(); + return value; } void InternalErrorReporter::incrementTmHits() { - mutex->lockMutex(timeoutType, timeoutMs); - tmHits++; - mutex->unlockMutex(); + mutex->lockMutex(timeoutType, timeoutMs); + tmHits++; + mutex->unlockMutex(); } void InternalErrorReporter::storeFull() { - incrementStoreHits(); + incrementStoreHits(); } uint32_t InternalErrorReporter::getAndResetStoreHits() { - uint32_t value; - mutex->lockMutex(timeoutType, timeoutMs); - value = storeHits; - storeHits = 0; - mutex->unlockMutex(); - return value; + uint32_t value; + mutex->lockMutex(timeoutType, timeoutMs); + value = storeHits; + storeHits = 0; + mutex->unlockMutex(); + return value; } uint32_t InternalErrorReporter::getStoreHits() { - uint32_t value; - mutex->lockMutex(timeoutType, timeoutMs); - value = storeHits; - mutex->unlockMutex(); - return value; + uint32_t value; + mutex->lockMutex(timeoutType, timeoutMs); + value = storeHits; + mutex->unlockMutex(); + return value; } void InternalErrorReporter::incrementStoreHits() { - mutex->lockMutex(timeoutType, timeoutMs); - storeHits++; - mutex->unlockMutex(); + mutex->lockMutex(timeoutType, timeoutMs); + storeHits++; + mutex->unlockMutex(); } object_id_t InternalErrorReporter::getObjectId() const { @@ -155,14 +158,11 @@ MessageQueueId_t InternalErrorReporter::getCommandQueue() const { ReturnValue_t InternalErrorReporter::initializeLocalDataPool( localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { - localDataPoolMap.emplace(errorPoolIds::TM_HITS, - new PoolEntry()); - localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, - new PoolEntry()); - localDataPoolMap.emplace(errorPoolIds::STORE_HITS, - new PoolEntry()); - poolManager.subscribeForPeriodicPacket(internalErrorSid, false, - getPeriodicOperationFrequency(), true); + localDataPoolMap.emplace(errorPoolIds::TM_HITS, new PoolEntry()); + localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, new PoolEntry()); + localDataPoolMap.emplace(errorPoolIds::STORE_HITS, new PoolEntry()); + poolManager.subscribeForPeriodicPacket(internalErrorSid, false, getPeriodicOperationFrequency(), + true); internalErrorDataset.setValidity(true, true); return HasReturnvaluesIF::RETURN_OK; } @@ -192,9 +192,9 @@ ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() { } void InternalErrorReporter::setMutexTimeout(MutexIF::TimeoutType timeoutType, - uint32_t timeoutMs) { - this->timeoutType = timeoutType; - this->timeoutMs = timeoutMs; + uint32_t timeoutMs) { + this->timeoutType = timeoutType; + this->timeoutMs = timeoutMs; } LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() { diff --git a/internalError/InternalErrorReporter.h b/internalError/InternalErrorReporter.h index a237418ed..580cb8f6c 100644 --- a/internalError/InternalErrorReporter.h +++ b/internalError/InternalErrorReporter.h @@ -17,77 +17,78 @@ * All functions were kept virtual so this class can be extended easily * to store custom internal errors (e.g. communication interface errors). */ -class InternalErrorReporter: public SystemObject, - public ExecutableObjectIF, - public InternalErrorReporterIF, - public HasLocalDataPoolIF { +class InternalErrorReporter: + public SystemObject, + public ExecutableObjectIF, + public InternalErrorReporterIF, + public HasLocalDataPoolIF { public: - InternalErrorReporter(object_id_t setObjectId, - uint32_t messageQueueDepth = 5); + InternalErrorReporter(object_id_t setObjectId, + uint32_t messageQueueDepth = 5); - /** - * Enable diagnostic printout. Please note that this feature will - * only work if DEBUG has been supplied to the build defines. - * @param enable - */ - void setDiagnosticPrintout(bool enable); + /** + * Enable diagnostic printout. Please note that this feature will + * only work if DEBUG has been supplied to the build defines. + * @param enable + */ + void setDiagnosticPrintout(bool enable); - void setMutexTimeout(MutexIF::TimeoutType timeoutType, - uint32_t timeoutMs); + void setMutexTimeout(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs); - virtual ~InternalErrorReporter(); + virtual ~InternalErrorReporter(); virtual object_id_t getObjectId() const override; virtual MessageQueueId_t getCommandQueue() const override; virtual ReturnValue_t initializeLocalDataPool( - localpool::DataPool& localDataPoolMap, + localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; virtual dur_millis_t getPeriodicOperationFrequency() const override; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; - LocalDataPoolManager* getHkManagerHandle() override; + LocalDataPoolManager* getHkManagerHandle() override; virtual ReturnValue_t initialize() 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: - MessageQueueIF* commandQueue; - LocalDataPoolManager poolManager; + MessageQueueIF* commandQueue; + LocalDataPoolManager poolManager; - PeriodicTaskIF* executingTask = nullptr; + PeriodicTaskIF* executingTask = nullptr; - MutexIF* mutex = nullptr; - MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; - uint32_t timeoutMs = 20; + MutexIF* mutex = nullptr; + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; + uint32_t timeoutMs = 20; - sid_t internalErrorSid; - InternalErrorDataset internalErrorDataset; + sid_t internalErrorSid; + InternalErrorDataset internalErrorDataset; - bool diagnosticPrintout = true; + bool diagnosticPrintout = true; - uint32_t queueHits = 0; - uint32_t tmHits = 0; - uint32_t storeHits = 0; + uint32_t queueHits = 0; + uint32_t tmHits = 0; + uint32_t storeHits = 0; - uint32_t getAndResetQueueHits(); - uint32_t getQueueHits(); - void incrementQueueHits(); + uint32_t getAndResetQueueHits(); + uint32_t getQueueHits(); + void incrementQueueHits(); - uint32_t getAndResetTmHits(); - uint32_t getTmHits(); - void incrementTmHits(); + uint32_t getAndResetTmHits(); + uint32_t getTmHits(); + void incrementTmHits(); - uint32_t getAndResetStoreHits(); - uint32_t getStoreHits(); - void incrementStoreHits(); + uint32_t getAndResetStoreHits(); + uint32_t getStoreHits(); + void incrementStoreHits(); }; diff --git a/ipc/MessageQueueIF.h b/ipc/MessageQueueIF.h index 1c06521ca..74ccb29a2 100644 --- a/ipc/MessageQueueIF.h +++ b/ipc/MessageQueueIF.h @@ -27,7 +27,7 @@ public: //! Returned if a reply method was called without partner static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3); //! Returned if the target destination is invalid. - static constexpr ReturnValue_t DESTINVATION_INVALID = MAKE_RETURN_CODE(4); + static constexpr ReturnValue_t DESTINATION_INVALID = MAKE_RETURN_CODE(4); virtual ~MessageQueueIF() {} /** diff --git a/ipc/MessageQueueMessage.cpp b/ipc/MessageQueueMessage.cpp index e97778c3f..1958af54a 100644 --- a/ipc/MessageQueueMessage.cpp +++ b/ipc/MessageQueueMessage.cpp @@ -86,3 +86,7 @@ size_t MessageQueueMessage::getMaximumMessageSize() const { return this->MAX_MESSAGE_SIZE; } +size_t MessageQueueMessage::getMaximumDataSize() const { + return this->MAX_DATA_SIZE; +} + diff --git a/ipc/MessageQueueMessage.h b/ipc/MessageQueueMessage.h index 5234f64ff..111056caf 100644 --- a/ipc/MessageQueueMessage.h +++ b/ipc/MessageQueueMessage.h @@ -139,6 +139,7 @@ public: virtual void setMessageSize(size_t messageSize) override; virtual size_t getMinimumMessageSize() const override; virtual size_t getMaximumMessageSize() const override; + virtual size_t getMaximumDataSize() const override; /** * @brief This is a debug method that prints the content. diff --git a/ipc/MessageQueueMessageIF.h b/ipc/MessageQueueMessageIF.h index 33e01e7d0..893c30b5e 100644 --- a/ipc/MessageQueueMessageIF.h +++ b/ipc/MessageQueueMessageIF.h @@ -72,6 +72,7 @@ public: virtual void setMessageSize(size_t messageSize) = 0; virtual size_t getMinimumMessageSize() const = 0; virtual size_t getMaximumMessageSize() const = 0; + virtual size_t getMaximumDataSize() const = 0; }; diff --git a/ipc/MutexGuard.h b/ipc/MutexGuard.h new file mode 100644 index 000000000..9ee68c81f --- /dev/null +++ b/ipc/MutexGuard.h @@ -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_ */ diff --git a/ipc/MutexHelper.h b/ipc/MutexHelper.h deleted file mode 100644 index bc744d3f9..000000000 --- a/ipc/MutexHelper.h +++ /dev/null @@ -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(status); -#endif /* FSFW_VERBOSE_LEVEL >= 1 */ - } - - ~MutexHelper() { - if(internalMutex != nullptr) { - internalMutex->unlockMutex(); - } - } -private: - MutexIF* internalMutex; -}; - -#endif /* FRAMEWORK_IPC_MUTEXHELPER_H_ */ diff --git a/osal/CMakeLists.txt b/osal/CMakeLists.txt index 02ff24057..76b939b1a 100644 --- a/osal/CMakeLists.txt +++ b/osal/CMakeLists.txt @@ -1,34 +1,35 @@ # Check the OS_FSFW variable if(${OS_FSFW} STREQUAL "freertos") - add_subdirectory(FreeRTOS) + add_subdirectory(FreeRTOS) elseif(${OS_FSFW} STREQUAL "rtems") - add_subdirectory(rtems) + add_subdirectory(rtems) elseif(${OS_FSFW} STREQUAL "linux") - add_subdirectory(linux) + add_subdirectory(linux) elseif(${OS_FSFW} STREQUAL "host") - add_subdirectory(host) - if (WIN32) - add_subdirectory(windows) - elseif(UNIX) - target_sources(${LIB_FSFW_NAME} - PUBLIC - linux/TcUnixUdpPollingTask.cpp - linux/TmTcUnixUdpBridge.cpp - ) - endif () + add_subdirectory(host) + if (WIN32) + add_subdirectory(windows) + elseif(UNIX) + # We still need to pull in some Linux specific sources + target_sources(${LIB_FSFW_NAME} PUBLIC + linux/tcpipHelpers.cpp + ) + endif () else() - 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 - if (WIN32) - add_subdirectory(host) - add_subdirectory(windows) - elseif (UNIX) - add_subdirectory(linux) - else () - # MacOS or other OSes have not been tested yet / are not supported. - message(FATAL_ERROR "The host OS could not be determined! Aborting.") - endif() + 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 + if (WIN32) + add_subdirectory(host) + add_subdirectory(windows) + elseif (UNIX) + add_subdirectory(linux) + else () + # MacOS or other OSes have not been tested yet / are not supported. + message(FATAL_ERROR "The host OS could not be determined! Aborting.") + endif() -endif() \ No newline at end of file +endif() + +add_subdirectory(common) \ No newline at end of file diff --git a/osal/FreeRTOS/Clock.cpp b/osal/FreeRTOS/Clock.cpp index 806edcc7c..c15971fee 100644 --- a/osal/FreeRTOS/Clock.cpp +++ b/osal/FreeRTOS/Clock.cpp @@ -111,7 +111,7 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) { - struct tm time_tm; + struct tm time_tm = {}; time_tm.tm_year = from->year - 1900; time_tm.tm_mon = from->month - 1; diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index c0c82cf11..3a0f654ed 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -135,7 +135,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, QueueHandle_t destination = nullptr; if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) { - return MessageQueueIF::DESTINVATION_INVALID; + return MessageQueueIF::DESTINATION_INVALID; } else { destination = reinterpret_cast(sendTo); diff --git a/osal/common/CMakeLists.txt b/osal/common/CMakeLists.txt new file mode 100644 index 000000000..af76484d3 --- /dev/null +++ b/osal/common/CMakeLists.txt @@ -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() \ No newline at end of file diff --git a/osal/common/TcpIpBase.cpp b/osal/common/TcpIpBase.cpp new file mode 100644 index 000000000..27384ecc7 --- /dev/null +++ b/osal/common/TcpIpBase.cpp @@ -0,0 +1,54 @@ +#include "TcpIpBase.h" + +#ifdef __unix__ + +#include +#include + +#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 +} + diff --git a/osal/common/TcpIpBase.h b/osal/common/TcpIpBase.h new file mode 100644 index 000000000..652d791a1 --- /dev/null +++ b/osal/common/TcpIpBase.h @@ -0,0 +1,50 @@ +#ifndef FSFW_OSAL_COMMON_TCPIPIF_H_ +#define FSFW_OSAL_COMMON_TCPIPIF_H_ + +#include + +#ifdef _WIN32 + +#include + +#elif defined(__unix__) + +#include + +#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_ */ diff --git a/osal/common/TcpTmTcServer.cpp b/osal/common/TcpTmTcServer.cpp new file mode 100644 index 000000000..08a62ffb9 --- /dev/null +++ b/osal/common/TcpTmTcServer.cpp @@ -0,0 +1,132 @@ +#include "TcpTmTcServer.h" +#include "tcpipHelpers.h" +#include "../../serviceinterface/ServiceInterface.h" + +#ifdef _WIN32 +#include +#include + +#elif defined(__unix__) + +#include + +#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(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(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; +} + + diff --git a/osal/common/TcpTmTcServer.h b/osal/common/TcpTmTcServer.h new file mode 100644 index 000000000..4dcc77a2d --- /dev/null +++ b/osal/common/TcpTmTcServer.h @@ -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 +#endif + +#include +#include + +//! 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 receptionBuffer; + int tcpSockOpt = 0; + + +}; + +#endif /* FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ */ diff --git a/osal/common/UdpTcPollingTask.cpp b/osal/common/UdpTcPollingTask.cpp new file mode 100644 index 000000000..47f67b295 --- /dev/null +++ b/osal/common/UdpTcPollingTask.cpp @@ -0,0 +1,180 @@ +#include "UdpTcPollingTask.h" +#include "tcpipHelpers.h" +#include "../../globalfunctions/arrayprinter.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +#ifdef _WIN32 + +#include + +#else + +#include +#include + +#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(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(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(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(&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 +} diff --git a/osal/windows/TcWinUdpPollingTask.h b/osal/common/UdpTcPollingTask.h similarity index 55% rename from osal/windows/TcWinUdpPollingTask.h rename to osal/common/UdpTcPollingTask.h index 50d39d25f..052eced52 100644 --- a/osal/windows/TcWinUdpPollingTask.h +++ b/osal/common/UdpTcPollingTask.h @@ -1,7 +1,7 @@ #ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ #define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ -#include "TmTcWinUdpBridge.h" +#include "UdpTmTcBridge.h" #include "../../objectmanager/SystemObject.h" #include "../../tasks/ExecutableObjectIF.h" #include "../../storagemanager/StorageManagerIF.h" @@ -9,25 +9,22 @@ #include /** - * @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. + * @brief This class should be used with the UdpTmTcBridge to implement a UDP server + * for receiving and sending PUS TMTC. */ -class TcWinUdpPollingTask: public SystemObject, +class UdpTcPollingTask: + public TcpIpBase, + public SystemObject, public ExecutableObjectIF { friend class TmTcWinUdpBridge; 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. - 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, - size_t frameSize = 0, double timeoutSeconds = -1); - virtual~ TcWinUdpPollingTask(); + UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, + size_t maxRecvSize = 0, double timeoutSeconds = -1); + virtual~ UdpTcPollingTask(); /** * Turn on optional timeout for UDP polling. In the default mode, @@ -46,14 +43,11 @@ protected: private: //! TMTC bridge is cached. object_id_t tmtcBridgeId = objects::NO_OBJECT; - TmTcWinUdpBridge* tmtcBridge = nullptr; + UdpTmTcBridge* tmtcBridge = nullptr; MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; - //! Reception flags: https://linux.die.net/man/2/recvfrom. - int receptionFlags = 0; - //! Server socket, which is member of TMTC bridge and is assigned in - //! constructor - SOCKET serverUdpSocket = 0; + //! See: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom + int receptionFlags = 0; std::vector receptionBuffer; @@ -61,7 +55,6 @@ private: timeval receptionTimeout; ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); - void handleReadError(); }; #endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */ diff --git a/osal/common/UdpTmTcBridge.cpp b/osal/common/UdpTmTcBridge.cpp new file mode 100644 index 000000000..ba23f521b --- /dev/null +++ b/osal/common/UdpTmTcBridge.cpp @@ -0,0 +1,174 @@ +#include "tcpipHelpers.h" + +#include +#include +#include + +#ifdef _WIN32 + +#include + +#elif defined(__unix__) + +#include +#include + +#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(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(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; +} diff --git a/osal/common/UdpTmTcBridge.h b/osal/common/UdpTmTcBridge.h new file mode 100644 index 000000000..8b8d19491 --- /dev/null +++ b/osal/common/UdpTmTcBridge.h @@ -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 + +#elif defined(__unix__) + +#include + +#endif + +#include + +/** + * @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_ */ + diff --git a/osal/common/tcpipCommon.cpp b/osal/common/tcpipCommon.cpp new file mode 100644 index 000000000..551e2a426 --- /dev/null +++ b/osal/common/tcpipCommon.cpp @@ -0,0 +1,75 @@ +#include "tcpipCommon.h" +#include + +#ifdef _WIN32 +#include +#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(addr); + stringPtr = inet_ntop(AF_INET, &(addrIn->sin_addr), ipAddress, INET_ADDRSTRLEN); + break; + } + case AF_INET6: { + struct sockaddr_in6 *addrIn = reinterpret_cast(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 +} diff --git a/osal/common/tcpipCommon.h b/osal/common/tcpipCommon.h new file mode 100644 index 000000000..22b914dc1 --- /dev/null +++ b/osal/common/tcpipCommon.h @@ -0,0 +1,42 @@ +#ifndef FSFW_OSAL_COMMON_TCPIPCOMMON_H_ +#define FSFW_OSAL_COMMON_TCPIPCOMMON_H_ + +#include "../../timemanager/clockDefinitions.h" +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#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_ */ diff --git a/osal/common/tcpipHelpers.h b/osal/common/tcpipHelpers.h new file mode 100644 index 000000000..9764a93fe --- /dev/null +++ b/osal/common/tcpipHelpers.h @@ -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_ */ diff --git a/osal/host/CMakeLists.txt b/osal/host/CMakeLists.txt index 367f721e0..2d29ce5df 100644 --- a/osal/host/CMakeLists.txt +++ b/osal/host/CMakeLists.txt @@ -10,6 +10,7 @@ target_sources(${LIB_FSFW_NAME} QueueMapManager.cpp SemaphoreFactory.cpp TaskFactory.cpp + taskHelpers.cpp ) if(UNIX) diff --git a/osal/host/FixedTimeslotTask.cpp b/osal/host/FixedTimeslotTask.cpp index 272d99b9a..89daa2786 100644 --- a/osal/host/FixedTimeslotTask.cpp +++ b/osal/host/FixedTimeslotTask.cpp @@ -1,10 +1,9 @@ +#include "taskHelpers.h" #include "../../osal/host/FixedTimeslotTask.h" - #include "../../ipc/MutexFactory.h" #include "../../osal/host/Mutex.h" #include "../../osal/host/FixedTimeslotTask.h" - -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" #include "../../tasks/ExecutableObjectIF.h" #include @@ -12,6 +11,7 @@ #if defined(WIN32) #include +#include "../windows/winTaskHelpers.h" #elif defined(LINUX) #include #endif @@ -24,34 +24,12 @@ FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority, // It is propably possible to set task priorities by using the native // task handles for Windows / Linux mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this); -#if defined(WIN32) - /* 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 */ - int result = SetPriorityClass( - reinterpret_cast(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(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. +#if defined(_WIN32) + tasks::setTaskPriority(reinterpret_cast(mainThread.native_handle()), setPriority); +#elif defined(__unix__) + // TODO: We could reuse existing code here. #endif + tasks::insertTaskName(mainThread.get_id(), taskName); } FixedTimeslotTask::~FixedTimeslotTask(void) { @@ -60,7 +38,6 @@ FixedTimeslotTask::~FixedTimeslotTask(void) { if(mainThread.joinable()) { mainThread.join(); } - delete this; } void FixedTimeslotTask::taskEntryPoint(void* argument) { @@ -141,8 +118,11 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, } #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Component " << std::hex << componentId << - " not found, not adding it to pst" << std::endl; + sif::error << "Component " << std::hex << "0x" << componentId << "not found, " + "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(componentId)); #endif return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/osal/host/MessageQueue.cpp b/osal/host/MessageQueue.cpp index dfc045e8d..41c55a3df 100644 --- a/osal/host/MessageQueue.cpp +++ b/osal/host/MessageQueue.cpp @@ -3,7 +3,7 @@ #include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../ipc/MutexFactory.h" -#include "../../ipc/MutexHelper.h" +#include "../../ipc/MutexGuard.h" MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): messageSize(maxMessageSize), messageDepth(messageDepth) { @@ -63,12 +63,9 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { if(messageQueue.empty()) { return MessageQueueIF::EMPTY; } - // not sure this will work.. - //*message = std::move(messageQueue.front()); - MutexHelper mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20); - MessageQueueMessage* currentMessage = &messageQueue.front(); - std::copy(currentMessage->getBuffer(), - currentMessage->getBuffer() + messageSize, message->getBuffer()); + MutexGuard mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20); + std::copy(messageQueue.front().data(), messageQueue.front().data() + messageSize, + message->getBuffer()); messageQueue.pop(); // The last partner is the first uint32_t field in the message this->lastPartner = message->getSender(); @@ -82,7 +79,7 @@ MessageQueueId_t MessageQueue::getLastPartner() const { ReturnValue_t MessageQueue::flush(uint32_t* count) { *count = messageQueue.size(); // Clears the queue. - messageQueue = std::queue(); + messageQueue = std::queue>(); return HasReturnvaluesIF::RETURN_OK; } @@ -108,6 +105,9 @@ bool MessageQueue::isDefaultDestinationSet() const { ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault) { + if(message == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } message->setSender(sentFrom); if(message->getMessageSize() > message->getMaximumMessageSize()) { // 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; } if(targetQueue->messageQueue.size() < targetQueue->messageDepth) { - MutexHelper mutexLock(targetQueue->queueLock, - MutexIF::TimeoutType::WAITING, 20); - // not ideal, works for now though. - MessageQueueMessage* mqmMessage = - dynamic_cast(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 - } - + MutexGuard mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20); + targetQueue->messageQueue.push(std::vector(message->getMaximumMessageSize())); + memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(), + message->getMaximumMessageSize()); } else { return MessageQueueIF::FULL; diff --git a/osal/host/MessageQueue.h b/osal/host/MessageQueue.h index 97a9e4915..e965123dc 100644 --- a/osal/host/MessageQueue.h +++ b/osal/host/MessageQueue.h @@ -212,7 +212,7 @@ protected: //static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); private: - std::queue messageQueue; + std::queue> messageQueue; /** * @brief The class stores the queue id it got assigned. * If initialization fails, the queue id is set to zero. diff --git a/osal/host/MutexFactory.cpp b/osal/host/MutexFactory.cpp index bf7707d11..f3b98fd1d 100644 --- a/osal/host/MutexFactory.cpp +++ b/osal/host/MutexFactory.cpp @@ -24,5 +24,7 @@ MutexIF* MutexFactory::createMutex() { } void MutexFactory::deleteMutex(MutexIF* mutex) { - delete mutex; + if(mutex != nullptr) { + delete mutex; + } } diff --git a/osal/host/PeriodicTask.cpp b/osal/host/PeriodicTask.cpp index 7663d522d..09df410fe 100644 --- a/osal/host/PeriodicTask.cpp +++ b/osal/host/PeriodicTask.cpp @@ -1,5 +1,6 @@ #include "Mutex.h" #include "PeriodicTask.h" +#include "taskHelpers.h" #include "../../ipc/MutexFactory.h" #include "../../serviceinterface/ServiceInterfaceStream.h" @@ -10,7 +11,8 @@ #if defined(WIN32) #include -#elif defined(LINUX) +#include +#elif defined(__unix__) #include #endif @@ -19,37 +21,15 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, void (*setDeadlineMissedFunc)()) : started(false), taskName(name), period(setPeriod), 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 mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); -#if defined(WIN32) - /* 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 */ - int result = SetPriorityClass( - reinterpret_cast(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(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. +#if defined(_WIN32) + tasks::setTaskPriority(reinterpret_cast(mainThread.native_handle()), setPriority); +#elif defined(__unix__) + // TODO: We could reuse existing code here. #endif + tasks::insertTaskName(mainThread.get_id(), taskName); } PeriodicTask::~PeriodicTask(void) { @@ -58,7 +38,6 @@ PeriodicTask::~PeriodicTask(void) { if(mainThread.joinable()) { mainThread.join(); } - delete this; } void PeriodicTask::taskEntryPoint(void* argument) { diff --git a/osal/host/QueueMapManager.cpp b/osal/host/QueueMapManager.cpp index 2a54f8134..c9100fe9a 100644 --- a/osal/host/QueueMapManager.cpp +++ b/osal/host/QueueMapManager.cpp @@ -2,7 +2,7 @@ #include "../../serviceinterface/ServiceInterface.h" #include "../../ipc/MutexFactory.h" -#include "../../ipc/MutexHelper.h" +#include "../../ipc/MutexGuard.h" QueueMapManager* QueueMapManager::mqManagerInstance = nullptr; @@ -10,6 +10,10 @@ QueueMapManager::QueueMapManager() { mapLock = MutexFactory::instance()->createMutex(); } +QueueMapManager::~QueueMapManager() { + MutexFactory::instance()->deleteMutex(mapLock); +} + QueueMapManager* QueueMapManager::instance() { if (mqManagerInstance == nullptr){ mqManagerInstance = new QueueMapManager(); @@ -43,7 +47,7 @@ ReturnValue_t QueueMapManager::addMessageQueue( MessageQueueIF* QueueMapManager::getMessageQueue( MessageQueueId_t messageQueueId) const { - MutexHelper(mapLock, MutexIF::TimeoutType::WAITING, 50); + MutexGuard(mapLock, MutexIF::TimeoutType::WAITING, 50); auto queueIter = queueMap.find(messageQueueId); if(queueIter != queueMap.end()) { return queueIter->second; diff --git a/osal/host/QueueMapManager.h b/osal/host/QueueMapManager.h index 3610ca638..90c39c2f0 100644 --- a/osal/host/QueueMapManager.h +++ b/osal/host/QueueMapManager.h @@ -36,6 +36,8 @@ public: private: //! External instantiation is forbidden. QueueMapManager(); + ~QueueMapManager(); + uint32_t queueCounter = 0; MutexIF* mapLock; QueueMap queueMap; diff --git a/osal/host/SemaphoreFactory.cpp b/osal/host/SemaphoreFactory.cpp index 3d3fe17f3..530b3e450 100644 --- a/osal/host/SemaphoreFactory.cpp +++ b/osal/host/SemaphoreFactory.cpp @@ -1,7 +1,5 @@ #include "../../tasks/SemaphoreFactory.h" -#include "../../osal/linux/BinarySemaphore.h" -#include "../../osal/linux/CountingSemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; diff --git a/osal/host/TaskFactory.cpp b/osal/host/TaskFactory.cpp index 4fafd3491..71d0bf8b9 100644 --- a/osal/host/TaskFactory.cpp +++ b/osal/host/TaskFactory.cpp @@ -1,14 +1,16 @@ +#include "taskHelpers.h" +#include "../../tasks/TaskFactory.h" #include "../../osal/host/FixedTimeslotTask.h" #include "../../osal/host/PeriodicTask.h" -#include "../../tasks/TaskFactory.h" #include "../../returnvalues/HasReturnvaluesIF.h" #include "../../tasks/PeriodicTaskIF.h" +#include "../../serviceinterface/ServiceInterface.h" #include 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; TaskFactory::TaskFactory() { @@ -49,8 +51,12 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ } void TaskFactory::printMissedDeadline() { - /* TODO: Implement */ - return; + std::string name = tasks::getTaskName(std::this_thread::get_id()); +#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 */ } diff --git a/osal/host/taskHelpers.cpp b/osal/host/taskHelpers.cpp new file mode 100644 index 000000000..be4c29adc --- /dev/null +++ b/osal/host/taskHelpers.cpp @@ -0,0 +1,27 @@ +#include "taskHelpers.h" +#include +#include + +std::mutex nameMapLock; +std::map taskNameMap; + +ReturnValue_t tasks::insertTaskName(std::thread::id threadId, std::string taskName) { + std::lock_guard 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 lg(nameMapLock); + auto resultIter = taskNameMap.find(threadId); + if(resultIter != taskNameMap.end()) { + return resultIter->second; + } + else { + return "Unknown task"; + } +} + diff --git a/osal/host/taskHelpers.h b/osal/host/taskHelpers.h new file mode 100644 index 000000000..fa00490fb --- /dev/null +++ b/osal/host/taskHelpers.h @@ -0,0 +1,16 @@ +#ifndef FSFW_OSAL_HOST_TASKHELPERS_H_ +#define FSFW_OSAL_HOST_TASKHELPERS_H_ + +#include +#include + +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_ */ diff --git a/osal/linux/CMakeLists.txt b/osal/linux/CMakeLists.txt index 474e548bf..332fe2f49 100644 --- a/osal/linux/CMakeLists.txt +++ b/osal/linux/CMakeLists.txt @@ -13,9 +13,8 @@ target_sources(${LIB_FSFW_NAME} QueueFactory.cpp SemaphoreFactory.cpp TaskFactory.cpp - TcUnixUdpPollingTask.cpp - TmTcUnixUdpBridge.cpp Timer.cpp + tcpipHelpers.cpp ) find_package(Threads REQUIRED) diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index 60d15dee7..12774a58c 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -190,13 +190,15 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { return HasReturnvaluesIF::RETURN_FAILED; } return HasReturnvaluesIF::RETURN_OK; - }else if(status==0){ + } + else if (status==0) { //Success but no message received return MessageQueueIF::EMPTY; - } else { + } + else { //No message was received. Keep lastPartner anyway, I might send //something later. But still, delete packet content. - memset(message->getData(), 0, message->getMaximumMessageSize()); + memset(message->getData(), 0, message->getMaximumDataSize()); switch(errno){ case EAGAIN: //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 " << sentFrom << std::endl; #endif - return DESTINVATION_INVALID; + return DESTINATION_INVALID; } case EINTR: //The call was interrupted by a signal. diff --git a/osal/linux/PosixThread.cpp b/osal/linux/PosixThread.cpp index bd8e72583..72adfb140 100644 --- a/osal/linux/PosixThread.cpp +++ b/osal/linux/PosixThread.cpp @@ -6,7 +6,7 @@ #include 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'; 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) { /* The tick count has overflowed since this function was - lasted called. In this case the only time we should ever - actually delay is if the wake time has also overflowed, - and the wake time is greater than the tick time. When this - is the case it is as if neither time had overflowed. */ + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) && (nextTimeToWake_ms > currentTime_ms)) { shouldDelay = true; } } else { - /* The tick time has not overflowed. In this case we will - delay if either the wake time has overflowed, and/or the - tick time is less than the wake time. */ + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) || (nextTimeToWake_ms > currentTime_ms)) { shouldDelay = true; @@ -184,8 +184,11 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { strerror(status) << std::endl; #endif } - - // TODO FIFO -> This needs root privileges for the process +#ifndef FSFW_USE_REALTIME_FOR_LINUX +#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); if(status != 0){ #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -203,7 +206,7 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { strerror(status) << std::endl; #endif } - +#endif //Set Signal Mask for suspend until startTask is called sigset_t waitSignal; sigemptyset(&waitSignal); @@ -220,8 +223,16 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { status = pthread_create(&thread,&attributes,fnc_,arg_); if(status != 0){ #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Posix Thread create failed with: " << + sif::error << "PosixThread::createTask: Failed with: " << 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 } diff --git a/osal/linux/TaskFactory.cpp b/osal/linux/TaskFactory.cpp index 935646477..80bf47b7c 100644 --- a/osal/linux/TaskFactory.cpp +++ b/osal/linux/TaskFactory.cpp @@ -2,6 +2,7 @@ #include "PeriodicPosixTask.h" #include "../../tasks/TaskFactory.h" +#include "../../serviceinterface/ServiceInterface.h" #include "../../returnvalues/HasReturnvaluesIF.h" //TODO: Different variant than the lazy loading in QueueFactory. What's better and why? diff --git a/osal/linux/TcUnixUdpPollingTask.cpp b/osal/linux/TcUnixUdpPollingTask.cpp deleted file mode 100644 index 11ed7fee6..000000000 --- a/osal/linux/TcUnixUdpPollingTask.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include "TcUnixUdpPollingTask.h" -#include "../../globalfunctions/arrayprinter.h" - -#include - -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(&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(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(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 - } - } -} diff --git a/osal/linux/TcUnixUdpPollingTask.h b/osal/linux/TcUnixUdpPollingTask.h deleted file mode 100644 index cc0325616..000000000 --- a/osal/linux/TcUnixUdpPollingTask.h +++ /dev/null @@ -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 -#include - -/** - * @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 receptionBuffer; - - size_t frameSize = 0; - timeval receptionTimeout; - - ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); - void handleReadError(); -}; - -#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */ diff --git a/osal/linux/TmTcUnixUdpBridge.cpp b/osal/linux/TmTcUnixUdpBridge.cpp deleted file mode 100644 index 0af1fc68b..000000000 --- a/osal/linux/TmTcUnixUdpBridge.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "TmTcUnixUdpBridge.h" -#include "../../serviceinterface/ServiceInterface.h" -#include "../../ipc/MutexHelper.h" - -#include -#include - - -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(&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(&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; -} - diff --git a/osal/linux/TmTcUnixUdpBridge.h b/osal/linux/TmTcUnixUdpBridge.h deleted file mode 100644 index ae6f6adca..000000000 --- a/osal/linux/TmTcUnixUdpBridge.h +++ /dev/null @@ -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 -#include -#include - -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_ */ diff --git a/osal/linux/tcpipHelpers.cpp b/osal/linux/tcpipHelpers.cpp new file mode 100644 index 000000000..d7c644ecb --- /dev/null +++ b/osal/linux/tcpipHelpers.cpp @@ -0,0 +1,109 @@ +#include "../common/tcpipHelpers.h" + +#include "../../serviceinterface/ServiceInterface.h" +#include "../../tasks/TaskFactory.h" + +#include +#include + +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); + } +} diff --git a/osal/rtems/Clock.cpp b/osal/rtems/Clock.cpp index aef71fe15..b80786f74 100644 --- a/osal/rtems/Clock.cpp +++ b/osal/rtems/Clock.cpp @@ -1,7 +1,7 @@ #include "RtemsBasic.h" #include "../../timemanager/Clock.h" -#include "../../ipc/MutexHelper.h" +#include "../../ipc/MutexGuard.h" #include #include @@ -183,7 +183,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ return HasReturnvaluesIF::RETURN_FAILED; } - MutexHelper helper(timeMutex); + MutexGuard helper(timeMutex); leapSeconds = leapSeconds_; @@ -196,7 +196,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { if(timeMutex==nullptr){ return HasReturnvaluesIF::RETURN_FAILED; } - MutexHelper helper(timeMutex); + MutexGuard helper(timeMutex); *leapSeconds_ = leapSeconds; diff --git a/osal/rtems/MessageQueue.cpp b/osal/rtems/MessageQueue.cpp index bfaf35690..717b80dd0 100644 --- a/osal/rtems/MessageQueue.cpp +++ b/osal/rtems/MessageQueue.cpp @@ -61,7 +61,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { } else { //No message was received. Keep lastPartner anyway, I might send something later. //But still, delete packet content. - memset(message->getData(), 0, message->getMaximumMessageSize()); + memset(message->getData(), 0, message->getMaximumDataSize()); } return convertReturnCode(status); } diff --git a/osal/windows/CMakeLists.txt b/osal/windows/CMakeLists.txt index b6e76d6a3..36a547658 100644 --- a/osal/windows/CMakeLists.txt +++ b/osal/windows/CMakeLists.txt @@ -1,11 +1,4 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - TcWinUdpPollingTask.cpp - TmTcWinUdpBridge.cpp +target_sources(${LIB_FSFW_NAME} PRIVATE + tcpipHelpers.cpp + winTaskHelpers.cpp ) - -target_link_libraries(${LIB_FSFW_NAME} - PRIVATE - wsock32 - ws2_32 -) \ No newline at end of file diff --git a/osal/windows/TcWinUdpPollingTask.cpp b/osal/windows/TcWinUdpPollingTask.cpp deleted file mode 100644 index 4fd88c937..000000000 --- a/osal/windows/TcWinUdpPollingTask.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "TcWinUdpPollingTask.h" -#include "../../globalfunctions/arrayprinter.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -#include -#include - -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(receptionBuffer.data()), frameSize, - receptionFlags, reinterpret_cast(&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(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(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(&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); -} diff --git a/osal/windows/TmTcWinUdpBridge.cpp b/osal/windows/TmTcWinUdpBridge.cpp deleted file mode 100644 index 69a48f3ee..000000000 --- a/osal/windows/TmTcWinUdpBridge.cpp +++ /dev/null @@ -1,212 +0,0 @@ -#include -#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(&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(&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(data), dataLen, flags, - reinterpret_cast(&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; - } - } -} - diff --git a/osal/windows/TmTcWinUdpBridge.h b/osal/windows/TmTcWinUdpBridge.h deleted file mode 100644 index 8188039c0..000000000 --- a/osal/windows/TmTcWinUdpBridge.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_ -#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_ - -#include "../../tmtcservices/TmTcBridge.h" - -#include -#include - -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_ */ - diff --git a/osal/windows/tcpipHelpers.cpp b/osal/windows/tcpipHelpers.cpp new file mode 100644 index 000000000..03278a92e --- /dev/null +++ b/osal/windows/tcpipHelpers.cpp @@ -0,0 +1,63 @@ +#include "../common/tcpipHelpers.h" +#include + +#include "../../tasks/TaskFactory.h" +#include "../../serviceinterface/ServiceInterface.h" + + +#include +#include + +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); + } +} + diff --git a/osal/windows/winTaskHelpers.cpp b/osal/windows/winTaskHelpers.cpp new file mode 100644 index 000000000..6765b952c --- /dev/null +++ b/osal/windows/winTaskHelpers.cpp @@ -0,0 +1,107 @@ +#include +#include + +TaskPriority tasks::makeWinPriority(PriorityClass prioClass, PriorityNumber prioNumber) { + return (static_cast(prioClass) << 16) | static_cast (prioNumber); +} + +void tasks::getWinPriorityParameters(TaskPriority priority, + DWORD& priorityClass, int& priorityNumber) { + PriorityClass classInternal = static_cast(priority >> 16 & 0xff); + PriorityNumber numberInternal = static_cast(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(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(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; +} diff --git a/osal/windows/winTaskHelpers.h b/osal/windows/winTaskHelpers.h new file mode 100644 index 000000000..64e526722 --- /dev/null +++ b/osal/windows/winTaskHelpers.h @@ -0,0 +1,37 @@ +#include "../../tasks/TaskFactory.h" + +#include +#include + +#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 + diff --git a/power/PowerComponent.cpp b/power/PowerComponent.cpp index 04f8658ea..9ea84dadb 100644 --- a/power/PowerComponent.cpp +++ b/power/PowerComponent.cpp @@ -1,6 +1,7 @@ #include "PowerComponent.h" #include "../serialize/SerializeAdapter.h" + PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF), doIHaveTwoSwitches(false) { } @@ -8,23 +9,23 @@ PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF), PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, uint8_t switchId1, bool twoSwitches, uint8_t switchId2) : deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2), - doIHaveTwoSwitches(twoSwitches), min(min), max(max), + doIHaveTwoSwitches(twoSwitches), minPower(min), maxPower(max), moduleId(moduleId) { } ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = SerializeAdapter::serialize(&min, buffer, + ReturnValue_t result = SerializeAdapter::serialize(&minPower, buffer, size, maxSize, streamEndianness); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - return SerializeAdapter::serialize(&max, buffer, size, maxSize, + return SerializeAdapter::serialize(&maxPower, buffer, size, maxSize, streamEndianness); } size_t PowerComponent::getSerializedSize() const { - return sizeof(min) + sizeof(max); + return sizeof(minPower) + sizeof(maxPower); } object_id_t PowerComponent::getDeviceObjectId() { @@ -44,21 +45,21 @@ bool PowerComponent::hasTwoSwitches() { } float PowerComponent::getMin() { - return min; + return minPower; } float PowerComponent::getMax() { - return max; + return maxPower; } ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, size_t* size, Endianness streamEndianness) { - ReturnValue_t result = SerializeAdapter::deSerialize(&min, buffer, + ReturnValue_t result = SerializeAdapter::deSerialize(&minPower, buffer, size, streamEndianness); if (result != HasReturnvaluesIF::RETURN_OK) { 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, @@ -69,10 +70,10 @@ ReturnValue_t PowerComponent::getParameter(uint8_t domainId, uint8_t uniqueId, } switch (uniqueId) { case 0: - parameterWrapper->set<>(min); + parameterWrapper->set<>(minPower); break; case 1: - parameterWrapper->set<>(max); + parameterWrapper->set<>(maxPower); break; default: return INVALID_IDENTIFIER_ID; diff --git a/power/PowerComponent.h b/power/PowerComponent.h index 659b68530..6b9778a59 100644 --- a/power/PowerComponent.h +++ b/power/PowerComponent.h @@ -9,7 +9,7 @@ class PowerComponent: public PowerComponentIF { 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 switchId2 = 0xFF); @@ -41,8 +41,8 @@ private: const bool doIHaveTwoSwitches; - float min = 0.0; - float max = 0.0; + float minPower = 0.0; + float maxPower = 0.0; uint8_t moduleId = 0; diff --git a/pus/CService200ModeCommanding.cpp b/pus/CService200ModeCommanding.cpp index c4e99359b..70caadd10 100644 --- a/pus/CService200ModeCommanding.cpp +++ b/pus/CService200ModeCommanding.cpp @@ -61,8 +61,7 @@ ReturnValue_t CService200ModeCommanding::prepareCommand( return result; } - ModeMessage::setModeMessage(dynamic_cast(message), - ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(), + ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(), modeCommandPacket.getSubmode()); return result; } diff --git a/pus/Service1TelecommandVerification.cpp b/pus/Service1TelecommandVerification.cpp index 9e86c752a..7ce75478b 100644 --- a/pus/Service1TelecommandVerification.cpp +++ b/pus/Service1TelecommandVerification.cpp @@ -15,7 +15,9 @@ Service1TelecommandVerification::Service1TelecommandVerification( tmQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); } -Service1TelecommandVerification::~Service1TelecommandVerification() {} +Service1TelecommandVerification::~Service1TelecommandVerification() { + QueueFactory::instance()->deleteMessageQueue(tmQueue); +} MessageQueueId_t Service1TelecommandVerification::getVerificationQueue(){ return tmQueue->getId(); diff --git a/pus/Service20ParameterManagement.cpp b/pus/Service20ParameterManagement.cpp index bc3a9119b..90e966500 100644 --- a/pus/Service20ParameterManagement.cpp +++ b/pus/Service20ParameterManagement.cpp @@ -75,9 +75,8 @@ ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue #else sif::printError("Service20ParameterManagement::checkInterfaceAndAcquire" "MessageQueue: Can't access object\n"); - sif::printError("Object ID: 0x%08x\n", objectId); - sif::printError("Make sure it implements " - "ReceivesParameterMessagesIF!\n"); + sif::printError("Object ID: 0x%08x\n", *objectId); + sif::printError("Make sure it implements ReceivesParameterMessagesIF!\n"); #endif return CommandingServiceBase::INVALID_OBJECT; diff --git a/pus/Service3Housekeeping.cpp b/pus/Service3Housekeeping.cpp index 5456764d0..c4f80c2a5 100644 --- a/pus/Service3Housekeeping.cpp +++ b/pus/Service3Housekeeping.cpp @@ -159,7 +159,7 @@ ReturnValue_t Service3Housekeeping::prepareCollectionIntervalModificationCommand CommandMessage *command, object_id_t objectId, bool isDiagnostics, const uint8_t *tcData, size_t tcDataLen) { 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; } diff --git a/pus/Service5EventReporting.cpp b/pus/Service5EventReporting.cpp index 29eb7f20e..965a27ad6 100644 --- a/pus/Service5EventReporting.cpp +++ b/pus/Service5EventReporting.cpp @@ -15,7 +15,9 @@ Service5EventReporting::Service5EventReporting(object_id_t objectId, eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); } -Service5EventReporting::~Service5EventReporting(){} +Service5EventReporting::~Service5EventReporting() { + QueueFactory::instance()->deleteMessageQueue(eventQueue); +} ReturnValue_t Service5EventReporting::performService() { EventMessage message; diff --git a/pus/Service8FunctionManagement.cpp b/pus/Service8FunctionManagement.cpp index a2202abc1..54187a829 100644 --- a/pus/Service8FunctionManagement.cpp +++ b/pus/Service8FunctionManagement.cpp @@ -53,12 +53,14 @@ ReturnValue_t Service8FunctionManagement::checkInterfaceAndAcquireMessageQueue( ReturnValue_t Service8FunctionManagement::prepareCommand( CommandMessage* message, uint8_t subservice, const uint8_t* tcData, size_t tcDataLen, uint32_t* state, object_id_t objectId) { - return prepareDirectCommand(dynamic_cast(message), - tcData, tcDataLen); + return prepareDirectCommand(message, tcData, tcDataLen); } ReturnValue_t Service8FunctionManagement::prepareDirectCommand( 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 FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Service8FunctionManagement::prepareDirectCommand:" diff --git a/pus/servicepackets/Service8Packets.h b/pus/servicepackets/Service8Packets.h index b026edf52..a27cf8bb6 100644 --- a/pus/servicepackets/Service8Packets.h +++ b/pus/servicepackets/Service8Packets.h @@ -43,8 +43,8 @@ public: private: DirectCommand(const DirectCommand &command); - object_id_t objectId; - ActionId_t actionId; + object_id_t objectId = 0; + ActionId_t actionId = 0; uint32_t parametersSize; //!< [EXPORT] : [IGNORE] const uint8_t * parameterBuffer; //!< [EXPORT] : [MAXSIZE] 65535 Bytes diff --git a/serialize/SerializeElement.h b/serialize/SerializeElement.h index 470802927..db66f9cc2 100644 --- a/serialize/SerializeElement.h +++ b/serialize/SerializeElement.h @@ -25,7 +25,7 @@ public: } SerializeElement() : - LinkedElement(this) { + LinkedElement(this), entry() { } ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, diff --git a/storagemanager/PoolManager.cpp b/storagemanager/PoolManager.cpp index 4e8014fd3..eec849078 100644 --- a/storagemanager/PoolManager.cpp +++ b/storagemanager/PoolManager.cpp @@ -15,7 +15,7 @@ PoolManager::~PoolManager(void) { ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address, bool ignoreFault) { - MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, + MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs); ReturnValue_t status = LocalPool::reserveSpace(size, address,ignoreFault); @@ -32,7 +32,7 @@ ReturnValue_t PoolManager::deleteData( ". id is "<< storeId.packetIndex << std::endl; #endif #endif - MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, + MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs); return LocalPool::deleteData(storeId); } @@ -40,7 +40,7 @@ ReturnValue_t PoolManager::deleteData( ReturnValue_t PoolManager::deleteData(uint8_t* buffer, 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, size, storeId); return status; diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 5786a2252..4dde3a23f 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -3,7 +3,7 @@ #include "LocalPool.h" #include "StorageAccessor.h" -#include "../ipc/MutexHelper.h" +#include "../ipc/MutexGuard.h" /** diff --git a/tasks/TaskFactory.h b/tasks/TaskFactory.h index 03b5163c4..d4795202c 100644 --- a/tasks/TaskFactory.h +++ b/tasks/TaskFactory.h @@ -22,9 +22,26 @@ public: /** * Creates a new periodic task and returns the interface pointer. * @param name_ Name of the task - * @param taskPriority_ Priority of the task + * @param taskPriority_ + * Priority of the task. This value might have different ranges for the various OSALs. + * - Linux Value ranging from 0 to 99 with 99 being the highest value. + * - Host For Windows, the value can be retrieved by using the #tasks::makeWinPriority + * function. For Linux, same priority system as specified above. MacOS not tested + * yet + * - FreeRTOS Value depends on the FreeRTOS configuration, higher number means higher priority + * - RTEMS Values ranging from 0 to 99 with 99 being the highest value. + * * @param stackSize_ Stack Size of the task + * This value might have different recommended ranges for the various OSALs. + * - Linux Lowest limit is the PeriodicTaskIF::MINIMUM_STACK_SIZE value + * - Host Value is ignored for now because the C++ threading abstraction layer is used. + * - FreeRTOS Stack size in bytes. It is recommended to specify at least 1kB of stack for + * FSFW tasks, but the lowest possible size is specified in the + * FreeRTOSConfig.h file. + * - RTEMS Lowest limit is specified the PeriodicTaskIF::MINIMUM_STACK_SIZE value. + * * @param period_ Period of the task + * * @param deadLineMissedFunction_ Function to be called if a deadline was missed * @return PeriodicTaskIF* Pointer to the newly created Task */ @@ -34,7 +51,8 @@ public: TaskDeadlineMissedFunction deadLineMissedFunction_); /** - * + * The meaning for the variables for fixed timeslot tasks is the same as for periodic tasks. + * See #createPeriodicTask documentation. * @param name_ Name of the task * @param taskPriority_ Priority of the task * @param stackSize_ Stack Size of the task diff --git a/tasks/Typedef.h b/tasks/Typedef.h index 07d96b00d..55f6bda26 100644 --- a/tasks/Typedef.h +++ b/tasks/Typedef.h @@ -2,7 +2,7 @@ #define FRAMEWORK_TASKS_TYPEDEF_H_ typedef const char* TaskName; -typedef uint8_t TaskPriority; +typedef uint32_t TaskPriority; typedef size_t TaskStackSize; typedef double TaskPeriod; typedef void (*TaskDeadlineMissedFunction)(); diff --git a/tcdistribution/CCSDSDistributor.cpp b/tcdistribution/CCSDSDistributor.cpp index b795854f2..62cbfbf2b 100644 --- a/tcdistribution/CCSDSDistributor.cpp +++ b/tcdistribution/CCSDSDistributor.cpp @@ -1,8 +1,10 @@ #include "CCSDSDistributor.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" #include "../tmtcpacket/SpacePacketBase.h" +#define CCSDS_DISTRIBUTOR_DEBUGGING 0 + CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId): TcDistributor(setObjectId), defaultApid( setDefaultApid ) { @@ -11,26 +13,36 @@ CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, CCSDSDistributor::~CCSDSDistributor() {} TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { +#if CCSDS_DISTRIBUTOR_DEBUGGING == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 -// sif::debug << "CCSDSDistributor::selectDestination received: " << -// this->currentMessage.getStorageId().pool_index << ", " << -// this->currentMessage.getStorageId().packet_index << std::endl; + sif::debug << "CCSDSDistributor::selectDestination received: " << + this->currentMessage.getStorageId().poolIndex << ", " << + this->currentMessage.getStorageId().packetIndex << std::endl; +#else + sif::printDebug("CCSDSDistributor::selectDestination received: %d, %d\n", + currentMessage.getStorageId().poolIndex, currentMessage.getStorageId().packetIndex); +#endif #endif const uint8_t* packet = nullptr; size_t size = 0; ReturnValue_t result = this->tcStore->getData(currentMessage.getStorageId(), &packet, &size ); if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CCSDSDistributor::selectDestination: Getting data from" " store failed!" << std::endl; +#else + sif::printError("CCSDSDistributor::selectDestination: Getting data from" + " store failed!\n"); +#endif #endif } SpacePacketBase currentPacket(packet); -#if FSFW_CPP_OSTREAM_ENABLED == 1 -// sif:: info << "CCSDSDistributor::selectDestination has packet with APID " -// << std::hex << currentPacket.getAPID() << std::dec << std::endl; +#if FSFW_CPP_OSTREAM_ENABLED == 1 && CCSDS_DISTRIBUTOR_DEBUGGING == 1 + sif::info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex << + currentPacket.getAPID() << std::dec << std::endl; #endif TcMqMapIter position = this->queueMap.find(currentPacket.getAPID()); if ( position != this->queueMap.end() ) { @@ -76,9 +88,14 @@ ReturnValue_t CCSDSDistributor::initialize() { ReturnValue_t status = this->TcDistributor::initialize(); this->tcStore = objectManager->get( objects::TC_STORE ); if (this->tcStore == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CCSDSDistributor::initialize: Could not initialize" " TC store!" << std::endl; +#else + sif::printError("CCSDSDistributor::initialize: Could not initialize" + " TC store!\n"); +#endif #endif status = RETURN_FAILED; } diff --git a/tcdistribution/PUSDistributor.cpp b/tcdistribution/PUSDistributor.cpp index 00fd9029a..abdd1f8d3 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/tcdistribution/PUSDistributor.cpp @@ -1,22 +1,24 @@ #include "CCSDSDistributorIF.h" #include "PUSDistributor.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" #include "../tmtcpacket/pus/TcPacketStored.h" #include "../tmtcservices/PusVerificationReport.h" +#define PUS_DISTRIBUTOR_DEBUGGING 0 + PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId, - object_id_t setPacketSource) : - TcDistributor(setObjectId), checker(setApid), verifyChannel(), - tcStatus(RETURN_FAILED), packetSource(setPacketSource) {} + object_id_t setPacketSource) : + TcDistributor(setObjectId), checker(setApid), verifyChannel(), + tcStatus(RETURN_FAILED), packetSource(setPacketSource) {} PUSDistributor::~PUSDistributor() {} PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - // sif:: debug << "PUSDistributor::handlePacket received: " - // << this->current_packet_id.store_index << ", " - // << this->current_packet_id.packet_index << std::endl; +#if FSFW_CPP_OSTREAM_ENABLED == 1 && PUS_DISTRIBUTOR_DEBUGGING == 1 + store_address_t storeId = this->currentMessage.getStorageId()); + sif:: debug << "PUSDistributor::handlePacket received: " << storeId.poolIndex << ", " << + storeId.packetIndex << std::endl; #endif TcMqMapIter queueMapIt = this->queueMap.end(); if(this->currentPacket == nullptr) { @@ -25,15 +27,17 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { this->currentPacket->setStoreAddress(this->currentMessage.getStorageId()); if (currentPacket->getWholeData() != nullptr) { tcStatus = checker.checkPacket(currentPacket); -#ifdef DEBUG if(tcStatus != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "PUSDistributor::handlePacket: Packet format " - << "invalid, code "<< static_cast(tcStatus) - << std::endl; + sif::debug << "PUSDistributor::handlePacket: Packet format invalid, code " << + static_cast(tcStatus) << std::endl; +#else + sif::printDebug("PUSDistributor::handlePacket: Packet format invalid, code %d\n", + static_cast(tcStatus)); +#endif #endif } -#endif uint32_t queue_id = currentPacket->getService(); queueMapIt = this->queueMap.find(queue_id); } @@ -43,11 +47,12 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { if (queueMapIt == this->queueMap.end()) { tcStatus = DESTINATION_NOT_FOUND; -#ifdef DEBUG +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "PUSDistributor::handlePacket: Destination not found, " - << "code "<< static_cast(tcStatus) << std::endl; -#endif + sif::debug << "PUSDistributor::handlePacket: Destination not found" << std::endl; +#else + sif::printDebug("PUSDistributor::handlePacket: Destination not found\n"); +#endif /* !FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif } @@ -62,46 +67,54 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { ReturnValue_t PUSDistributor::registerService(AcceptsTelecommandsIF* service) { - uint16_t serviceId = service->getIdentifier(); + uint16_t serviceId = service->getIdentifier(); +#if PUS_DISTRIBUTOR_DEBUGGING == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - // sif::info << "Service ID: " << (int)serviceId << std::endl; + sif::info << "Service ID: " << static_cast(serviceId) << std::endl; +#else + sif::printInfo("Service ID: %d\n", static_cast(serviceId)); #endif - MessageQueueId_t queue = service->getRequestQueue(); - auto returnPair = queueMap.emplace(serviceId, queue); - if (not returnPair.second) { +#endif + MessageQueueId_t queue = service->getRequestQueue(); + auto returnPair = queueMap.emplace(serviceId, queue); + if (not returnPair.second) { +#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PUSDistributor::registerService: Service ID already" - " exists in map." << std::endl; + sif::error << "PUSDistributor::registerService: Service ID already" + " exists in map" << std::endl; +#else + sif::printError("PUSDistributor::registerService: Service ID already exists in map\n"); #endif - return SERVICE_ID_ALREADY_EXISTS; - } - return HasReturnvaluesIF::RETURN_OK; +#endif + return SERVICE_ID_ALREADY_EXISTS; + } + return HasReturnvaluesIF::RETURN_OK; } MessageQueueId_t PUSDistributor::getRequestQueue() { - return tcQueue->getId(); + return tcQueue->getId(); } ReturnValue_t PUSDistributor::callbackAfterSending(ReturnValue_t queueStatus) { - if (queueStatus != RETURN_OK) { - tcStatus = queueStatus; - } - if (tcStatus != RETURN_OK) { - this->verifyChannel.sendFailureReport(tc_verification::ACCEPTANCE_FAILURE, - currentPacket, tcStatus); - // A failed packet is deleted immediately after reporting, - // otherwise it will block memory. - currentPacket->deletePacket(); - return RETURN_FAILED; - } else { - this->verifyChannel.sendSuccessReport(tc_verification::ACCEPTANCE_SUCCESS, - currentPacket); - return RETURN_OK; - } + if (queueStatus != RETURN_OK) { + tcStatus = queueStatus; + } + if (tcStatus != RETURN_OK) { + this->verifyChannel.sendFailureReport(tc_verification::ACCEPTANCE_FAILURE, + currentPacket, tcStatus); + // A failed packet is deleted immediately after reporting, + // otherwise it will block memory. + currentPacket->deletePacket(); + return RETURN_FAILED; + } else { + this->verifyChannel.sendSuccessReport(tc_verification::ACCEPTANCE_SUCCESS, + currentPacket); + return RETURN_OK; + } } uint16_t PUSDistributor::getIdentifier() { - return checker.getApid(); + return checker.getApid(); } ReturnValue_t PUSDistributor::initialize() { @@ -111,15 +124,17 @@ ReturnValue_t PUSDistributor::initialize() { return ObjectManagerIF::CHILD_INIT_FAILED; } - CCSDSDistributorIF* ccsdsDistributor = - objectManager->get(packetSource); - if (ccsdsDistributor == nullptr) { + CCSDSDistributorIF* ccsdsDistributor = + objectManager->get(packetSource); + if (ccsdsDistributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PUSDistributor::initialize: Packet source invalid." - << " Make sure it exists and implements CCSDSDistributorIF!" - << std::endl; + sif::error << "PUSDistributor::initialize: Packet source invalid" << std::endl; + sif::error << " Make sure it exists and implements CCSDSDistributorIF!" << std::endl; +#else + sif::printError("PUSDistributor::initialize: Packet source invalid\n"); + sif::printError("Make sure it exists and implements CCSDSDistributorIF\n"); #endif - return RETURN_FAILED; - } - return ccsdsDistributor->registerApplication(this); + return RETURN_FAILED; + } + return ccsdsDistributor->registerApplication(this); } diff --git a/thermal/Heater.cpp b/thermal/Heater.cpp index 782ce2963..770494385 100644 --- a/thermal/Heater.cpp +++ b/thermal/Heater.cpp @@ -1,350 +1,352 @@ -#include "../devicehandlers/DeviceHandlerFailureIsolation.h" #include "Heater.h" +#include "../devicehandlers/DeviceHandlerFailureIsolation.h" #include "../power/Fuse.h" #include "../ipc/QueueFactory.h" Heater::Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1) : - HealthDevice(objectId, 0), internalState(STATE_OFF), powerSwitcher( - NULL), pcduQueueId(0), switch0(switch0), switch1(switch1), wasOn( - false), timedOut(false), reactedToBeingFaulty(false), passive( - false), eventQueue(NULL), heaterOnCountdown(10800000)/*about two orbits*/, parameterHelper( - this), lastAction(CLEAR) { - eventQueue = QueueFactory::instance()->createMessageQueue(); +HealthDevice(objectId, 0), internalState(STATE_OFF), switch0(switch0), switch1(switch1), + heaterOnCountdown(10800000)/*about two orbits*/, + parameterHelper(this) { + eventQueue = QueueFactory::instance()->createMessageQueue(); } Heater::~Heater() { - QueueFactory::instance()->deleteMessageQueue(eventQueue); + QueueFactory::instance()->deleteMessageQueue(eventQueue); } ReturnValue_t Heater::set() { - passive = false; - //wait for clear before doing anything - if (internalState == STATE_WAIT) { - return HasReturnvaluesIF::RETURN_OK; - } - if (healthHelper.healthTable->isHealthy(getObjectId())) { - doAction(SET); - if ((internalState == STATE_OFF) || (internalState == STATE_PASSIVE)){ - return HasReturnvaluesIF::RETURN_FAILED; - } else { - return HasReturnvaluesIF::RETURN_OK; - } - } else { - if (healthHelper.healthTable->isFaulty(getObjectId())) { - if (!reactedToBeingFaulty) { - reactedToBeingFaulty = true; - doAction(CLEAR); - } - } - return HasReturnvaluesIF::RETURN_FAILED; - } + passive = false; + //wait for clear before doing anything + if (internalState == STATE_WAIT) { + return HasReturnvaluesIF::RETURN_OK; + } + if (healthHelper.healthTable->isHealthy(getObjectId())) { + doAction(SET); + if ((internalState == STATE_OFF) || (internalState == STATE_PASSIVE)){ + return HasReturnvaluesIF::RETURN_FAILED; + } else { + return HasReturnvaluesIF::RETURN_OK; + } + } else { + if (healthHelper.healthTable->isFaulty(getObjectId())) { + if (!reactedToBeingFaulty) { + reactedToBeingFaulty = true; + doAction(CLEAR); + } + } + return HasReturnvaluesIF::RETURN_FAILED; + } } void Heater::clear(bool passive) { - this->passive = passive; - //Force switching off - if (internalState == STATE_WAIT) { - internalState = STATE_ON; - } - if (healthHelper.healthTable->isHealthy(getObjectId())) { - doAction(CLEAR); - } else if (healthHelper.healthTable->isFaulty(getObjectId())) { - if (!reactedToBeingFaulty) { - reactedToBeingFaulty = true; - doAction(CLEAR); - } - } + this->passive = passive; + //Force switching off + if (internalState == STATE_WAIT) { + internalState = STATE_ON; + } + if (healthHelper.healthTable->isHealthy(getObjectId())) { + doAction(CLEAR); + } else if (healthHelper.healthTable->isFaulty(getObjectId())) { + if (!reactedToBeingFaulty) { + reactedToBeingFaulty = true; + doAction(CLEAR); + } + } } void Heater::doAction(Action action) { - //only act if we are not in the right state or in a transition - if (action == SET) { - if ((internalState == STATE_OFF) || (internalState == STATE_PASSIVE) - || (internalState == STATE_EXTERNAL_CONTROL)) { - switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); - internalState = STATE_WAIT_FOR_SWITCHES_ON; - powerSwitcher->sendSwitchCommand(switch0, PowerSwitchIF::SWITCH_ON); - powerSwitcher->sendSwitchCommand(switch1, PowerSwitchIF::SWITCH_ON); - } - } else { //clear - if ((internalState == STATE_ON) || (internalState == STATE_FAULTY) - || (internalState == STATE_EXTERNAL_CONTROL)) { - internalState = STATE_WAIT_FOR_SWITCHES_OFF; - switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); - powerSwitcher->sendSwitchCommand(switch0, - PowerSwitchIF::SWITCH_OFF); - powerSwitcher->sendSwitchCommand(switch1, - PowerSwitchIF::SWITCH_OFF); - } - } + //only act if we are not in the right state or in a transition + if (action == SET) { + if ((internalState == STATE_OFF) || (internalState == STATE_PASSIVE) + || (internalState == STATE_EXTERNAL_CONTROL)) { + switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); + internalState = STATE_WAIT_FOR_SWITCHES_ON; + powerSwitcher->sendSwitchCommand(switch0, PowerSwitchIF::SWITCH_ON); + powerSwitcher->sendSwitchCommand(switch1, PowerSwitchIF::SWITCH_ON); + } + } else { //clear + if ((internalState == STATE_ON) || (internalState == STATE_FAULTY) + || (internalState == STATE_EXTERNAL_CONTROL)) { + internalState = STATE_WAIT_FOR_SWITCHES_OFF; + switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); + powerSwitcher->sendSwitchCommand(switch0, + PowerSwitchIF::SWITCH_OFF); + powerSwitcher->sendSwitchCommand(switch1, + PowerSwitchIF::SWITCH_OFF); + } + } } void Heater::setPowerSwitcher(PowerSwitchIF* powerSwitch) { - this->powerSwitcher = powerSwitch; + this->powerSwitcher = powerSwitch; } ReturnValue_t Heater::performOperation(uint8_t opCode) { - handleQueue(); - handleEventQueue(); + handleQueue(); + handleEventQueue(); - if (!healthHelper.healthTable->isFaulty(getObjectId())) { - reactedToBeingFaulty = false; - } + if (!healthHelper.healthTable->isFaulty(getObjectId())) { + reactedToBeingFaulty = false; + } - switch (internalState) { - case STATE_ON: - if ((powerSwitcher->getSwitchState(switch0) == PowerSwitchIF::SWITCH_OFF) - || (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_OFF)) { - //switch went off on its own - //trigger event. FDIR can confirm if it is caused by MniOps and decide on the action - //do not trigger FD events when under external control - if (healthHelper.getHealth() != EXTERNAL_CONTROL) { - triggerEvent(PowerSwitchIF::SWITCH_WENT_OFF); - } else { - internalState = STATE_EXTERNAL_CONTROL; - } - } - break; - case STATE_OFF: - //check if heater is on, ie both switches are on - //if so, just command it to off, to resolve the situation or force a switch stayed on event - //But, only do anything if not already faulty (state off is the stable point for being faulty) - if ((!healthHelper.healthTable->isFaulty(getObjectId())) - && (powerSwitcher->getSwitchState(switch0) - == PowerSwitchIF::SWITCH_ON) - && (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_ON)) { - //do not trigger FD events when under external control - if (healthHelper.getHealth() != EXTERNAL_CONTROL) { - internalState = STATE_WAIT_FOR_SWITCHES_OFF; - switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); - powerSwitcher->sendSwitchCommand(switch0, - PowerSwitchIF::SWITCH_OFF); - powerSwitcher->sendSwitchCommand(switch1, - PowerSwitchIF::SWITCH_OFF); - } else { - internalState = STATE_EXTERNAL_CONTROL; - } - } - break; - case STATE_PASSIVE: - break; - case STATE_WAIT_FOR_SWITCHES_ON: - if (switchCountdown.hasTimedOut()) { - if ((powerSwitcher->getSwitchState(switch0) - == PowerSwitchIF::SWITCH_OFF) - || (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_OFF)) { - triggerEvent(HEATER_STAYED_OFF); - internalState = STATE_WAIT_FOR_FDIR; //wait before retrying or anything - } else { - triggerEvent(HEATER_ON); - internalState = STATE_ON; - } - } - break; - case STATE_WAIT_FOR_SWITCHES_OFF: - if (switchCountdown.hasTimedOut()) { - //only check for both being on (ie heater still on) - if ((powerSwitcher->getSwitchState(switch0) - == PowerSwitchIF::SWITCH_ON) - && (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_ON)) { - if (healthHelper.healthTable->isFaulty(getObjectId())) { - if (passive) { - internalState = STATE_PASSIVE; - } else { - internalState = STATE_OFF; //just accept it - } - triggerEvent(HEATER_ON); //but throw an event to make it more visible - break; - } - triggerEvent(HEATER_STAYED_ON); - internalState = STATE_WAIT_FOR_FDIR; //wait before retrying or anything - } else { - triggerEvent(HEATER_OFF); - if (passive) { - internalState = STATE_PASSIVE; - } else { - internalState = STATE_OFF; - } - } - } - break; - default: - break; - } + switch (internalState) { + case STATE_ON: + if ((powerSwitcher->getSwitchState(switch0) == PowerSwitchIF::SWITCH_OFF) + || (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_OFF)) { + //switch went off on its own + //trigger event. FDIR can confirm if it is caused by MniOps and decide on the action + //do not trigger FD events when under external control + if (healthHelper.getHealth() != EXTERNAL_CONTROL) { + triggerEvent(PowerSwitchIF::SWITCH_WENT_OFF); + } else { + internalState = STATE_EXTERNAL_CONTROL; + } + } + break; + case STATE_OFF: + //check if heater is on, ie both switches are on + //if so, just command it to off, to resolve the situation or force a switch stayed on event + //But, only do anything if not already faulty (state off is the stable point for being faulty) + if ((!healthHelper.healthTable->isFaulty(getObjectId())) + && (powerSwitcher->getSwitchState(switch0) + == PowerSwitchIF::SWITCH_ON) + && (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_ON)) { + //do not trigger FD events when under external control + if (healthHelper.getHealth() != EXTERNAL_CONTROL) { + internalState = STATE_WAIT_FOR_SWITCHES_OFF; + switchCountdown.setTimeout(powerSwitcher->getSwitchDelayMs()); + powerSwitcher->sendSwitchCommand(switch0, + PowerSwitchIF::SWITCH_OFF); + powerSwitcher->sendSwitchCommand(switch1, + PowerSwitchIF::SWITCH_OFF); + } else { + internalState = STATE_EXTERNAL_CONTROL; + } + } + break; + case STATE_PASSIVE: + break; + case STATE_WAIT_FOR_SWITCHES_ON: + if (switchCountdown.hasTimedOut()) { + if ((powerSwitcher->getSwitchState(switch0) + == PowerSwitchIF::SWITCH_OFF) + || (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_OFF)) { + triggerEvent(HEATER_STAYED_OFF); + internalState = STATE_WAIT_FOR_FDIR; //wait before retrying or anything + } else { + triggerEvent(HEATER_ON); + internalState = STATE_ON; + } + } + break; + case STATE_WAIT_FOR_SWITCHES_OFF: + if (switchCountdown.hasTimedOut()) { + //only check for both being on (ie heater still on) + if ((powerSwitcher->getSwitchState(switch0) + == PowerSwitchIF::SWITCH_ON) + && (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_ON)) { + if (healthHelper.healthTable->isFaulty(getObjectId())) { + if (passive) { + internalState = STATE_PASSIVE; + } else { + internalState = STATE_OFF; //just accept it + } + triggerEvent(HEATER_ON); //but throw an event to make it more visible + break; + } + triggerEvent(HEATER_STAYED_ON); + internalState = STATE_WAIT_FOR_FDIR; //wait before retrying or anything + } else { + triggerEvent(HEATER_OFF); + if (passive) { + internalState = STATE_PASSIVE; + } else { + internalState = STATE_OFF; + } + } + } + break; + default: + break; + } - if ((powerSwitcher->getSwitchState(switch0) == PowerSwitchIF::SWITCH_ON) - && (powerSwitcher->getSwitchState(switch1) - == PowerSwitchIF::SWITCH_ON)) { - if (wasOn) { - if (heaterOnCountdown.hasTimedOut()) { - //SHOULDDO this means if a heater fails in single mode, the timeout will start again - //I am not sure if this is a bug, but atm I have no idea how to fix this and think - //it will be ok. whatcouldpossiblygowrong™ - if (!timedOut) { - triggerEvent(HEATER_TIMEOUT); - timedOut = true; - } - } - } else { - wasOn = true; - heaterOnCountdown.resetTimer(); - timedOut = false; - } - } else { - wasOn = false; - } + if ((powerSwitcher->getSwitchState(switch0) == PowerSwitchIF::SWITCH_ON) + && (powerSwitcher->getSwitchState(switch1) + == PowerSwitchIF::SWITCH_ON)) { + if (wasOn) { + if (heaterOnCountdown.hasTimedOut()) { + //SHOULDDO this means if a heater fails in single mode, the timeout will start again + //I am not sure if this is a bug, but atm I have no idea how to fix this and think + //it will be ok. whatcouldpossiblygowrong™ + if (!timedOut) { + triggerEvent(HEATER_TIMEOUT); + timedOut = true; + } + } + } else { + wasOn = true; + heaterOnCountdown.resetTimer(); + timedOut = false; + } + } else { + wasOn = false; + } - return HasReturnvaluesIF::RETURN_OK; + return HasReturnvaluesIF::RETURN_OK; } void Heater::setSwitch(uint8_t number, ReturnValue_t state, - uint32_t* uptimeOfSwitching) { - if (powerSwitcher == NULL) { - return; - } - if (powerSwitcher->getSwitchState(number) == state) { - *uptimeOfSwitching = INVALID_UPTIME; - } else { - if ((*uptimeOfSwitching == INVALID_UPTIME)) { - powerSwitcher->sendSwitchCommand(number, state); - Clock::getUptime(uptimeOfSwitching); - } else { - uint32_t currentUptime; - Clock::getUptime(¤tUptime); - if (currentUptime - *uptimeOfSwitching - > powerSwitcher->getSwitchDelayMs()) { - *uptimeOfSwitching = INVALID_UPTIME; - if (healthHelper.healthTable->isHealthy(getObjectId())) { - if (state == PowerSwitchIF::SWITCH_ON) { - triggerEvent(HEATER_STAYED_OFF); - } else { - triggerEvent(HEATER_STAYED_ON); - } - } - //SHOULDDO MiniOps during switch timeout leads to a faulty switch - } - } - } + uint32_t* uptimeOfSwitching) { + if (powerSwitcher == NULL) { + return; + } + if (powerSwitcher->getSwitchState(number) == state) { + *uptimeOfSwitching = INVALID_UPTIME; + } else { + if ((*uptimeOfSwitching == INVALID_UPTIME)) { + powerSwitcher->sendSwitchCommand(number, state); + Clock::getUptime(uptimeOfSwitching); + } else { + uint32_t currentUptime; + Clock::getUptime(¤tUptime); + if (currentUptime - *uptimeOfSwitching + > powerSwitcher->getSwitchDelayMs()) { + *uptimeOfSwitching = INVALID_UPTIME; + if (healthHelper.healthTable->isHealthy(getObjectId())) { + if (state == PowerSwitchIF::SWITCH_ON) { + triggerEvent(HEATER_STAYED_OFF); + } else { + triggerEvent(HEATER_STAYED_ON); + } + } + } + } + } } MessageQueueId_t Heater::getCommandQueue() const { - return commandQueue->getId(); + return commandQueue->getId(); } ReturnValue_t Heater::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + ReturnValue_t result = SystemObject::initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - EventManagerIF* manager = objectManager->get( - objects::EVENT_MANAGER); - if (manager == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - result = manager->registerListener(eventQueue->getId()); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + EventManagerIF* manager = objectManager->get( + objects::EVENT_MANAGER); + if (manager == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + result = manager->registerListener(eventQueue->getId()); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - ConfirmsFailuresIF* pcdu = objectManager->get( - DeviceHandlerFailureIsolation::powerConfirmationId); - if (pcdu == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - pcduQueueId = pcdu->getEventReceptionQueue(); + ConfirmsFailuresIF* pcdu = objectManager->get( + DeviceHandlerFailureIsolation::powerConfirmationId); + if (pcdu == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + pcduQueueId = pcdu->getEventReceptionQueue(); - result = manager->subscribeToAllEventsFrom(eventQueue->getId(), - getObjectId()); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + result = manager->subscribeToAllEventsFrom(eventQueue->getId(), + getObjectId()); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - result = parameterHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + result = parameterHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - result = healthHelper.initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + result = healthHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - return HasReturnvaluesIF::RETURN_OK; + return HasReturnvaluesIF::RETURN_OK; } void Heater::handleQueue() { - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - result = healthHelper.handleHealthCommand(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - parameterHelper.handleParameterMessage(&command); - } + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + result = healthHelper.handleHealthCommand(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + result = parameterHelper.handleParameterMessage(&command); + if (result == HasReturnvaluesIF::RETURN_OK) { + return; + } + } } ReturnValue_t Heater::getParameter(uint8_t domainId, uint8_t uniqueId, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, - uint16_t startAtIndex) { - if (domainId != DOMAIN_ID_BASE) { - return INVALID_DOMAIN_ID; - } - switch (uniqueId) { - case 0: - parameterWrapper->set(heaterOnCountdown.timeout); - break; - default: - return INVALID_IDENTIFIER_ID; - } - return HasReturnvaluesIF::RETURN_OK; + uint16_t startAtIndex) { + if (domainId != DOMAIN_ID_BASE) { + return INVALID_DOMAIN_ID; + } + switch (uniqueId) { + case 0: + parameterWrapper->set(heaterOnCountdown.timeout); + break; + default: + return INVALID_IDENTIFIER_ID; + } + return HasReturnvaluesIF::RETURN_OK; } void Heater::handleEventQueue() { - EventMessage event; - for (ReturnValue_t result = eventQueue->receiveMessage(&event); - result == HasReturnvaluesIF::RETURN_OK; - result = eventQueue->receiveMessage(&event)) { - switch (event.getMessageId()) { - case EventMessage::EVENT_MESSAGE: - switch (event.getEvent()) { - case Fuse::FUSE_WENT_OFF: - case HEATER_STAYED_OFF: - case HEATER_STAYED_ON://Setting it faulty does not help, but we need to reach a stable state and can check for being faulty before throwing this event again. - if (healthHelper.healthTable->isCommandable(getObjectId())) { - healthHelper.setHealth(HasHealthIF::FAULTY); - internalState = STATE_FAULTY; - } - break; - case PowerSwitchIF::SWITCH_WENT_OFF: - internalState = STATE_WAIT; - event.setMessageId(EventMessage::CONFIRMATION_REQUEST); - if (pcduQueueId != 0) { - eventQueue->sendMessage(pcduQueueId, &event); - } else { - healthHelper.setHealth(HasHealthIF::FAULTY); - internalState = STATE_FAULTY; - } - break; - default: - return; - } - break; - case EventMessage::YOUR_FAULT: - healthHelper.setHealth(HasHealthIF::FAULTY); - internalState = STATE_FAULTY; - break; - case EventMessage::MY_FAULT: - //do nothing, we are already in STATE_WAIT and wait for a clear() - break; - default: - return; - } - } + EventMessage event; + for (ReturnValue_t result = eventQueue->receiveMessage(&event); + result == HasReturnvaluesIF::RETURN_OK; + result = eventQueue->receiveMessage(&event)) { + switch (event.getMessageId()) { + case EventMessage::EVENT_MESSAGE: + switch (event.getEvent()) { + case Fuse::FUSE_WENT_OFF: + case HEATER_STAYED_OFF: + // HEATER_STAYED_ON is a setting if faulty does not help, but we need to reach a stable state and can check + // for being faulty before throwing this event again. + case HEATER_STAYED_ON: + if (healthHelper.healthTable->isCommandable(getObjectId())) { + healthHelper.setHealth(HasHealthIF::FAULTY); + internalState = STATE_FAULTY; + } + break; + case PowerSwitchIF::SWITCH_WENT_OFF: + internalState = STATE_WAIT; + event.setMessageId(EventMessage::CONFIRMATION_REQUEST); + if (pcduQueueId != 0) { + eventQueue->sendMessage(pcduQueueId, &event); + } else { + healthHelper.setHealth(HasHealthIF::FAULTY); + internalState = STATE_FAULTY; + } + break; + default: + return; + } + break; + case EventMessage::YOUR_FAULT: + healthHelper.setHealth(HasHealthIF::FAULTY); + internalState = STATE_FAULTY; + break; + case EventMessage::MY_FAULT: + //do nothing, we are already in STATE_WAIT and wait for a clear() + break; + default: + return; + } + } } diff --git a/thermal/Heater.h b/thermal/Heater.h index f83957a2e..2caddd852 100644 --- a/thermal/Heater.h +++ b/thermal/Heater.h @@ -1,90 +1,93 @@ -#ifndef FRAMEWORK_THERMAL_HEATER_H_ -#define FRAMEWORK_THERMAL_HEATER_H_ +#ifndef FSFW_THERMAL_HEATER_H_ +#define FSFW_THERMAL_HEATER_H_ #include "../devicehandlers/HealthDevice.h" #include "../parameters/ParameterHelper.h" #include "../power/PowerSwitchIF.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../timemanager/Countdown.h" -#include -//class RedundantHeater; +#include + class Heater: public HealthDevice, public ReceivesParameterMessagesIF { - friend class RedundantHeater; + friend class RedundantHeater; public: - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HEATER; - static const Event HEATER_ON = MAKE_EVENT(0, severity::INFO); - static const Event HEATER_OFF = MAKE_EVENT(1, severity::INFO); - static const Event HEATER_TIMEOUT = MAKE_EVENT(2, severity::LOW); - static const Event HEATER_STAYED_ON = MAKE_EVENT(3, severity::LOW); - static const Event HEATER_STAYED_OFF = MAKE_EVENT(4, severity::LOW); + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HEATER; + static const Event HEATER_ON = MAKE_EVENT(0, severity::INFO); + static const Event HEATER_OFF = MAKE_EVENT(1, severity::INFO); + static const Event HEATER_TIMEOUT = MAKE_EVENT(2, severity::LOW); + static const Event HEATER_STAYED_ON = MAKE_EVENT(3, severity::LOW); + static const Event HEATER_STAYED_OFF = MAKE_EVENT(4, severity::LOW); - Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1); - virtual ~Heater(); + Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1); + virtual ~Heater(); - ReturnValue_t performOperation(uint8_t opCode); + ReturnValue_t performOperation(uint8_t opCode); - ReturnValue_t initialize(); + ReturnValue_t initialize(); - ReturnValue_t set(); - void clear(bool passive); + ReturnValue_t set(); + void clear(bool passive); - void setPowerSwitcher(PowerSwitchIF *powerSwitch); + void setPowerSwitcher(PowerSwitchIF *powerSwitch); - MessageQueueId_t getCommandQueue() const; + MessageQueueId_t getCommandQueue() const; - ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); + ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); protected: - static const uint32_t INVALID_UPTIME = 0; + static const uint32_t INVALID_UPTIME = 0; - enum InternalState { - STATE_ON, - STATE_OFF, - STATE_PASSIVE, - STATE_WAIT_FOR_SWITCHES_ON, - STATE_WAIT_FOR_SWITCHES_OFF, - STATE_WAIT_FOR_FDIR, //used to avoid doing anything until fdir decided what to do - STATE_FAULTY, - STATE_WAIT, //used when waiting for system to recover from miniops - STATE_EXTERNAL_CONTROL //entered when under external control and a fdir reaction would be triggered. This is useful when leaving external control into an unknown state - //if no fdir reaction is triggered under external control the state is still ok and no need for any special treatment is needed - } internalState; + enum InternalState { + STATE_ON, + STATE_OFF, + STATE_PASSIVE, + STATE_WAIT_FOR_SWITCHES_ON, + STATE_WAIT_FOR_SWITCHES_OFF, + STATE_WAIT_FOR_FDIR, // Used to avoid doing anything until fdir decided what to do + STATE_FAULTY, + STATE_WAIT, // Used when waiting for system to recover from miniops + // Entered when under external control and a fdir reaction would be triggered. + // This is useful when leaving external control into an unknown state + STATE_EXTERNAL_CONTROL + // If no fdir reaction is triggered under external control the state is still ok and + // no need for any special treatment is needed + } internalState; - PowerSwitchIF *powerSwitcher; - MessageQueueId_t pcduQueueId; + PowerSwitchIF *powerSwitcher = nullptr; + MessageQueueId_t pcduQueueId = MessageQueueIF::NO_QUEUE; - uint8_t switch0; - uint8_t switch1; + uint8_t switch0; + uint8_t switch1; - bool wasOn; + bool wasOn = false; - bool timedOut; + bool timedOut = false; - bool reactedToBeingFaulty; + bool reactedToBeingFaulty = false; - bool passive; + bool passive = false; - MessageQueueIF* eventQueue; - Countdown heaterOnCountdown; - Countdown switchCountdown; - ParameterHelper parameterHelper; + MessageQueueIF* eventQueue = nullptr; + Countdown heaterOnCountdown; + Countdown switchCountdown; + ParameterHelper parameterHelper; - enum Action { - SET, CLEAR - } lastAction; + enum Action { + SET, CLEAR + } lastAction = CLEAR; - void doAction(Action action); + void doAction(Action action); - void setSwitch(uint8_t number, ReturnValue_t state, - uint32_t *upTimeOfSwitching); + void setSwitch(uint8_t number, ReturnValue_t state, + uint32_t *upTimeOfSwitching); - void handleQueue(); + void handleQueue(); - void handleEventQueue(); + void handleEventQueue(); }; -#endif /* FRAMEWORK_THERMAL_HEATER_H_ */ +#endif /* FSFW_THERMAL_HEATER_H_ */ diff --git a/thermal/TemperatureSensor.h b/thermal/TemperatureSensor.h index 2b1fb1f07..c7b9d771b 100644 --- a/thermal/TemperatureSensor.h +++ b/thermal/TemperatureSensor.h @@ -1,11 +1,14 @@ -#ifndef TEMPERATURESENSOR_H_ -#define TEMPERATURESENSOR_H_ +#ifndef FSFW_THERMAL_TEMPERATURESENSOR_H_ +#define FSFW_THERMAL_TEMPERATURESENSOR_H_ -#include "../thermal/AbstractTemperatureSensor.h" -#include "../datapoolglob/GlobalDataSet.h" -#include "../datapoolglob/GlobalPoolVariable.h" +#include "tcsDefinitions.h" +#include "AbstractTemperatureSensor.h" + +#include "../datapoollocal/LocalPoolDataSetBase.h" +#include "../datapoollocal/LocalPoolVariable.h" #include "../monitoring/LimitMonitor.h" + /** * @brief This building block handles non-linear value conversion and * range checks for analog temperature sensors. @@ -57,27 +60,25 @@ public: /** * Instantiate Temperature Sensor Object. - * @param setObjectid objectId of the sensor object - * @param inputValue Input value which is converted to a temperature - * @param poolVariable Pool Variable to store the temperature value - * @param vectorIndex Vector Index for the sensor monitor - * @param parameters Calculation parameters, temperature limits, gradient limit - * @param datapoolId Datapool ID of the output temperature - * @param outputSet Output dataset for the output temperature to fetch it with read() - * @param thermalModule respective thermal module, if it has one + * @param setObjectid objectId of the sensor object + * @param inputTemperature Pointer to a raw input value which is converted to an floating + * point C output temperature + * @param outputGpid Global Pool ID of the output value + * @param vectorIndex Vector Index for the sensor monitor + * @param parameters Calculation parameters, temperature limits, gradient limit + * @param outputSet Output dataset for the output temperature to fetch it with read() + * @param thermalModule Respective thermal module, if it has one */ - TemperatureSensor(object_id_t setObjectid, - inputType *inputValue, PoolVariableIF *poolVariable, - uint8_t vectorIndex, uint32_t datapoolId, Parameters parameters = {0, 0, 0, 0, 0, 0}, - GlobDataSet *outputSet = NULL, ThermalModuleIF *thermalModule = NULL) : + TemperatureSensor(object_id_t setObjectid,lp_var_t* inputTemperature, + gp_id_t outputGpid, uint8_t vectorIndex, Parameters parameters = {0, 0, 0, 0, 0, 0}, + LocalPoolDataSetBase *outputSet = nullptr, ThermalModuleIF *thermalModule = nullptr) : AbstractTemperatureSensor(setObjectid, thermalModule), parameters(parameters), - inputValue(inputValue), poolVariable(poolVariable), - outputTemperature(datapoolId, outputSet, PoolVariableIF::VAR_WRITE), - sensorMonitor(setObjectid, DOMAIN_ID_SENSOR, - GlobalDataPool::poolIdAndPositionToPid(poolVariable->getDataPoolId(), vectorIndex), + inputTemperature(inputTemperature), + outputTemperature(outputGpid, outputSet, PoolVariableIF::VAR_WRITE), + sensorMonitor(setObjectid, DOMAIN_ID_SENSOR, outputGpid, DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, parameters.upperLimit, TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), - oldTemperature(20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) { + oldTemperature(20), uptimeOfOldTemperature({ thermal::INVALID_TEMPERATURE, 0 }) { } @@ -98,7 +99,7 @@ protected: private: void setInvalid() { - outputTemperature = INVALID_TEMPERATURE; + outputTemperature = thermal::INVALID_TEMPERATURE; outputTemperature.setValid(false); uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; sensorMonitor.setToInvalid(); @@ -108,11 +109,8 @@ protected: UsedParameters parameters; - inputType * inputValue; - - PoolVariableIF *poolVariable; - - gp_float_t outputTemperature; + lp_var_t* inputTemperature; + lp_var_t outputTemperature; LimitMonitor sensorMonitor; @@ -120,22 +118,27 @@ protected: timeval uptimeOfOldTemperature; void doChildOperation() { - if (!poolVariable->isValid() - || !healthHelper.healthTable->isHealthy(getObjectId())) { + ReturnValue_t result = inputTemperature->read(MutexIF::TimeoutType::WAITING, 20); + if(result != HasReturnvaluesIF::RETURN_OK) { + return; + } + + if ((not inputTemperature->isValid()) or + (not healthHelper.healthTable->isHealthy(getObjectId()))) { setInvalid(); return; } - outputTemperature = calculateOutputTemperature(*inputValue); + outputTemperature = calculateOutputTemperature(inputTemperature->value); outputTemperature.setValid(PoolVariableIF::VALID); timeval uptime; Clock::getUptime(&uptime); if (uptimeOfOldTemperature.tv_sec != INVALID_UPTIME) { - //In theory, we could use an AbsValueMonitor to monitor the gradient. - //But this would require storing the maxGradient in DP and quite some overhead. - //The concept of delta limits is a bit strange anyway. + // In theory, we could use an AbsValueMonitor to monitor the gradient. + // But this would require storing the maxGradient in DP and quite some overhead. + // The concept of delta limits is a bit strange anyway. float deltaTime; float deltaTemp; @@ -148,17 +151,17 @@ protected: } if (parameters.gradient < deltaTemp / deltaTime) { triggerEvent(TEMP_SENSOR_GRADIENT); - //Don't set invalid, as we did not recognize it as invalid with full authority, let FDIR handle it + // Don't set invalid, as we did not recognize it as invalid with full authority, + // let FDIR handle it } } - //Check is done against raw limits. SHOULDDO: Why? Using �C would be more easy to handle. sensorMonitor.doCheck(outputTemperature.value); if (sensorMonitor.isOutOfLimits()) { uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; outputTemperature.setValid(PoolVariableIF::INVALID); - outputTemperature = INVALID_TEMPERATURE; + outputTemperature = thermal::INVALID_TEMPERATURE; } else { oldTemperature = outputTemperature; uptimeOfOldTemperature = uptime; @@ -179,7 +182,10 @@ public: static const uint16_t ADDRESS_C = 2; static const uint16_t ADDRESS_GRADIENT = 3; - static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.) + //! Changed due to issue with later temperature checking even tough the sensor monitor was + //! confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. + //! Chosen rather large, should not be so bad for components and helps survive glitches.) + static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; static const uint8_t DOMAIN_ID_SENSOR = 1; @@ -219,4 +225,4 @@ public: }; -#endif /* TEMPERATURESENSOR_H_ */ +#endif /* FSFW_THERMAL_TEMPERATURESENSOR_H_ */ diff --git a/timemanager/TimeMessage.cpp b/timemanager/TimeMessage.cpp index a1042efe5..66aea0f4d 100644 --- a/timemanager/TimeMessage.cpp +++ b/timemanager/TimeMessage.cpp @@ -25,6 +25,6 @@ uint32_t TimeMessage::getCounterValue() { return temp; } -size_t TimeMessage::getMinimumMessageSize() { +size_t TimeMessage::getMinimumMessageSize() const { return this->MAX_SIZE; } diff --git a/timemanager/TimeMessage.h b/timemanager/TimeMessage.h index f5ac3e14d..00778fb7f 100644 --- a/timemanager/TimeMessage.h +++ b/timemanager/TimeMessage.h @@ -11,7 +11,7 @@ protected: * @brief This call always returns the same fixed size of the message. * @return Returns HEADER_SIZE + \c sizeof(timeval) + sizeof(uint32_t). */ - size_t getMinimumMessageSize(); + size_t getMinimumMessageSize() const override; public: /** diff --git a/tmtcservices/TmTcBridge.cpp b/tmtcservices/TmTcBridge.cpp index 12d163d16..dcffac41e 100644 --- a/tmtcservices/TmTcBridge.cpp +++ b/tmtcservices/TmTcBridge.cpp @@ -4,6 +4,8 @@ #include "../serviceinterface/ServiceInterface.h" #include "../globalfunctions/arrayprinter.h" +#define TMTCBRIDGE_WIRETAPPING 0 + TmTcBridge::TmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId): SystemObject(objectId),tmStoreId(tmStoreId), tcStoreId(tcStoreId), @@ -14,7 +16,9 @@ TmTcBridge::TmTcBridge(object_id_t objectId, object_id_t tcDestination, createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH); } -TmTcBridge::~TmTcBridge() {} +TmTcBridge::~TmTcBridge() { + QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); +} ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle( uint8_t sentPacketsPerCycle) { @@ -173,6 +177,9 @@ ReturnValue_t TmTcBridge::handleTmQueue() { ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) { store_address_t storeId = 0; + if(tmFifo == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } if(tmFifo->full()) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -231,17 +238,11 @@ ReturnValue_t TmTcBridge::handleStoredTm() { void TmTcBridge::registerCommConnect() { if(not communicationLinkUp) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - //sif::info << "TMTC Bridge: Registered Comm Link Connect" << std::endl; -#endif communicationLinkUp = true; } } void TmTcBridge::registerCommDisconnect() { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - //sif::info << "TMTC Bridge: Registered Comm Link Disconnect" << std::endl; -#endif if(communicationLinkUp) { communicationLinkUp = false; } diff --git a/unittest/tests/action/TestActionHelper.cpp b/unittest/tests/action/TestActionHelper.cpp index a7adfc82d..d8bd58c99 100644 --- a/unittest/tests/action/TestActionHelper.cpp +++ b/unittest/tests/action/TestActionHelper.cpp @@ -70,7 +70,7 @@ TEST_CASE( "Action Helper" , "[ActionHelper]") { SECTION("Handle finish"){ CHECK(not testMqMock.wasMessageSent()); ReturnValue_t status = 0x9876; - actionHelper.finish(true, testMqMock.getId(), testActionId, status); + actionHelper.finish(false, testMqMock.getId(), testActionId, status); CHECK(testMqMock.wasMessageSent()); CommandMessage testMessage; REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); diff --git a/unittest/tests/datapoollocal/CMakeLists.txt b/unittest/tests/datapoollocal/CMakeLists.txt index f196a080a..1c98e7dc2 100644 --- a/unittest/tests/datapoollocal/CMakeLists.txt +++ b/unittest/tests/datapoollocal/CMakeLists.txt @@ -3,4 +3,5 @@ target_sources(${TARGET_NAME} PRIVATE LocalPoolVectorTest.cpp DataSetTest.cpp LocalPoolManagerTest.cpp + LocalPoolOwnerBase.cpp ) diff --git a/unittest/tests/datapoollocal/DataSetTest.cpp b/unittest/tests/datapoollocal/DataSetTest.cpp index 561345951..d0b13e86f 100644 --- a/unittest/tests/datapoollocal/DataSetTest.cpp +++ b/unittest/tests/datapoollocal/DataSetTest.cpp @@ -4,13 +4,14 @@ #include #include +#include #include -#include +#include #include #include -TEST_CASE("LocalDataSet" , "[LocDataSetTest]") { +TEST_CASE("DataSetTest" , "[DataSetTest]") { LocalPoolOwnerBase* poolOwner = objectManager-> get(objects::TEST_LOCAL_POOL_OWNER_BASE); REQUIRE(poolOwner != nullptr); @@ -21,6 +22,7 @@ TEST_CASE("LocalDataSet" , "[LocDataSetTest]") { SECTION("BasicTest") { /* Test some basic functions */ + CHECK(localSet.getReportingEnabled() == false); CHECK(localSet.getLocalPoolIdsSerializedSize(false) == 3 * sizeof(lp_id_t)); CHECK(localSet.getLocalPoolIdsSerializedSize(true) == 3 * sizeof(lp_id_t) + sizeof(uint8_t)); @@ -54,7 +56,7 @@ TEST_CASE("LocalDataSet" , "[LocDataSetTest]") { { /* Test read operation. Values should be all zeros */ - PoolReadHelper readHelper(&localSet); + PoolReadGuard readHelper(&localSet); REQUIRE(readHelper.getReadResult() == retval::CATCH_OK); CHECK(not localSet.isValid()); CHECK(localSet.localPoolVarUint8.value == 0); @@ -79,10 +81,15 @@ TEST_CASE("LocalDataSet" , "[LocDataSetTest]") { localSet.localPoolVarUint8 = 0; localSet.localPoolVarFloat = 0; + localSet.setAllVariablesReadOnly(); + CHECK(localSet.localPoolUint16Vec.getReadWriteMode() == pool_rwm_t::VAR_READ); + CHECK(localSet.localPoolVarUint8.getReadWriteMode() == pool_rwm_t::VAR_READ); + CHECK(localSet.localPoolVarFloat.getReadWriteMode() == pool_rwm_t::VAR_READ); + { /* Now we read again and check whether our zeroed values were overwritten with the values in the pool */ - PoolReadHelper readHelper(&localSet); + PoolReadGuard readHelper(&localSet); REQUIRE(readHelper.getReadResult() == retval::CATCH_OK); CHECK(localSet.isValid()); CHECK(localSet.localPoolVarUint8.value == 232); @@ -201,6 +208,75 @@ TEST_CASE("LocalDataSet" , "[LocDataSetTest]") { } + SECTION("MorePoolVariables") { + LocalDataSet set(poolOwner, 2, 10); + + /* Register same variables again to get more than 8 registered variables */ + for(uint8_t idx = 0; idx < 8; idx ++) { + REQUIRE(set.registerVariable(&localSet.localPoolVarUint8) == retval::CATCH_OK); + } + REQUIRE(set.registerVariable(&localSet.localPoolVarUint8) == retval::CATCH_OK); + REQUIRE(set.registerVariable(&localSet.localPoolUint16Vec) == retval::CATCH_OK); + + set.setValidityBufferGeneration(true); + { + PoolReadGuard readHelper(&localSet); + localSet.localPoolVarUint8.value = 42; + localSet.localPoolVarUint8.setValid(true); + localSet.localPoolUint16Vec.setValid(false); + } + + size_t maxSize = set.getSerializedSize(); + CHECK(maxSize == 9 + sizeof(uint16_t) * 3 + 2); + size_t serSize = 0; + /* Already reserve additional space for validity buffer, will be needed later */ + uint8_t buffer[maxSize + 1]; + uint8_t* buffPtr = buffer; + CHECK(set.serialize(&buffPtr, &serSize, maxSize, + SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + std::array validityBuffer; + std::memcpy(validityBuffer.data(), buffer + 9 + sizeof(uint16_t) * 3, 2); + /* The first 9 variables should be valid */ + CHECK(validityBuffer[0] == 0xff); + CHECK(bitutil::bitGet(validityBuffer.data() + 1, 0) == true); + CHECK(bitutil::bitGet(validityBuffer.data() + 1, 1) == false); + + /* Now we invert the validity */ + validityBuffer[0] = 0; + validityBuffer[1] = 0b0100'0000; + std::memcpy(buffer + 9 + sizeof(uint16_t) * 3, validityBuffer.data(), 2); + const uint8_t* constBuffPtr = buffer; + size_t sizeToDeSerialize = serSize; + CHECK(set.deSerialize(&constBuffPtr, &sizeToDeSerialize, SerializeIF::Endianness::MACHINE) + == retval::CATCH_OK); + CHECK(localSet.localPoolVarUint8.isValid() == false); + CHECK(localSet.localPoolUint16Vec.isValid() == true); + } + + SECTION("SharedDataSet") { + object_id_t sharedSetId = objects::SHARED_SET_ID; + SharedLocalDataSet sharedSet(sharedSetId, poolOwner, lpool::testSetId, 5); + localSet.localPoolVarUint8.setReadWriteMode(pool_rwm_t::VAR_WRITE); + localSet.localPoolUint16Vec.setReadWriteMode(pool_rwm_t::VAR_WRITE); + CHECK(sharedSet.registerVariable(&localSet.localPoolVarUint8) == retval::CATCH_OK); + CHECK(sharedSet.registerVariable(&localSet.localPoolUint16Vec) == retval::CATCH_OK); + CHECK(sharedSet.initialize() == retval::CATCH_OK); + CHECK(sharedSet.lockDataset() == retval::CATCH_OK); + CHECK(sharedSet.unlockDataset() == retval::CATCH_OK); + + { + //PoolReadGuard rg(&sharedSet); + //CHECK(rg.getReadResult() == retval::CATCH_OK); + localSet.localPoolVarUint8.value = 5; + localSet.localPoolUint16Vec.value[0] = 1; + localSet.localPoolUint16Vec.value[1] = 2; + localSet.localPoolUint16Vec.value[2] = 3; + CHECK(sharedSet.commit() == retval::CATCH_OK); + } + + sharedSet.setReadCommitProtectionBehaviour(true); + } + /* we need to reset the subscription list because the pool owner is a global object. */ CHECK(poolOwner->reset() == retval::CATCH_OK); diff --git a/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp b/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp index a10b44999..52485b011 100644 --- a/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp +++ b/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -20,14 +20,21 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() == retval::CATCH_OK); - //REQUIRE(poolOwner->dataset.assignPointers() == retval::CATCH_OK); + MessageQueueMockBase* mqMock = poolOwner->getMockQueueHandle(); REQUIRE(mqMock != nullptr); CommandMessage messageSent; uint8_t messagesSent = 0; - SECTION("BasicTest") { + { + /* For code coverage, should not crash */ + LocalDataPoolManager manager(nullptr, nullptr); + } + auto owner = poolOwner->poolManager.getOwner(); + REQUIRE(owner != nullptr); + CHECK(owner->getObjectId() == objects::TEST_LOCAL_POOL_OWNER_BASE); + /* Subscribe for message generation on update. */ REQUIRE(poolOwner->subscribeWrapperSetUpdate() == retval::CATCH_OK); /* Subscribe for an update message. */ @@ -72,10 +79,10 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { } - SECTION("SnapshotUpdateTests") { + SECTION("SetSnapshotUpdateTest") { /* Set the variables in the set to certain values. These are checked later. */ { - PoolReadHelper readHelper(&poolOwner->dataset); + PoolReadGuard readHelper(&poolOwner->dataset); REQUIRE(readHelper.getReadResult() == retval::CATCH_OK); poolOwner->dataset.localPoolVarUint8.value = 5; poolOwner->dataset.localPoolVarFloat.value = -12.242; @@ -137,7 +144,69 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(1)); } - SECTION("AdvancedTests") { + SECTION("VariableSnapshotTest") { + /* Acquire subscription interface */ + ProvidesDataPoolSubscriptionIF* subscriptionIF = poolOwner->getSubscriptionInterface(); + REQUIRE(subscriptionIF != nullptr); + + /* Subscribe for variable snapshot */ + REQUIRE(poolOwner->subscribeWrapperVariableSnapshot(lpool::uint8VarId) == retval::CATCH_OK); + auto poolVar = dynamic_cast*>( + poolOwner->getPoolObjectHandle(lpool::uint8VarId)); + REQUIRE(poolVar != nullptr); + + { + PoolReadGuard rg(poolVar); + CHECK(rg.getReadResult() == retval::CATCH_OK); + poolVar->value = 25; + } + + poolVar->setChanged(true); + + /* Store current time, we are going to check the (approximate) time equality later */ + CCSDSTime::CDS_short timeCdsNow; + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::convertToCcsds(&timeCdsNow, &now); + + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + + /* Check update snapshot was sent. */ + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + + /* Should have been reset. */ + CHECK(poolVar->hasChanged() == false); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE)); + /* Now we deserialize the snapshot into a new dataset instance */ + CCSDSTime::CDS_short cdsShort; + lp_var_t varCopy = lp_var_t(lpool::uint8VarGpid); + HousekeepingSnapshot snapshot(&cdsShort, &varCopy); + store_address_t storeId; + HousekeepingMessage::getUpdateSnapshotVariableCommand(&messageSent, &storeId); + ConstAccessorPair accessorPair = tglob::getIpcStoreHandle()->getData(storeId); + REQUIRE(accessorPair.first == retval::CATCH_OK); + const uint8_t* readOnlyPtr = accessorPair.second.data(); + size_t sizeToDeserialize = accessorPair.second.size(); + CHECK(varCopy.value == 0); + /* Fill the dataset and timestamp */ + REQUIRE(snapshot.deSerialize(&readOnlyPtr, &sizeToDeserialize, + SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + CHECK(varCopy.value == 25); + + /* Now we check that both times are equal */ + CHECK(cdsShort.pField == timeCdsNow.pField); + CHECK(cdsShort.dayLSB == Catch::Approx(timeCdsNow.dayLSB).margin(1)); + CHECK(cdsShort.dayMSB == Catch::Approx(timeCdsNow.dayMSB).margin(1)); + CHECK(cdsShort.msDay_h == Catch::Approx(timeCdsNow.msDay_h).margin(1)); + CHECK(cdsShort.msDay_hh == Catch::Approx(timeCdsNow.msDay_hh).margin(1)); + CHECK(cdsShort.msDay_l == Catch::Approx(timeCdsNow.msDay_l).margin(1)); + CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(1)); + } + + SECTION("VariableNotificationTest") { /* Acquire subscription interface */ ProvidesDataPoolSubscriptionIF* subscriptionIF = poolOwner->getSubscriptionInterface(); REQUIRE(subscriptionIF != nullptr); @@ -149,6 +218,7 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { poolOwner->getPoolObjectHandle(lpool::uint8VarId)); REQUIRE(poolVar != nullptr); poolVar->setChanged(true); + REQUIRE(poolVar->hasChanged() == true); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); /* Check update notification was sent. */ @@ -190,6 +260,164 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { REQUIRE(mqMock->receiveMessage(&messageSent) == static_cast(MessageQueueIF::EMPTY)); } + SECTION("PeriodicHKAndMessaging") { + /* Now we subcribe for a HK periodic generation. Even when it's difficult to simulate + the temporal behaviour correctly the HK manager should generate a HK packet + immediately and the periodic helper depends on HK op function calls anyway instead of + using the clock, so we could also just call performHkOperation multiple times */ + REQUIRE(poolOwner->subscribePeriodicHk(true) == retval::CATCH_OK); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + /* Now HK packet should be sent as message immediately. */ + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + LocalPoolDataSetBase* setHandle = poolOwner->getDataSetHandle(lpool::testSid); + REQUIRE(setHandle != nullptr); + CHECK(poolOwner->poolManager.generateHousekeepingPacket(lpool::testSid, + setHandle, false) == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + CHECK(setHandle->getReportingEnabled() == true); + CommandMessage hkCmd; + HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + CHECK(setHandle->getReportingEnabled() == false); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, false); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + CHECK(setHandle->getReportingEnabled() == true); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + CHECK(setHandle->getReportingEnabled() == false); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, + lpool::testSid, 0.4, false); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + /* For non-diagnostics and a specified minimum frequency of 0.2 seconds, the + resulting collection interval should be 1.0 second */ + CHECK(poolOwner->dataset.getCollectionInterval() == 1.0); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + /* Now HK packet should be sent as message. */ + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setUpdateNotificationSetCommand(&hkCmd, lpool::testSid); + sid_t sidToCheck; + store_address_t storeId; + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + CHECK(poolOwner->changedDataSetCallbackWasCalled(sidToCheck, storeId) == true); + CHECK(sidToCheck == lpool::testSid); + + /* Now we test the handling is the dataset is set to diagnostic */ + poolOwner->dataset.setDiagnostic(true); + + HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == + static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); + /* We still expect a failure message being sent */ + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, + lpool::testSid, 0.4, false); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == + static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == + static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, true); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4, + true); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, true); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, true); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == + static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, true); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + CHECK(mqMock->popMessage() == retval::CATCH_OK); + + HousekeepingMessage::setUpdateNotificationVariableCommand(&hkCmd, lpool::uint8VarGpid); + gp_id_t gpidToCheck; + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + CHECK(poolOwner->changedVariableCallbackWasCalled(gpidToCheck, storeId) == true); + CHECK(gpidToCheck == lpool::uint8VarGpid); + + HousekeepingMessage::setUpdateSnapshotSetCommand(&hkCmd, lpool::testSid, + storeId::INVALID_STORE_ADDRESS); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + CHECK(poolOwner->changedDataSetCallbackWasCalled(sidToCheck, storeId) == true); + CHECK(sidToCheck == lpool::testSid); + + HousekeepingMessage::setUpdateSnapshotVariableCommand(&hkCmd, lpool::uint8VarGpid, + storeId::INVALID_STORE_ADDRESS); + CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); + CHECK(poolOwner->changedVariableCallbackWasCalled(gpidToCheck, storeId) == true); + CHECK(gpidToCheck == lpool::uint8VarGpid); + + poolOwner->poolManager.printPoolEntry(lpool::uint8VarId); + + } + /* we need to reset the subscription list because the pool owner is a global object. */ CHECK(poolOwner->reset() == retval::CATCH_OK); diff --git a/unittest/tests/datapoollocal/LocalPoolOwnerBase.cpp b/unittest/tests/datapoollocal/LocalPoolOwnerBase.cpp new file mode 100644 index 000000000..991314a9d --- /dev/null +++ b/unittest/tests/datapoollocal/LocalPoolOwnerBase.cpp @@ -0,0 +1,141 @@ +#include "LocalPoolOwnerBase.h" + +LocalPoolOwnerBase::LocalPoolOwnerBase(object_id_t objectId): + SystemObject(objectId), poolManager(this, messageQueue), + dataset(this, lpool::testSetId) { + messageQueue = new MessageQueueMockBase(); +} + +LocalPoolOwnerBase::~LocalPoolOwnerBase() { + QueueFactory::instance()->deleteMessageQueue(messageQueue); +} + +ReturnValue_t LocalPoolOwnerBase::initializeHkManager() { + if(not initialized) { + initialized = true; + return poolManager.initialize(messageQueue); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalPoolOwnerBase::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) { + + // Default initialization empty for now. + localDataPoolMap.emplace(lpool::uint8VarId, + new PoolEntry({0})); + localDataPoolMap.emplace(lpool::floatVarId, + new PoolEntry({0})); + localDataPoolMap.emplace(lpool::uint32VarId, + new PoolEntry({0})); + + localDataPoolMap.emplace(lpool::uint16Vec3Id, + new PoolEntry({0, 0, 0})); + localDataPoolMap.emplace(lpool::int64Vec2Id, + new PoolEntry({0, 0})); + return HasReturnvaluesIF::RETURN_OK; +} + +LocalPoolObjectBase* LocalPoolOwnerBase::getPoolObjectHandle(lp_id_t localPoolId) { + if(localPoolId == lpool::uint8VarId) { + return &testUint8; + } + else if(localPoolId == lpool::uint16Vec3Id) { + return &testUint16Vec; + } + else if(localPoolId == lpool::floatVarId) { + return &testFloat; + } + else if(localPoolId == lpool::int64Vec2Id) { + return &testInt64Vec; + } + else if(localPoolId == lpool::uint32VarId) { + return &testUint32; + } + else { + return &testUint8; + } +} + +ReturnValue_t LocalPoolOwnerBase::reset() { + resetSubscriptionList(); + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + { + PoolReadGuard readHelper(&dataset); + if(readHelper.getReadResult() != HasReturnvaluesIF::RETURN_OK) { + status = readHelper.getReadResult(); + } + dataset.localPoolVarUint8.value = 0; + dataset.localPoolVarFloat.value = 0.0; + dataset.localPoolUint16Vec.value[0] = 0; + dataset.localPoolUint16Vec.value[1] = 0; + dataset.localPoolUint16Vec.value[2] = 0; + dataset.setValidity(false, true); + } + + { + PoolReadGuard readHelper(&testUint32); + if(readHelper.getReadResult() != HasReturnvaluesIF::RETURN_OK) { + status = readHelper.getReadResult(); + } + testUint32.value = 0; + testUint32.setValid(false); + } + + { + PoolReadGuard readHelper(&testInt64Vec); + if(readHelper.getReadResult() != HasReturnvaluesIF::RETURN_OK) { + status = readHelper.getReadResult(); + } + testInt64Vec.value[0] = 0; + testInt64Vec.value[1] = 0; + testInt64Vec.setValid(false); + } + return status; +} + +bool LocalPoolOwnerBase::changedDataSetCallbackWasCalled(sid_t &sid, store_address_t &storeId) { + bool condition = false; + if(not this->changedDatasetSid.notSet()) { + condition = true; + } + sid = changedDatasetSid; + storeId = storeIdForChangedSet; + this->changedDatasetSid.raw = sid_t::INVALID_SID; + this->storeIdForChangedSet = storeId::INVALID_STORE_ADDRESS; + return condition; +} + +void LocalPoolOwnerBase::handleChangedDataset(sid_t sid, store_address_t storeId, + bool* clearMessage) { + this->changedDatasetSid = sid; + this->storeIdForChangedSet = storeId; +} + +bool LocalPoolOwnerBase::changedVariableCallbackWasCalled(gp_id_t &gpid, store_address_t &storeId) { + bool condition = false; + if(not this->changedPoolVariableGpid.notSet()) { + condition = true; + } + gpid = changedPoolVariableGpid; + storeId = storeIdForChangedVariable; + this->changedPoolVariableGpid.raw = gp_id_t::INVALID_GPID; + this->storeIdForChangedVariable = storeId::INVALID_STORE_ADDRESS; + return condition; +} + +ReturnValue_t LocalPoolOwnerBase::initializeHkManagerAfterTaskCreation() { + if(not initializedAfterTaskCreation) { + initializedAfterTaskCreation = true; + return poolManager.initializeAfterTaskCreation(); + } + return HasReturnvaluesIF::RETURN_OK; + +} + +void LocalPoolOwnerBase::handleChangedPoolVariable(gp_id_t globPoolId, store_address_t storeId, + bool* clearMessage) { + this->changedPoolVariableGpid = globPoolId; + this->storeIdForChangedVariable = storeId; +} + diff --git a/unittest/tests/datapoollocal/LocalPoolOwnerBase.h b/unittest/tests/datapoollocal/LocalPoolOwnerBase.h index 5c277850f..8d2073b0e 100644 --- a/unittest/tests/datapoollocal/LocalPoolOwnerBase.h +++ b/unittest/tests/datapoollocal/LocalPoolOwnerBase.h @@ -1,16 +1,17 @@ #ifndef FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ #define FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ +#include + #include #include #include #include #include #include -#include #include #include -#include "../../../datapool/PoolReadHelper.h" +#include namespace lpool { static constexpr lp_id_t uint8VarId = 0; @@ -36,10 +37,11 @@ class LocalPoolStaticTestDataSet: public StaticLocalDataSet<3> { public: LocalPoolStaticTestDataSet(): StaticLocalDataSet(lpool::testSid) { + } LocalPoolStaticTestDataSet(HasLocalDataPoolIF* owner, uint32_t setId): - StaticLocalDataSet(owner, setId) { + StaticLocalDataSet(owner, setId) { } lp_var_t localPoolVarUint8 = lp_var_t(lpool::uint8VarGpid, this); @@ -52,8 +54,7 @@ private: class LocalPoolTestDataSet: public LocalDataSet { public: LocalPoolTestDataSet(): - LocalDataSet(lpool::testSid, lpool::dataSetMaxVariables) { - } + LocalDataSet(lpool::testSid, lpool::dataSetMaxVariables) {} LocalPoolTestDataSet(HasLocalDataPoolIF* owner, uint32_t setId): LocalDataSet(owner, setId, lpool::dataSetMaxVariables) { @@ -63,42 +64,26 @@ public: lp_var_t localPoolVarFloat = lp_var_t(lpool::floatVarGpid, this); lp_vec_t localPoolUint16Vec = lp_vec_t(lpool::uint16Vec3Gpid, this); + void setDiagnostic(bool isDiagnostic) { + LocalPoolDataSetBase::setDiagnostic(isDiagnostic); + } private: }; class LocalPoolOwnerBase: public SystemObject, public HasLocalDataPoolIF { public: - LocalPoolOwnerBase( - object_id_t objectId = objects::TEST_LOCAL_POOL_OWNER_BASE): - SystemObject(objectId), poolManager(this, messageQueue), - dataset(this, lpool::testSetId) { - messageQueue = new MessageQueueMockBase(); - } + LocalPoolOwnerBase(object_id_t objectId = objects::TEST_LOCAL_POOL_OWNER_BASE); - ~LocalPoolOwnerBase() { - QueueFactory::instance()->deleteMessageQueue(messageQueue); - } + ~LocalPoolOwnerBase(); object_id_t getObjectId() const override { return SystemObject::getObjectId(); } - ReturnValue_t initializeHkManager() { - if(not initialized) { - initialized = true; - return poolManager.initialize(messageQueue); - } - return HasReturnvaluesIF::RETURN_OK; - } + ReturnValue_t initializeHkManager(); - ReturnValue_t initializeHkManagerAfterTaskCreation() { - if(not initializedAfterTaskCreation) { - initializedAfterTaskCreation = true; - return poolManager.initializeAfterTaskCreation(); - } - return HasReturnvaluesIF::RETURN_OK; - } + ReturnValue_t initializeHkManagerAfterTaskCreation(); /** Command queue for housekeeping messages. */ MessageQueueId_t getCommandQueue() const override { @@ -106,30 +91,15 @@ public: } // This is called by initializeAfterTaskCreation of the HK manager. - virtual ReturnValue_t initializeLocalDataPool( - localpool::DataPool& localDataPoolMap, - LocalDataPoolManager& poolManager) { - // Default initialization empty for now. - localDataPoolMap.emplace(lpool::uint8VarId, - new PoolEntry({0})); - localDataPoolMap.emplace(lpool::floatVarId, - new PoolEntry({0})); - localDataPoolMap.emplace(lpool::uint32VarId, - new PoolEntry({0})); - - localDataPoolMap.emplace(lpool::uint16Vec3Id, - new PoolEntry({0, 0, 0})); - localDataPoolMap.emplace(lpool::int64Vec2Id, - new PoolEntry({0, 0})); - return HasReturnvaluesIF::RETURN_OK; - } + virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; LocalDataPoolManager* getHkManagerHandle() override { return &poolManager; } - uint32_t getPeriodicOperationFrequency() const override { - return 0; + dur_millis_t getPeriodicOperationFrequency() const override { + return 200; } /** @@ -142,32 +112,16 @@ public: return &dataset; } - virtual LocalPoolObjectBase* getPoolObjectHandle( - lp_id_t localPoolId) override { - if(localPoolId == lpool::uint8VarId) { - return &testUint8; - } - else if(localPoolId == lpool::uint16Vec3Id) { - return &testUint16Vec; - } - else if(localPoolId == lpool::floatVarId) { - return &testFloat; - } - else if(localPoolId == lpool::int64Vec2Id) { - return &testInt64Vec; - } - else if(localPoolId == lpool::uint32VarId) { - return &testUint32; - } - else { - return &testUint8; - } - } + virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) override; MessageQueueMockBase* getMockQueueHandle() const { return dynamic_cast(messageQueue); } + ReturnValue_t subscribePeriodicHk(bool enableReporting) { + return poolManager.subscribeForPeriodicPacket(lpool::testSid, enableReporting, 0.2, false); + } + ReturnValue_t subscribeWrapperSetUpdate() { return poolManager.subscribeForSetUpdateMessage(lpool::testSetId, objects::NO_OBJECT, objects::HK_RECEIVER_MOCK, false); @@ -188,51 +142,33 @@ public: MessageQueueIF::NO_QUEUE, objects::HK_RECEIVER_MOCK, false); } - ReturnValue_t reset() { - resetSubscriptionList(); - ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; - { - PoolReadGuard readHelper(&dataset); - if(readHelper.getReadResult() != HasReturnvaluesIF::RETURN_OK) { - status = readHelper.getReadResult(); - } - dataset.localPoolVarUint8.value = 0; - dataset.localPoolVarFloat.value = 0.0; - dataset.localPoolUint16Vec.value[0] = 0; - dataset.localPoolUint16Vec.value[1] = 0; - dataset.localPoolUint16Vec.value[2] = 0; - dataset.setValidity(false, true); - } - - { - PoolReadGuard readHelper(&testUint32); - if(readHelper.getReadResult() != HasReturnvaluesIF::RETURN_OK) { - status = readHelper.getReadResult(); - } - testUint32.value = 0; - testUint32.setValid(false); - } - - { - PoolReadGuard readHelper(&testInt64Vec); - if(readHelper.getReadResult() != HasReturnvaluesIF::RETURN_OK) { - status = readHelper.getReadResult(); - } - testInt64Vec.value[0] = 0; - testInt64Vec.value[1] = 0; - testInt64Vec.setValid(false); - } - return status; + ReturnValue_t subscribeWrapperVariableSnapshot(lp_id_t localPoolId) { + return poolManager.subscribeForVariableUpdateMessage(localPoolId, + MessageQueueIF::NO_QUEUE, objects::HK_RECEIVER_MOCK, true); } + ReturnValue_t reset(); + void resetSubscriptionList() { poolManager.clearReceiversList(); } + bool changedDataSetCallbackWasCalled(sid_t& sid, store_address_t& storeId); + bool changedVariableCallbackWasCalled(gp_id_t& gpid, store_address_t& storeId); + LocalDataPoolManager poolManager; LocalPoolTestDataSet dataset; private: + void handleChangedDataset(sid_t sid, store_address_t storeId, bool* clearMessage) override; + sid_t changedDatasetSid; + store_address_t storeIdForChangedSet; + + void handleChangedPoolVariable(gp_id_t globPoolId, store_address_t storeId, + bool* clearMessage) override; + gp_id_t changedPoolVariableGpid; + store_address_t storeIdForChangedVariable; + lp_var_t testUint8 = lp_var_t(this, lpool::uint8VarId); lp_var_t testFloat = lp_var_t(this, lpool::floatVarId); lp_var_t testUint32 = lp_var_t(this, lpool::uint32VarId); diff --git a/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp b/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp index e5a5d3645..980ffda19 100644 --- a/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp +++ b/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp @@ -10,8 +10,7 @@ TEST_CASE("LocalPoolVariable" , "[LocPoolVarTest]") { get(objects::TEST_LOCAL_POOL_OWNER_BASE); REQUIRE(poolOwner != nullptr); REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); - REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() - == retval::CATCH_OK); + REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() == retval::CATCH_OK); SECTION("Basic Tests") { /* very basic test. */ diff --git a/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp b/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp index 2bc47568f..db76fc00e 100644 --- a/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp +++ b/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp @@ -115,6 +115,7 @@ TEST_CASE("LocalPoolVector" , "[LocPoolVecTest]") { REQUIRE(readOnlyVec.commit() == static_cast(PoolVariableIF::INVALID_READ_WRITE_MODE)); } + poolOwner->reset(); } diff --git a/unittest/tests/mocks/MessageQueueMockBase.h b/unittest/tests/mocks/MessageQueueMockBase.h index 7b810b41f..3000f7fb5 100644 --- a/unittest/tests/mocks/MessageQueueMockBase.h +++ b/unittest/tests/mocks/MessageQueueMockBase.h @@ -29,16 +29,24 @@ public: return tempMessageSent; } + /** + * Pop a message, clearing it in the process. + * @return + */ + ReturnValue_t popMessage() { + CommandMessage message; + message.clear(); + return receiveMessage(&message); + } + virtual ReturnValue_t reply( MessageQueueMessageIF* message ) { - //messageSent = true; - //lastMessage = *(dynamic_cast(message)); return sendMessage(myQueueId, message); - return HasReturnvaluesIF::RETURN_OK; }; virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t *receivedFrom) { return receiveMessage(message); } + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) { if(messagesSentQueue.empty()) { return MessageQueueIF::EMPTY; @@ -61,21 +69,13 @@ public: virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) { - //messageSent = true; - //lastMessage = *(dynamic_cast(message)); - //return HasReturnvaluesIF::RETURN_OK; return sendMessage(sendTo, message); } virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) { - //messageSent = true; - //lastMessage = *(dynamic_cast(message)); - //return HasReturnvaluesIF::RETURN_OK; return sendMessage(myQueueId, message); } virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ) { - //messageSent = true; - //lastMessage = *(dynamic_cast(message)); return sendMessage(myQueueId, message); } virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, @@ -114,7 +114,6 @@ public: private: std::queue messagesSentQueue; - //MessageQueueMessage lastMessage; };