Merge remote-tracking branch 'origin/gaisser_fixes_subsystem' into gaisser_fixes_subsystem
This commit is contained in:
commit
4fd443f70b
@ -1,5 +1,13 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
|
option(FSFW_GENERATE_SECTIONS
|
||||||
|
"Generate function and data sections. Required to remove unused code" ON
|
||||||
|
)
|
||||||
|
|
||||||
|
if(FSFW_GENERATE_SECTIONS)
|
||||||
|
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
||||||
# Options to exclude parts of the FSFW from compilation.
|
# Options to exclude parts of the FSFW from compilation.
|
||||||
option(FSFW_USE_RMAP "Compile with RMAP" ON)
|
option(FSFW_USE_RMAP "Compile with RMAP" ON)
|
||||||
@ -26,15 +34,22 @@ if(NOT OS_FSFW)
|
|||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(FSFW_OSAL_DEFINITION FSFW_HOST)
|
||||||
|
|
||||||
if(${OS_FSFW} STREQUAL host)
|
if(${OS_FSFW} STREQUAL host)
|
||||||
set(OS_FSFW_NAME "Host")
|
set(OS_FSFW_NAME "Host")
|
||||||
elseif(${OS_FSFW} STREQUAL linux)
|
elseif(${OS_FSFW} STREQUAL linux)
|
||||||
set(OS_FSFW_NAME "Linux")
|
set(OS_FSFW_NAME "Linux")
|
||||||
|
set(FSFW_OSAL_DEFINITION FSFW_LINUX)
|
||||||
elseif(${OS_FSFW} STREQUAL freertos)
|
elseif(${OS_FSFW} STREQUAL freertos)
|
||||||
set(OS_FSFW_NAME "FreeRTOS")
|
set(OS_FSFW_NAME "FreeRTOS")
|
||||||
target_link_libraries(${LIB_FSFW_NAME} ${LIB_OS_NAME})
|
set(FSFW_OSAL_DEFINITION FSFW_FREERTOS)
|
||||||
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
${LIB_OS_NAME}
|
||||||
|
)
|
||||||
elseif(${OS_FSFW} STREQUAL rtems)
|
elseif(${OS_FSFW} STREQUAL rtems)
|
||||||
set(OS_FSFW_NAME "RTEMS")
|
set(OS_FSFW_NAME "RTEMS")
|
||||||
|
set(FSFW_OSAL_DEFINITION FSFW_RTEMS)
|
||||||
else()
|
else()
|
||||||
message(WARNING
|
message(WARNING
|
||||||
"Invalid operating system for FSFW specified! Setting to host.."
|
"Invalid operating system for FSFW specified! Setting to host.."
|
||||||
@ -43,6 +58,14 @@ else()
|
|||||||
set(OS_FSFW "host")
|
set(OS_FSFW "host")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
${FSFW_OSAL_DEFINITION}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(${LIB_FSFW_NAME} INTERFACE
|
||||||
|
${FSFW_OSAL_DEFINITION}
|
||||||
|
)
|
||||||
|
|
||||||
message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.")
|
message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.")
|
||||||
|
|
||||||
add_subdirectory(action)
|
add_subdirectory(action)
|
||||||
@ -88,6 +111,7 @@ add_subdirectory(timemanager)
|
|||||||
add_subdirectory(tmstorage)
|
add_subdirectory(tmstorage)
|
||||||
add_subdirectory(tmtcpacket)
|
add_subdirectory(tmtcpacket)
|
||||||
add_subdirectory(tmtcservices)
|
add_subdirectory(tmtcservices)
|
||||||
|
add_subdirectory(unittest)
|
||||||
|
|
||||||
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
|
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
|
||||||
# If this is not given, we include the default configuration and emit a warning.
|
# If this is not given, we include the default configuration and emit a warning.
|
||||||
@ -107,6 +131,21 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATH})
|
||||||
|
if(IS_ABSOLUTE ${INCLUDE_PATH})
|
||||||
|
set(CURR_ABS_INC_PATH "${FREERTOS_PATH}")
|
||||||
|
else()
|
||||||
|
get_filename_component(CURR_ABS_INC_PATH
|
||||||
|
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_VERBOSE)
|
||||||
|
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND FSFW_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
if(NOT DEFINED FSFW_WARNING_FLAGS)
|
if(NOT DEFINED FSFW_WARNING_FLAGS)
|
||||||
set(FSFW_WARNING_FLAGS
|
set(FSFW_WARNING_FLAGS
|
||||||
@ -118,6 +157,19 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(FSFW_GENERATE_SECTIONS)
|
||||||
|
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
"-ffunction-sections"
|
||||||
|
"-fdata-sections"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FSFW_REMOVE_UNUSED_CODE)
|
||||||
|
target_link_options(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
"Wl,--gc-sections"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
|
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
|
||||||
list(APPEND WARNING_FLAGS "-Wshadow=local")
|
list(APPEND WARNING_FLAGS "-Wshadow=local")
|
||||||
endif()
|
endif()
|
||||||
@ -132,6 +184,7 @@ endif()
|
|||||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
||||||
${CMAKE_SOURCE_DIR}
|
${CMAKE_SOURCE_DIR}
|
||||||
${FSFW_CONFIG_PATH_ABSOLUTE}
|
${FSFW_CONFIG_PATH_ABSOLUTE}
|
||||||
|
${FSFW_ADD_INC_PATHS_ABS}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Includes path required to compile FSFW itself as well
|
# Includes path required to compile FSFW itself as well
|
||||||
@ -140,9 +193,14 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
|||||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
||||||
${CMAKE_SOURCE_DIR}
|
${CMAKE_SOURCE_DIR}
|
||||||
${FSFW_CONFIG_PATH_ABSOLUTE}
|
${FSFW_CONFIG_PATH_ABSOLUTE}
|
||||||
|
${FSFW_ADD_INC_PATHS_ABS}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
||||||
${FSFW_WARNING_FLAGS}
|
${FSFW_WARNING_FLAGS}
|
||||||
${COMPILER_FLAGS}
|
${COMPILER_FLAGS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
${FSFW_ADDITIONAL_LINK_LIBS}
|
||||||
|
)
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
const char* const FSFW_VERSION_NAME = "ASTP";
|
const char* const FSFW_VERSION_NAME = "ASTP";
|
||||||
|
|
||||||
#define FSFW_VERSION 0
|
#define FSFW_VERSION 1
|
||||||
#define FSFW_SUBVERSION 0
|
#define FSFW_SUBVERSION 0
|
||||||
#define FSFW_REVISION 1
|
#define FSFW_REVISION 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,11 +147,6 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
ipcStore->deleteData(storeAddress);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We don't need to report the objectId, as we receive REQUESTED data before the completion
|
/* We don't need to report the objectId, as we receive REQUESTED data before the completion
|
||||||
success message. True aperiodic replies need to be reported with another dedicated message. */
|
success message. True aperiodic replies need to be reported with another dedicated message. */
|
||||||
ActionMessage::setDataReply(&reply, replyId, storeAddress);
|
ActionMessage::setDataReply(&reply, replyId, storeAddress);
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
*/
|
*/
|
||||||
template<typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
template<typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
||||||
class FixedArrayList: public ArrayList<T, count_t> {
|
class FixedArrayList: public ArrayList<T, count_t> {
|
||||||
static_assert(MAX_SIZE <= (pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE");
|
#if !defined(_MSC_VER)
|
||||||
|
static_assert(MAX_SIZE <= (std::pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE");
|
||||||
|
#endif
|
||||||
private:
|
private:
|
||||||
T data[MAX_SIZE];
|
T data[MAX_SIZE];
|
||||||
public:
|
public:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "SharedRingBuffer.h"
|
#include "SharedRingBuffer.h"
|
||||||
#include "../ipc/MutexFactory.h"
|
#include "../ipc/MutexFactory.h"
|
||||||
#include "../ipc/MutexHelper.h"
|
#include "../ipc/MutexGuard.h"
|
||||||
|
|
||||||
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size,
|
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size,
|
||||||
bool overwriteOld, size_t maxExcessBytes):
|
bool overwriteOld, size_t maxExcessBytes):
|
||||||
@ -17,6 +17,9 @@ SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
|
|||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedRingBuffer::~SharedRingBuffer() {
|
||||||
|
MutexFactory::instance()->deleteMutex(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
|
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
|
||||||
this->fifoDepth = fifoDepth;
|
this->fifoDepth = fifoDepth;
|
||||||
|
@ -26,6 +26,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
SharedRingBuffer(object_id_t objectId, const size_t size,
|
SharedRingBuffer(object_id_t objectId, const size_t size,
|
||||||
bool overwriteOld, size_t maxExcessBytes);
|
bool overwriteOld, size_t maxExcessBytes);
|
||||||
|
/**
|
||||||
|
* This constructor takes an external buffer with the specified size.
|
||||||
|
* @param buffer
|
||||||
|
* @param size
|
||||||
|
* @param overwriteOld
|
||||||
|
* If the ring buffer is overflowing at a write operartion, the oldest data
|
||||||
|
* will be overwritten.
|
||||||
|
*/
|
||||||
|
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
|
||||||
|
bool overwriteOld, size_t maxExcessBytes);
|
||||||
|
|
||||||
|
virtual~ SharedRingBuffer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function can be used to add an optional FIFO to the class
|
* @brief This function can be used to add an optional FIFO to the class
|
||||||
@ -37,16 +49,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setToUseReceiveSizeFIFO(size_t fifoDepth);
|
void setToUseReceiveSizeFIFO(size_t fifoDepth);
|
||||||
|
|
||||||
/**
|
|
||||||
* This constructor takes an external buffer with the specified size.
|
|
||||||
* @param buffer
|
|
||||||
* @param size
|
|
||||||
* @param overwriteOld
|
|
||||||
* If the ring buffer is overflowing at a write operartion, the oldest data
|
|
||||||
* will be overwritten.
|
|
||||||
*/
|
|
||||||
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
|
|
||||||
bool overwriteOld, size_t maxExcessBytes);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unless a read-only constant value is read, all operations on the
|
* Unless a read-only constant value is read, all operations on the
|
||||||
@ -66,7 +69,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The mutex handle can be accessed directly, for example to perform
|
* The mutex handle can be accessed directly, for example to perform
|
||||||
* the lock with the #MutexHelper for a RAII compliant lock operation.
|
* the lock with the #MutexGuard for a RAII compliant lock operation.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
MutexIF* getMutexHandle() const;
|
MutexIF* getMutexHandle() const;
|
||||||
|
@ -17,14 +17,6 @@ ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ReturnValue_t ExtendedControllerBase::initializeLocalDataPool(
|
|
||||||
localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
|
|
||||||
/* Needs to be overriden and implemented by child class. */
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
object_id_t ExtendedControllerBase::getObjectId() const {
|
object_id_t ExtendedControllerBase::getObjectId() const {
|
||||||
return SystemObject::getObjectId();
|
return SystemObject::getObjectId();
|
||||||
}
|
}
|
||||||
@ -107,14 +99,6 @@ MessageQueueId_t ExtendedControllerBase::getCommandQueue() const {
|
|||||||
return commandQueue->getId();
|
return commandQueue->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalPoolDataSetBase* ExtendedControllerBase::getDataSetHandle(sid_t sid) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "ExtendedControllerBase::getDataSetHandle: No child "
|
|
||||||
<< " implementation provided, returning nullptr!" << std::endl;
|
|
||||||
#endif
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() {
|
LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() {
|
||||||
return &poolManager;
|
return &poolManager;
|
||||||
}
|
}
|
||||||
|
@ -61,11 +61,11 @@ protected:
|
|||||||
/* HasLocalDatapoolIF overrides */
|
/* HasLocalDatapoolIF overrides */
|
||||||
virtual LocalDataPoolManager* getHkManagerHandle() override;
|
virtual LocalDataPoolManager* getHkManagerHandle() override;
|
||||||
virtual object_id_t getObjectId() const override;
|
virtual object_id_t getObjectId() const override;
|
||||||
virtual ReturnValue_t initializeLocalDataPool(
|
|
||||||
localpool::DataPool& localDataPoolMap,
|
|
||||||
LocalDataPoolManager& poolManager) override;
|
|
||||||
virtual uint32_t getPeriodicOperationFrequency() const override;
|
virtual uint32_t getPeriodicOperationFrequency() const override;
|
||||||
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
|
|
||||||
|
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||||
|
LocalDataPoolManager& poolManager) override = 0;
|
||||||
|
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
HkSwitchHelper::~HkSwitchHelper() {
|
HkSwitchHelper::~HkSwitchHelper() {
|
||||||
// TODO Auto-generated destructor stub
|
QueueFactory::instance()->deleteMessageQueue(actionQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::initialize() {
|
ReturnValue_t HkSwitchHelper::initialize() {
|
||||||
|
@ -8,13 +8,16 @@
|
|||||||
PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
|
PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
|
||||||
const size_t maxFillCount):
|
const size_t maxFillCount):
|
||||||
registeredVariables(registeredVariablesArray),
|
registeredVariables(registeredVariablesArray),
|
||||||
maxFillCount(maxFillCount) {
|
maxFillCount(maxFillCount) {}
|
||||||
}
|
|
||||||
|
|
||||||
PoolDataSetBase::~PoolDataSetBase() {}
|
PoolDataSetBase::~PoolDataSetBase() {}
|
||||||
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF *variable) {
|
ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF *variable) {
|
||||||
|
if(registeredVariables == nullptr) {
|
||||||
|
/* Underlying container invalid */
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
if (state != States::STATE_SET_UNINITIALISED) {
|
if (state != States::STATE_SET_UNINITIALISED) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl;
|
sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl;
|
||||||
@ -61,11 +64,11 @@ ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "DataSet::read(): Call made in wrong position. Don't forget to commit"
|
sif::warning << "PoolDataSetBase::read: Call made in wrong position. Don't forget to "
|
||||||
" member datasets!" << std::endl;
|
"commit member datasets!" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printError("DataSet::read(): Call made in wrong position. Don't forget to commit"
|
sif::printWarning("PoolDataSetBase::read: Call made in wrong position. Don't forget to "
|
||||||
" member datasets!\n");
|
"commit member datasets!\n");
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
result = SET_WAS_ALREADY_READ;
|
result = SET_WAS_ALREADY_READ;
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
* and unlock a data pool and read/commit semantics.
|
* and unlock a data pool and read/commit semantics.
|
||||||
*/
|
*/
|
||||||
class PoolDataSetIF:
|
class PoolDataSetIF:
|
||||||
public DataSetIF,
|
virtual public DataSetIF,
|
||||||
public ReadCommitIF {
|
virtual public ReadCommitIF {
|
||||||
public:
|
public:
|
||||||
virtual~ PoolDataSetIF() {};
|
virtual~ PoolDataSetIF() {};
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid ):
|
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid ):
|
||||||
length(initValue.size()), valid(setValid) {
|
length(static_cast<uint8_t>(initValue.size())), valid(setValid) {
|
||||||
this->address = new T[this->length];
|
this->address = new T[this->length];
|
||||||
if(initValue.size() == 0) {
|
if(initValue.size() == 0) {
|
||||||
std::memset(this->address, 0, this->getByteSize());
|
std::memset(this->address, 0, this->getByteSize());
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
#ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
|
#ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
|
||||||
#define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
|
#define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
|
||||||
|
|
||||||
#include "PoolDataSetIF.h"
|
#include "PoolDataSetIF.h"
|
||||||
|
|
||||||
class SharedDataSetIF: public PoolDataSetIF {
|
class SharedDataSetIF {
|
||||||
public:
|
public:
|
||||||
virtual ~SharedDataSetIF() {};
|
virtual ~SharedDataSetIF() {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ReturnValue_t lockDataset(dur_millis_t mutexTimeout) = 0;
|
virtual ReturnValue_t lockDataset(MutexIF::TimeoutType timeoutType,
|
||||||
|
dur_millis_t mutexTimeout) = 0;
|
||||||
virtual ReturnValue_t unlockDataset() = 0;
|
virtual ReturnValue_t unlockDataset() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,34 +65,45 @@ public:
|
|||||||
* usually be the period the pool owner performs its periodic operation.
|
* usually be the period the pool owner performs its periodic operation.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual uint32_t getPeriodicOperationFrequency() const = 0;
|
virtual dur_millis_t getPeriodicOperationFrequency() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function will be called by the manager if an update
|
* @brief This function will be called by the manager if an update
|
||||||
* notification is received.
|
* notification is received.
|
||||||
* @details HasLocalDataPoolIF
|
* @details HasLocalDataPoolIF
|
||||||
* Can be overriden by the child class to handle changed datasets.
|
* Can be overriden by the child class to handle changed datasets.
|
||||||
* @param sid
|
* @param sid SID of the updated set
|
||||||
* @param storeId If a snapshot was requested, data will be located inside
|
* @param storeId If a snapshot was requested, data will be located inside
|
||||||
* the IPC store with this store ID.
|
* the IPC store with this store ID.
|
||||||
|
* @param clearMessage If this is set to true, the pool manager will take care of
|
||||||
|
* clearing the store automatically
|
||||||
*/
|
*/
|
||||||
virtual void handleChangedDataset(sid_t sid,
|
virtual void handleChangedDataset(sid_t sid,
|
||||||
store_address_t storeId = storeId::INVALID_STORE_ADDRESS) {
|
store_address_t storeId = storeId::INVALID_STORE_ADDRESS,
|
||||||
return;
|
bool* clearMessage = nullptr) {
|
||||||
|
if(clearMessage != nullptr) {
|
||||||
|
*clearMessage = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function will be called by the manager if an update
|
* @brief This function will be called by the manager if an update
|
||||||
* notification is received.
|
* notification is received.
|
||||||
* @details
|
* @details
|
||||||
* Can be overriden by the child class to handle changed pool IDs.
|
* Can be overriden by the child class to handle changed pool variables.
|
||||||
* @param sid
|
* @param gpid GPID of the updated variable.
|
||||||
* @param storeId If a snapshot was requested, data will be located inside
|
* @param storeId If a snapshot was requested, data will be located inside
|
||||||
* the IPC store with this store ID.
|
* the IPC store with this store ID.
|
||||||
|
* @param clearMessage Relevant for snapshots. If the boolean this points to is set to true,
|
||||||
|
* the pool manager will take care of clearing the store automatically
|
||||||
|
* after the callback.
|
||||||
*/
|
*/
|
||||||
virtual void handleChangedPoolVariable(gp_id_t globPoolId,
|
virtual void handleChangedPoolVariable(gp_id_t gpid,
|
||||||
store_address_t storeId = storeId::INVALID_STORE_ADDRESS) {
|
store_address_t storeId = storeId::INVALID_STORE_ADDRESS,
|
||||||
return;
|
bool* clearMessage = nullptr) {
|
||||||
|
if(clearMessage != nullptr) {
|
||||||
|
*clearMessage = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include "../housekeeping/AcceptsHkPacketsIF.h"
|
#include "../housekeeping/AcceptsHkPacketsIF.h"
|
||||||
#include "../timemanager/CCSDSTime.h"
|
#include "../timemanager/CCSDSTime.h"
|
||||||
#include "../ipc/MutexFactory.h"
|
#include "../ipc/MutexFactory.h"
|
||||||
#include "../ipc/MutexHelper.h"
|
#include "../ipc/MutexGuard.h"
|
||||||
#include "../ipc/QueueFactory.h"
|
#include "../ipc/QueueFactory.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
@ -38,7 +38,11 @@ LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQue
|
|||||||
hkQueue = queueToUse;
|
hkQueue = queueToUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDataPoolManager::~LocalDataPoolManager() {}
|
LocalDataPoolManager::~LocalDataPoolManager() {
|
||||||
|
if(mutex != nullptr) {
|
||||||
|
MutexFactory::instance()->deleteMutex(mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
|
ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
|
||||||
if(queueToUse == nullptr) {
|
if(queueToUse == nullptr) {
|
||||||
@ -132,13 +136,16 @@ ReturnValue_t LocalDataPoolManager::performHkOperation() {
|
|||||||
ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver,
|
ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver,
|
||||||
ReturnValue_t& status) {
|
ReturnValue_t& status) {
|
||||||
if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) {
|
if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) {
|
||||||
// Update packets shall only be generated from datasets.
|
/* Update packets shall only be generated from datasets. */
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner,
|
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner,
|
||||||
receiver.dataId.sid);
|
receiver.dataId.sid);
|
||||||
|
if(dataSet == nullptr) {
|
||||||
|
return DATASET_NOT_FOUND;
|
||||||
|
}
|
||||||
if(dataSet->hasChanged()) {
|
if(dataSet->hasChanged()) {
|
||||||
// prepare and send update notification
|
/* Prepare and send update notification */
|
||||||
ReturnValue_t result = generateHousekeepingPacket(
|
ReturnValue_t result = generateHousekeepingPacket(
|
||||||
receiver.dataId.sid, dataSet, true);
|
receiver.dataId.sid, dataSet, true);
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
@ -328,7 +335,7 @@ void LocalDataPoolManager::handleChangeResetLogic(
|
|||||||
toReset->setChanged(false);
|
toReset->setChanged(false);
|
||||||
}
|
}
|
||||||
/* All recipients have been notified, reset the changed flag */
|
/* All recipients have been notified, reset the changed flag */
|
||||||
if(changeInfo.currentUpdateCounter <= 1) {
|
else if(changeInfo.currentUpdateCounter <= 1) {
|
||||||
toReset->setChanged(false);
|
toReset->setChanged(false);
|
||||||
changeInfo.currentUpdateCounter = 0;
|
changeInfo.currentUpdateCounter = 0;
|
||||||
}
|
}
|
||||||
@ -372,7 +379,7 @@ ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid,
|
|||||||
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting);
|
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting);
|
||||||
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics);
|
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics);
|
||||||
LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval,
|
LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval,
|
||||||
owner->getPeriodicOperationFrequency(), isDiagnostics);
|
owner->getPeriodicOperationFrequency());
|
||||||
}
|
}
|
||||||
|
|
||||||
hkReceivers.push_back(hkReceiver);
|
hkReceivers.push_back(hkReceiver);
|
||||||
@ -398,7 +405,6 @@ ReturnValue_t LocalDataPoolManager::subscribeForUpdatePacket(sid_t sid,
|
|||||||
hkReceiver.destinationQueue = hkReceiverObject->getHkQueue();
|
hkReceiver.destinationQueue = hkReceiverObject->getHkQueue();
|
||||||
|
|
||||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||||
//LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid);
|
|
||||||
if(dataSet != nullptr) {
|
if(dataSet != nullptr) {
|
||||||
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true);
|
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true);
|
||||||
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics);
|
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics);
|
||||||
@ -516,11 +522,19 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): {
|
case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): {
|
||||||
return generateSetStructurePacket(sid, true);
|
result = generateSetStructurePacket(sid, true);
|
||||||
|
if(result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): {
|
case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): {
|
||||||
return generateSetStructurePacket(sid, false);
|
result = generateSetStructurePacket(sid, false);
|
||||||
|
if(result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL):
|
case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL):
|
||||||
case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): {
|
case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): {
|
||||||
@ -540,14 +554,15 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(
|
|||||||
case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT):
|
case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT):
|
||||||
case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): {
|
case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): {
|
||||||
LocalPoolDataSetBase* dataSet =HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
LocalPoolDataSetBase* dataSet =HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||||
//LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid);
|
|
||||||
if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT
|
if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT
|
||||||
and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
|
and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
|
||||||
return WRONG_HK_PACKET_TYPE;
|
result = WRONG_HK_PACKET_TYPE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT
|
else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT
|
||||||
and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
|
and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
|
||||||
return WRONG_HK_PACKET_TYPE;
|
result = WRONG_HK_PACKET_TYPE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return generateHousekeepingPacket(HousekeepingMessage::getSid(message),
|
return generateHousekeepingPacket(HousekeepingMessage::getSid(message),
|
||||||
dataSet, true);
|
dataSet, true);
|
||||||
@ -566,14 +581,22 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(
|
|||||||
case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): {
|
case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): {
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId);
|
HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId);
|
||||||
owner->handleChangedDataset(sid, storeId);
|
bool clearMessage = true;
|
||||||
|
owner->handleChangedDataset(sid, storeId, &clearMessage);
|
||||||
|
if(clearMessage) {
|
||||||
|
message->clear();
|
||||||
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): {
|
case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): {
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
gp_id_t globPoolId = HousekeepingMessage::getUpdateSnapshotVariableCommand(message,
|
gp_id_t globPoolId = HousekeepingMessage::getUpdateSnapshotVariableCommand(message,
|
||||||
&storeId);
|
&storeId);
|
||||||
owner->handleChangedPoolVariable(globPoolId, storeId);
|
bool clearMessage = true;
|
||||||
|
owner->handleChangedPoolVariable(globPoolId, storeId, &clearMessage);
|
||||||
|
if(clearMessage) {
|
||||||
|
message->clear();
|
||||||
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +639,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
|
|||||||
LocalPoolDataSetBase* dataSet, bool forDownlink,
|
LocalPoolDataSetBase* dataSet, bool forDownlink,
|
||||||
MessageQueueId_t destination) {
|
MessageQueueId_t destination) {
|
||||||
if(dataSet == nullptr) {
|
if(dataSet == nullptr) {
|
||||||
// Configuration error.
|
/* Configuration error. */
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING,
|
printWarningOrError(sif::OutputTypes::OUT_WARNING,
|
||||||
"generateHousekeepingPacket",
|
"generateHousekeepingPacket",
|
||||||
DATASET_NOT_FOUND);
|
DATASET_NOT_FOUND);
|
||||||
@ -632,7 +655,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// and now we set a HK message and send it the HK packet destination.
|
/* Now we set a HK message and send it the HK packet destination. */
|
||||||
CommandMessage hkMessage;
|
CommandMessage hkMessage;
|
||||||
if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
|
if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
|
||||||
HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId);
|
HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId);
|
||||||
@ -642,7 +665,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(hkQueue == nullptr) {
|
if(hkQueue == nullptr) {
|
||||||
// error, no queue available to send packet with.
|
/* Error, no queue available to send packet with. */
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING,
|
printWarningOrError(sif::OutputTypes::OUT_WARNING,
|
||||||
"generateHousekeepingPacket",
|
"generateHousekeepingPacket",
|
||||||
QUEUE_OR_DESTINATION_INVALID);
|
QUEUE_OR_DESTINATION_INVALID);
|
||||||
@ -650,7 +673,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
|
|||||||
}
|
}
|
||||||
if(destination == MessageQueueIF::NO_QUEUE) {
|
if(destination == MessageQueueIF::NO_QUEUE) {
|
||||||
if(hkDestinationId == MessageQueueIF::NO_QUEUE) {
|
if(hkDestinationId == MessageQueueIF::NO_QUEUE) {
|
||||||
// error, all destinations invalid
|
/* Error, all destinations invalid */
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING,
|
printWarningOrError(sif::OutputTypes::OUT_WARNING,
|
||||||
"generateHousekeepingPacket",
|
"generateHousekeepingPacket",
|
||||||
QUEUE_OR_DESTINATION_INVALID);
|
QUEUE_OR_DESTINATION_INVALID);
|
||||||
@ -729,6 +752,12 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
|||||||
ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid,
|
ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid,
|
||||||
bool enable, bool isDiagnostics) {
|
bool enable, bool isDiagnostics) {
|
||||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||||
|
if(dataSet == nullptr) {
|
||||||
|
printWarningOrError(sif::OutputTypes::OUT_WARNING, "togglePeriodicGeneration",
|
||||||
|
DATASET_NOT_FOUND);
|
||||||
|
return DATASET_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
if((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or
|
if((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or
|
||||||
(not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) {
|
(not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) {
|
||||||
return WRONG_HK_PACKET_TYPE;
|
return WRONG_HK_PACKET_TYPE;
|
||||||
@ -746,6 +775,12 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid,
|
|||||||
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
|
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
|
||||||
float newCollectionInterval, bool isDiagnostics) {
|
float newCollectionInterval, bool isDiagnostics) {
|
||||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||||
|
if(dataSet == nullptr) {
|
||||||
|
printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval",
|
||||||
|
DATASET_NOT_FOUND);
|
||||||
|
return DATASET_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
|
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
|
||||||
if((targetIsDiagnostics and not isDiagnostics) or
|
if((targetIsDiagnostics and not isDiagnostics) or
|
||||||
(not targetIsDiagnostics and isDiagnostics)) {
|
(not targetIsDiagnostics and isDiagnostics)) {
|
||||||
@ -756,7 +791,7 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
|
|||||||
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);
|
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);
|
||||||
|
|
||||||
if(periodicHelper == nullptr) {
|
if(periodicHelper == nullptr) {
|
||||||
// config error
|
/* Configuration error, set might not have a corresponding pool manager */
|
||||||
return PERIODIC_HELPER_INVALID;
|
return PERIODIC_HELPER_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,13 +801,11 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
|
|||||||
|
|
||||||
ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid,
|
ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid,
|
||||||
bool isDiagnostics) {
|
bool isDiagnostics) {
|
||||||
// Get and check dataset first.
|
/* Get and check dataset first. */
|
||||||
//LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid);
|
|
||||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||||
if(dataSet == nullptr) {
|
if(dataSet == nullptr) {
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING,
|
printWarningOrError(sif::OutputTypes::OUT_WARNING,
|
||||||
"performPeriodicHkGeneration",
|
"performPeriodicHkGeneration", DATASET_NOT_FOUND);
|
||||||
DATASET_NOT_FOUND);
|
|
||||||
return DATASET_NOT_FOUND;
|
return DATASET_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -831,6 +864,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid,
|
|||||||
void LocalDataPoolManager::clearReceiversList() {
|
void LocalDataPoolManager::clearReceiversList() {
|
||||||
/* Clear the vector completely and releases allocated memory. */
|
/* Clear the vector completely and releases allocated memory. */
|
||||||
HkReceivers().swap(hkReceivers);
|
HkReceivers().swap(hkReceivers);
|
||||||
|
/* Also clear the reset helper if it exists */
|
||||||
|
if(hkUpdateResetList != nullptr) {
|
||||||
|
HkUpdateResetList().swap(*hkUpdateResetList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MutexIF* LocalDataPoolManager::getLocalPoolMutex() {
|
MutexIF* LocalDataPoolManager::getLocalPoolMutex() {
|
||||||
@ -843,6 +880,7 @@ object_id_t LocalDataPoolManager::getCreatorObjectId() const {
|
|||||||
|
|
||||||
void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
|
void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
|
||||||
const char* functionName, ReturnValue_t error, const char* errorPrint) {
|
const char* functionName, ReturnValue_t error, const char* errorPrint) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
if(errorPrint == nullptr) {
|
if(errorPrint == nullptr) {
|
||||||
if(error == DATASET_NOT_FOUND) {
|
if(error == DATASET_NOT_FOUND) {
|
||||||
errorPrint = "Dataset not found";
|
errorPrint = "Dataset not found";
|
||||||
@ -871,33 +909,32 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
|
|||||||
errorPrint = "Unknown error";
|
errorPrint = "Unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
object_id_t objectId = 0xffffffff;
|
||||||
|
if(owner != nullptr) {
|
||||||
|
objectId = owner->getObjectId();
|
||||||
|
}
|
||||||
|
|
||||||
if(outputType == sif::OutputTypes::OUT_WARNING) {
|
if(outputType == sif::OutputTypes::OUT_WARNING) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LocalDataPoolManager::" << functionName
|
sif::warning << "LocalDataPoolManager::" << functionName << ": Object ID 0x" <<
|
||||||
<< ": Object ID 0x" << std::setw(8) << std::setfill('0')
|
std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint <<
|
||||||
<< std::hex << owner->getObjectId() << " | " << errorPrint
|
std::dec << std::setfill(' ') << std::endl;
|
||||||
<< std::dec << std::setfill(' ') << std::endl;
|
|
||||||
#else
|
#else
|
||||||
sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
|
sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
|
||||||
functionName, owner->getObjectId(), errorPrint);
|
functionName, objectId, errorPrint);
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
|
||||||
}
|
}
|
||||||
else if(outputType == sif::OutputTypes::OUT_ERROR) {
|
else if(outputType == sif::OutputTypes::OUT_ERROR) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "LocalDataPoolManager::" << functionName
|
sif::error << "LocalDataPoolManager::" << functionName << ": Object ID 0x" <<
|
||||||
<< ": Object ID 0x" << std::setw(8) << std::setfill('0')
|
std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint <<
|
||||||
<< std::hex << owner->getObjectId() << " | " << errorPrint
|
std::dec << std::setfill(' ') << std::endl;
|
||||||
<< std::dec << std::setfill(' ') << std::endl;
|
|
||||||
#else
|
#else
|
||||||
sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
|
sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
|
||||||
functionName, owner->getObjectId(), errorPrint);
|
functionName, objectId, errorPrint);
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
|
||||||
}
|
}
|
||||||
|
#endif /* #if FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDataPoolManager* LocalDataPoolManager::getPoolManagerHandle() {
|
LocalDataPoolManager* LocalDataPoolManager::getPoolManagerHandle() {
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#include "../ipc/MutexIF.h"
|
#include "../ipc/MutexIF.h"
|
||||||
#include "../ipc/CommandMessage.h"
|
#include "../ipc/CommandMessage.h"
|
||||||
#include "../ipc/MessageQueueIF.h"
|
#include "../ipc/MessageQueueIF.h"
|
||||||
#include "../ipc/MutexHelper.h"
|
#include "../ipc/MutexGuard.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -391,6 +391,10 @@ protected:
|
|||||||
|
|
||||||
template<class T> inline
|
template<class T> inline
|
||||||
ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, PoolEntry<T> **poolEntry) {
|
ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, PoolEntry<T> **poolEntry) {
|
||||||
|
if(poolEntry == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
auto poolIter = localPoolMap.find(localPoolId);
|
auto poolIter = localPoolMap.find(localPoolId);
|
||||||
if (poolIter == localPoolMap.end()) {
|
if (poolIter == localPoolMap.end()) {
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry",
|
printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry",
|
||||||
|
@ -58,8 +58,7 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registere
|
|||||||
this->sid = sid;
|
this->sid = sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalPoolDataSetBase::LocalPoolDataSetBase(
|
LocalPoolDataSetBase::LocalPoolDataSetBase(PoolVariableIF **registeredVariablesArray,
|
||||||
PoolVariableIF **registeredVariablesArray,
|
|
||||||
const size_t maxNumberOfVariables, bool protectEveryReadCommitCall):
|
const size_t maxNumberOfVariables, bool protectEveryReadCommitCall):
|
||||||
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
|
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
|
||||||
this->setReadCommitProtectionBehaviour(protectEveryReadCommitCall);
|
this->setReadCommitProtectionBehaviour(protectEveryReadCommitCall);
|
||||||
@ -95,14 +94,23 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer
|
|||||||
size_t *size, size_t maxSize,
|
size_t *size, size_t maxSize,
|
||||||
SerializeIF::Endianness streamEndianness) const {
|
SerializeIF::Endianness streamEndianness) const {
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||||
uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount)/8.0);
|
const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount)/8.0);
|
||||||
uint8_t validityMask[validityMaskSize] = {};
|
uint8_t* validityPtr = nullptr;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
/* Use a std::vector here because MSVC will (rightly) not create a fixed size array
|
||||||
|
with a non constant size specifier */
|
||||||
|
std::vector<uint8_t> validityMask(validityMaskSize);
|
||||||
|
validityPtr = validityMask.data();
|
||||||
|
#else
|
||||||
|
uint8_t validityMask[validityMaskSize] = {0};
|
||||||
|
validityPtr = validityMask;
|
||||||
|
#endif
|
||||||
uint8_t validBufferIndex = 0;
|
uint8_t validBufferIndex = 0;
|
||||||
uint8_t validBufferIndexBit = 0;
|
uint8_t validBufferIndexBit = 0;
|
||||||
for (uint16_t count = 0; count < fillCount; count++) {
|
for (uint16_t count = 0; count < fillCount; count++) {
|
||||||
if(registeredVariables[count]->isValid()) {
|
if(registeredVariables[count]->isValid()) {
|
||||||
/* Set bit at correct position */
|
/* Set bit at correct position */
|
||||||
bitutil::bitSet(validityMask + validBufferIndex, validBufferIndexBit);
|
bitutil::bitSet(validityPtr + validBufferIndex, validBufferIndexBit);
|
||||||
}
|
}
|
||||||
if(validBufferIndexBit == 7) {
|
if(validBufferIndexBit == 7) {
|
||||||
validBufferIndex ++;
|
validBufferIndex ++;
|
||||||
@ -123,7 +131,7 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer
|
|||||||
return SerializeIF::BUFFER_TOO_SHORT;
|
return SerializeIF::BUFFER_TOO_SHORT;
|
||||||
}
|
}
|
||||||
// copy validity buffer to end
|
// copy validity buffer to end
|
||||||
std::memcpy(*buffer, validityMask, validityMaskSize);
|
std::memcpy(*buffer, validityPtr, validityMaskSize);
|
||||||
*size += validityMaskSize;
|
*size += validityMaskSize;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -262,11 +270,9 @@ bool LocalPoolDataSetBase::getReportingEnabled() const {
|
|||||||
return reportingEnabled;
|
return reportingEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalPoolDataSetBase::initializePeriodicHelper(
|
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
|
||||||
float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
dur_millis_t minimumPeriodicInterval, uint8_t nonDiagIntervalFactor) {
|
||||||
bool isDiagnostics, uint8_t nonDiagIntervalFactor) {
|
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor);
|
||||||
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval,
|
|
||||||
isDiagnostics, nonDiagIntervalFactor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalPoolDataSetBase::setChanged(bool changed) {
|
void LocalPoolDataSetBase::setChanged(bool changed) {
|
||||||
@ -306,3 +312,12 @@ void LocalPoolDataSetBase::setAllVariablesReadOnly() {
|
|||||||
registeredVariables[idx]->setReadWriteMode(pool_rwm_t::VAR_READ);
|
registeredVariables[idx]->setReadWriteMode(pool_rwm_t::VAR_READ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float LocalPoolDataSetBase::getCollectionInterval() const {
|
||||||
|
if(periodicHelper != nullptr) {
|
||||||
|
return periodicHelper->getCollectionIntervalInSeconds();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -166,6 +166,16 @@ public:
|
|||||||
|
|
||||||
object_id_t getCreatorObjectId();
|
object_id_t getCreatorObjectId();
|
||||||
|
|
||||||
|
bool getReportingEnabled() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current periodic HK generation interval this set
|
||||||
|
* belongs to a HK manager and the interval is not 0. Otherwise,
|
||||||
|
* returns 0.0
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
float getCollectionInterval() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
sid_t sid;
|
sid_t sid;
|
||||||
//! This mutex is used if the data is created by one object only.
|
//! This mutex is used if the data is created by one object only.
|
||||||
@ -180,11 +190,9 @@ protected:
|
|||||||
*/
|
*/
|
||||||
bool reportingEnabled = false;
|
bool reportingEnabled = false;
|
||||||
void setReportingEnabled(bool enabled);
|
void setReportingEnabled(bool enabled);
|
||||||
bool getReportingEnabled() const;
|
|
||||||
|
|
||||||
void initializePeriodicHelper(float collectionInterval,
|
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||||
dur_millis_t minimumPeriodicInterval,
|
uint8_t nonDiagIntervalFactor = 5);
|
||||||
bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the valid state of a dataset is always relevant to the whole
|
* If the valid state of a dataset is always relevant to the whole
|
||||||
|
@ -25,7 +25,7 @@ inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId,
|
|||||||
template<typename T, uint16_t vectorSize>
|
template<typename T, uint16_t vectorSize>
|
||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::read(
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::read(
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
||||||
MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
|
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
|
||||||
return readWithoutLock();
|
return readWithoutLock();
|
||||||
}
|
}
|
||||||
template<typename T, uint16_t vectorSize>
|
template<typename T, uint16_t vectorSize>
|
||||||
@ -64,7 +64,7 @@ inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(bool valid,
|
|||||||
template<typename T, uint16_t vectorSize>
|
template<typename T, uint16_t vectorSize>
|
||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
||||||
MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
|
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
|
||||||
return commitWithoutLock();
|
return commitWithoutLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,37 @@
|
|||||||
#include "SharedLocalDataSet.h"
|
#include "SharedLocalDataSet.h"
|
||||||
|
|
||||||
|
|
||||||
SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId, sid_t sid,
|
SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId, sid_t sid,
|
||||||
const size_t maxSize): SystemObject(objectId),
|
const size_t maxSize): SystemObject(objectId),
|
||||||
LocalPoolDataSetBase(sid, nullptr, maxSize) {
|
LocalPoolDataSetBase(sid, nullptr, maxSize), poolVarVector(maxSize) {
|
||||||
this->setContainer(poolVarVector.data());
|
this->setContainer(poolVarVector.data());
|
||||||
datasetLock = MutexFactory::instance()->createMutex();
|
datasetLock = MutexFactory::instance()->createMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t SharedLocalDataSet::lockDataset(dur_millis_t mutexTimeout) {
|
SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId,
|
||||||
return datasetLock->lockMutex(MutexIF::TimeoutType::WAITING, mutexTimeout);
|
HasLocalDataPoolIF *owner, uint32_t setId,
|
||||||
|
const size_t maxSize): SystemObject(objectId),
|
||||||
|
LocalPoolDataSetBase(owner, setId, nullptr, maxSize), poolVarVector(maxSize) {
|
||||||
|
this->setContainer(poolVarVector.data());
|
||||||
|
datasetLock = MutexFactory::instance()->createMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t SharedLocalDataSet::lockDataset(MutexIF::TimeoutType timeoutType,
|
||||||
|
dur_millis_t mutexTimeout) {
|
||||||
|
if(datasetLock != nullptr) {
|
||||||
|
return datasetLock->lockMutex(timeoutType, mutexTimeout);
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SharedLocalDataSet::~SharedLocalDataSet() {
|
||||||
|
MutexFactory::instance()->deleteMutex(datasetLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t SharedLocalDataSet::unlockDataset() {
|
ReturnValue_t SharedLocalDataSet::unlockDataset() {
|
||||||
|
if(datasetLock != nullptr) {
|
||||||
return datasetLock->unlockMutex();
|
return datasetLock->unlockMutex();
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -11,16 +11,22 @@
|
|||||||
* multiple threads. It provides a lock in addition to all other functionalities provided
|
* multiple threads. It provides a lock in addition to all other functionalities provided
|
||||||
* by the LocalPoolDataSetBase class.
|
* by the LocalPoolDataSetBase class.
|
||||||
*
|
*
|
||||||
* TODO: override and protect read, commit and some other calls used by pool manager.
|
* The user is completely responsible for lockingand unlocking the dataset when using the
|
||||||
|
* shared dataset.
|
||||||
*/
|
*/
|
||||||
class SharedLocalDataSet:
|
class SharedLocalDataSet:
|
||||||
public SystemObject,
|
public SystemObject,
|
||||||
public LocalPoolDataSetBase,
|
public LocalPoolDataSetBase,
|
||||||
public SharedDataSetIF {
|
public SharedDataSetIF {
|
||||||
public:
|
public:
|
||||||
SharedLocalDataSet(object_id_t objectId, sid_t sid,
|
SharedLocalDataSet(object_id_t objectId, HasLocalDataPoolIF* owner, uint32_t setId,
|
||||||
const size_t maxSize);
|
const size_t maxSize);
|
||||||
ReturnValue_t lockDataset(dur_millis_t mutexTimeout) override;
|
SharedLocalDataSet(object_id_t objectId, sid_t sid, const size_t maxSize);
|
||||||
|
|
||||||
|
virtual~ SharedLocalDataSet();
|
||||||
|
|
||||||
|
ReturnValue_t lockDataset(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||||
|
dur_millis_t mutexTimeout = 20) override;
|
||||||
ReturnValue_t unlockDataset() override;
|
ReturnValue_t unlockDataset() override;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
12
datapoollocal/datapoollocal.h
Normal file
12
datapoollocal/datapoollocal.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
|
||||||
|
#define FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
|
||||||
|
|
||||||
|
/* Collected related headers */
|
||||||
|
#include "LocalPoolVariable.h"
|
||||||
|
#include "LocalPoolVector.h"
|
||||||
|
#include "StaticLocalDataSet.h"
|
||||||
|
#include "LocalDataSet.h"
|
||||||
|
#include "SharedLocalDataSet.h"
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ */
|
@ -14,9 +14,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
|
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
|
||||||
uint32_t minimumPeriodicIntervalMs,
|
uint32_t minimumPeriodicIntervalMs, uint8_t nonDiagIntervalFactor = 5) {
|
||||||
bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5) {
|
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs,
|
||||||
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs, isDiagnostics,
|
|
||||||
nonDiagIntervalFactor);
|
nonDiagIntervalFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,11 +96,11 @@ union gp_id_t {
|
|||||||
return raw == INVALID_GPID;
|
return raw == INVALID_GPID;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const sid_t& other) const {
|
bool operator==(const gp_id_t& other) const {
|
||||||
return raw == other.raw;
|
return raw == other.raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const sid_t& other) const {
|
bool operator!=(const gp_id_t& other) const {
|
||||||
return not (raw == other.raw);
|
return not (raw == other.raw);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -40,6 +40,13 @@
|
|||||||
//! Specify whether a special mode store is used for Subsystem components.
|
//! Specify whether a special mode store is used for Subsystem components.
|
||||||
#define FSFW_USE_MODESTORE 0
|
#define FSFW_USE_MODESTORE 0
|
||||||
|
|
||||||
|
//! Defines if the real time scheduler for linux should be used.
|
||||||
|
//! If set to 0, this will also disable priority settings for linux
|
||||||
|
//! as most systems will not allow to set nice values without privileges
|
||||||
|
//! For embedded linux system set this to 1.
|
||||||
|
//! If set to 1 the binary needs "cap_sys_nice=eip" privileges to run
|
||||||
|
#define FSFW_USE_REALTIME_FOR_LINUX 1
|
||||||
|
|
||||||
namespace fsfwconfig {
|
namespace fsfwconfig {
|
||||||
//! Default timestamp size. The default timestamp will be an eight byte CDC
|
//! Default timestamp size. The default timestamp will be an eight byte CDC
|
||||||
//! short timestamp.
|
//! short timestamp.
|
||||||
@ -52,11 +59,12 @@ static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
|
|||||||
|
|
||||||
//! Defines the FIFO depth of each commanding service base which
|
//! Defines the FIFO depth of each commanding service base which
|
||||||
//! also determines how many commands a CSB service can handle in one cycle
|
//! also determines how many commands a CSB service can handle in one cycle
|
||||||
//! simulataneously. This will increase the required RAM for
|
//! simultaneously. This will increase the required RAM for
|
||||||
//! each CSB service !
|
//! each CSB service !
|
||||||
static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6;
|
static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6;
|
||||||
|
|
||||||
static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124;
|
static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_FSFWCONFIG_H_ */
|
#endif /* CONFIG_FSFWCONFIG_H_ */
|
||||||
|
@ -1483,7 +1483,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
|
|||||||
if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) {
|
if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) {
|
||||||
errorPrint = "Initialization error";
|
errorPrint = "Initialization error";
|
||||||
}
|
}
|
||||||
if(errorCode == HasReturnvaluesIF::RETURN_FAILED) {
|
else if(errorCode == HasReturnvaluesIF::RETURN_FAILED) {
|
||||||
if(errorType == sif::OutputTypes::OUT_WARNING) {
|
if(errorType == sif::OutputTypes::OUT_WARNING) {
|
||||||
errorPrint = "Generic Warning";
|
errorPrint = "Generic Warning";
|
||||||
}
|
}
|
||||||
@ -1495,6 +1495,9 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
|
|||||||
errorPrint = "Unknown error";
|
errorPrint = "Unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(functionName == nullptr) {
|
||||||
|
functionName = "unknown function";
|
||||||
|
}
|
||||||
|
|
||||||
if(errorType == sif::OutputTypes::OUT_WARNING) {
|
if(errorType == sif::OutputTypes::OUT_WARNING) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -1504,7 +1507,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
|
|||||||
<< std::setfill(' ') << std::endl;
|
<< std::setfill(' ') << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
|
sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
|
||||||
this->getObjectId(), errorPrint);
|
functionName, this->getObjectId(), errorPrint);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if(errorType == sif::OutputTypes::OUT_ERROR) {
|
else if(errorType == sif::OutputTypes::OUT_ERROR) {
|
||||||
@ -1515,7 +1518,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
|
|||||||
<< std::setfill(' ') << std::endl;
|
<< std::setfill(' ') << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
|
sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
|
||||||
this->getObjectId(), errorPrint);
|
functionName, this->getObjectId(), errorPrint);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +16,9 @@ ReturnValue_t HealthDevice::performOperation(uint8_t opCode) {
|
|||||||
CommandMessage command;
|
CommandMessage command;
|
||||||
ReturnValue_t result = commandQueue->receiveMessage(&command);
|
ReturnValue_t result = commandQueue->receiveMessage(&command);
|
||||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
healthHelper.handleHealthCommand(&command);
|
result = healthHelper.handleHealthCommand(&command);
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t HealthDevice::initialize() {
|
ReturnValue_t HealthDevice::initialize() {
|
||||||
|
@ -109,6 +109,6 @@ bool EventMessage::isClearedEventMessage() {
|
|||||||
return getEvent() == INVALID_EVENT;
|
return getEvent() == INVALID_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t EventMessage::getMinimumMessageSize() {
|
size_t EventMessage::getMinimumMessageSize() const {
|
||||||
return EVENT_MESSAGE_SIZE;
|
return EVENT_MESSAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const Event INVALID_EVENT = 0;
|
static const Event INVALID_EVENT = 0;
|
||||||
virtual size_t getMinimumMessageSize();
|
virtual size_t getMinimumMessageSize() const override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ void arrayprinter::printHex(const uint8_t *data, size_t size,
|
|||||||
#else
|
#else
|
||||||
// General format: 0x01, 0x02, 0x03 so it is number of chars times 6
|
// General format: 0x01, 0x02, 0x03 so it is number of chars times 6
|
||||||
// plus line break plus small safety margin.
|
// plus line break plus small safety margin.
|
||||||
char printBuffer[(size + 1) * 7 + 1];
|
char printBuffer[(size + 1) * 7 + 1] = {};
|
||||||
size_t currentPos = 0;
|
size_t currentPos = 0;
|
||||||
for(size_t i = 0; i < size; i++) {
|
for(size_t i = 0; i < size; i++) {
|
||||||
// To avoid buffer overflows.
|
// To avoid buffer overflows.
|
||||||
@ -67,7 +67,9 @@ void arrayprinter::printHex(const uint8_t *data, size_t size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if FSFW_DISABLE_PRINTOUT == 0
|
||||||
printf("[%s]\n", printBuffer);
|
printf("[%s]\n", printBuffer);
|
||||||
|
#endif /* FSFW_DISABLE_PRINTOUT == 0 */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +94,7 @@ void arrayprinter::printDec(const uint8_t *data, size_t size,
|
|||||||
#else
|
#else
|
||||||
// General format: 32, 243, -12 so it is number of chars times 5
|
// General format: 32, 243, -12 so it is number of chars times 5
|
||||||
// plus line break plus small safety margin.
|
// plus line break plus small safety margin.
|
||||||
char printBuffer[(size + 1) * 5 + 1];
|
char printBuffer[(size + 1) * 5 + 1] = {};
|
||||||
size_t currentPos = 0;
|
size_t currentPos = 0;
|
||||||
for(size_t i = 0; i < size; i++) {
|
for(size_t i = 0; i < size; i++) {
|
||||||
// To avoid buffer overflows.
|
// To avoid buffer overflows.
|
||||||
@ -108,7 +110,9 @@ void arrayprinter::printDec(const uint8_t *data, size_t size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if FSFW_DISABLE_PRINTOUT == 0
|
||||||
printf("[%s]\n", printBuffer);
|
printf("[%s]\n", printBuffer);
|
||||||
|
#endif /* FSFW_DISABLE_PRINTOUT == 0 */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "HealthTable.h"
|
#include "HealthTable.h"
|
||||||
#include "../ipc/MutexHelper.h"
|
#include "../ipc/MutexGuard.h"
|
||||||
#include "../ipc/MutexFactory.h"
|
#include "../ipc/MutexFactory.h"
|
||||||
#include "../serialize/SerializeAdapter.h"
|
#include "../serialize/SerializeAdapter.h"
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ ReturnValue_t HealthTable::registerObject(object_id_t object,
|
|||||||
|
|
||||||
void HealthTable::setHealth(object_id_t object,
|
void HealthTable::setHealth(object_id_t object,
|
||||||
HasHealthIF::HealthState newState) {
|
HasHealthIF::HealthState newState) {
|
||||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
||||||
HealthMap::iterator iter = healthMap.find(object);
|
HealthMap::iterator iter = healthMap.find(object);
|
||||||
if (iter != healthMap.end()) {
|
if (iter != healthMap.end()) {
|
||||||
iter->second = newState;
|
iter->second = newState;
|
||||||
@ -40,7 +40,7 @@ void HealthTable::setHealth(object_id_t object,
|
|||||||
|
|
||||||
HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) {
|
HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) {
|
||||||
HasHealthIF::HealthState state = HasHealthIF::HEALTHY;
|
HasHealthIF::HealthState state = HasHealthIF::HEALTHY;
|
||||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
||||||
HealthMap::iterator iter = healthMap.find(object);
|
HealthMap::iterator iter = healthMap.find(object);
|
||||||
if (iter != healthMap.end()) {
|
if (iter != healthMap.end()) {
|
||||||
state = iter->second;
|
state = iter->second;
|
||||||
@ -49,7 +49,7 @@ HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HealthTable::hasHealth(object_id_t object) {
|
bool HealthTable::hasHealth(object_id_t object) {
|
||||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
||||||
HealthMap::iterator iter = healthMap.find(object);
|
HealthMap::iterator iter = healthMap.find(object);
|
||||||
if (iter != healthMap.end()) {
|
if (iter != healthMap.end()) {
|
||||||
return true;
|
return true;
|
||||||
@ -58,35 +58,51 @@ bool HealthTable::hasHealth(object_id_t object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t HealthTable::getPrintSize() {
|
size_t HealthTable::getPrintSize() {
|
||||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
||||||
uint32_t size = healthMap.size() * sizeof(object_id_t) +
|
uint32_t size = healthMap.size() * sizeof(object_id_t) +
|
||||||
sizeof(HasHealthIF::HealthState) + sizeof(uint16_t);
|
sizeof(HasHealthIF::HealthState) + sizeof(uint16_t);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HealthTable::printAll(uint8_t* pointer, size_t maxSize) {
|
void HealthTable::printAll(uint8_t* pointer, size_t maxSize) {
|
||||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
uint16_t count = healthMap.size();
|
uint16_t count = healthMap.size();
|
||||||
SerializeAdapter::serialize(&count,
|
ReturnValue_t result = SerializeAdapter::serialize(&count,
|
||||||
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "HealthTable::printAll: Serialization of health table failed" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning("HealthTable::printAll: Serialization of health table failed\n");
|
||||||
|
#endif
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (const auto& health: healthMap) {
|
for (const auto& health: healthMap) {
|
||||||
SerializeAdapter::serialize(&health.first,
|
result = SerializeAdapter::serialize(&health.first,
|
||||||
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
uint8_t healthValue = health.second;
|
uint8_t healthValue = health.second;
|
||||||
SerializeAdapter::serialize(&healthValue, &pointer, &size,
|
result = SerializeAdapter::serialize(&healthValue, &pointer, &size,
|
||||||
maxSize, SerializeIF::Endianness::BIG);
|
maxSize, SerializeIF::Endianness::BIG);
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) {
|
ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) {
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||||
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
||||||
if (reset) {
|
if (reset) {
|
||||||
mapIterator = healthMap.begin();
|
mapIterator = healthMap.begin();
|
||||||
}
|
}
|
||||||
if (mapIterator == healthMap.end()) {
|
if (mapIterator == healthMap.end()) {
|
||||||
result = HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
*value = *mapIterator;
|
*value = *mapIterator;
|
||||||
mapIterator++;
|
mapIterator++;
|
||||||
|
@ -84,15 +84,21 @@ void HousekeepingMessage::setCollectionIntervalModificationCommand(
|
|||||||
else {
|
else {
|
||||||
command->setCommand(MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL);
|
command->setCommand(MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL);
|
||||||
}
|
}
|
||||||
command->setParameter3(collectionInterval);
|
|
||||||
|
/* Raw storage of the float in the message. Do not use setParameter3, does
|
||||||
|
implicit conversion to integer type! */
|
||||||
|
std::memcpy(command->getData() + 2 * sizeof(uint32_t), &collectionInterval,
|
||||||
|
sizeof(collectionInterval));
|
||||||
|
|
||||||
setSid(command, sid);
|
setSid(command, sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
sid_t HousekeepingMessage::getCollectionIntervalModificationCommand(
|
sid_t HousekeepingMessage::getCollectionIntervalModificationCommand(
|
||||||
const CommandMessage* command, float* newCollectionInterval) {
|
const CommandMessage* command, float* newCollectionInterval) {
|
||||||
|
|
||||||
if(newCollectionInterval != nullptr) {
|
if(newCollectionInterval != nullptr) {
|
||||||
*newCollectionInterval = command->getParameter3();
|
std::memcpy(newCollectionInterval, command->getData() + 2 * sizeof(uint32_t),
|
||||||
|
sizeof(*newCollectionInterval));
|
||||||
}
|
}
|
||||||
|
|
||||||
return getSid(command);
|
return getSid(command);
|
||||||
@ -151,7 +157,8 @@ void HousekeepingMessage::clear(CommandMessage* message) {
|
|||||||
case(DIAGNOSTICS_REPORT):
|
case(DIAGNOSTICS_REPORT):
|
||||||
case(HK_DEFINITIONS_REPORT):
|
case(HK_DEFINITIONS_REPORT):
|
||||||
case(DIAGNOSTICS_DEFINITION_REPORT):
|
case(DIAGNOSTICS_DEFINITION_REPORT):
|
||||||
case(UPDATE_SNAPSHOT_SET): {
|
case(UPDATE_SNAPSHOT_SET):
|
||||||
|
case(UPDATE_SNAPSHOT_VARIABLE): {
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
getHkDataReply(message, &storeId);
|
getHkDataReply(message, &storeId);
|
||||||
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
* @brief This helper class will be used to serialize and deserialize update housekeeping packets
|
* @brief This helper class will be used to serialize and deserialize update housekeeping packets
|
||||||
* into the store.
|
* into the store.
|
||||||
*/
|
*/
|
||||||
class HousekeepingSnapshot: public SerializeIF {
|
class HousekeepingSnapshot:
|
||||||
|
public SerializeIF {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,6 +37,17 @@ public:
|
|||||||
timeStamp(timeStamp), timeStampSize(timeStampSize),
|
timeStamp(timeStamp), timeStampSize(timeStampSize),
|
||||||
updateData(dataSetPtr) {};
|
updateData(dataSetPtr) {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update packet constructor for pool variables.
|
||||||
|
* @param timeStamp
|
||||||
|
* @param timeStampSize
|
||||||
|
* @param dataSetPtr
|
||||||
|
*/
|
||||||
|
HousekeepingSnapshot(CCSDSTime::CDS_short* cdsShort, LocalPoolObjectBase* dataSetPtr):
|
||||||
|
timeStamp(reinterpret_cast<uint8_t*>(cdsShort)),
|
||||||
|
timeStampSize(sizeof(CCSDSTime::CDS_short)), updateData(dataSetPtr) {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update packet constructor for pool variables.
|
* Update packet constructor for pool variables.
|
||||||
* @param timeStamp
|
* @param timeStamp
|
||||||
@ -47,8 +59,8 @@ public:
|
|||||||
timeStamp(timeStamp), timeStampSize(timeStampSize),
|
timeStamp(timeStamp), timeStampSize(timeStampSize),
|
||||||
updateData(dataSetPtr) {};
|
updateData(dataSetPtr) {};
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size,
|
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||||
size_t maxSize, Endianness streamEndianness) const {
|
Endianness streamEndianness) const {
|
||||||
if(timeStamp != nullptr) {
|
if(timeStamp != nullptr) {
|
||||||
/* Endianness will always be MACHINE, so we can simply use memcpy
|
/* Endianness will always be MACHINE, so we can simply use memcpy
|
||||||
here. */
|
here. */
|
||||||
|
@ -6,20 +6,18 @@
|
|||||||
PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(
|
PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(
|
||||||
LocalPoolDataSetBase* owner): owner(owner) {}
|
LocalPoolDataSetBase* owner): owner(owner) {}
|
||||||
|
|
||||||
|
|
||||||
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
|
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
|
||||||
dur_millis_t minimumPeriodicInterval, bool isDiagnostics,
|
dur_millis_t minimumPeriodicInterval, uint8_t nonDiagIntervalFactor) {
|
||||||
uint8_t nonDiagIntervalFactor) {
|
|
||||||
this->minimumPeriodicInterval = minimumPeriodicInterval;
|
this->minimumPeriodicInterval = minimumPeriodicInterval;
|
||||||
if(not isDiagnostics) {
|
this->nonDiagIntervalFactor = nonDiagIntervalFactor;
|
||||||
this->minimumPeriodicInterval = this->minimumPeriodicInterval *
|
collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval);
|
||||||
nonDiagIntervalFactor;
|
/* 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. */
|
||||||
collectionIntervalTicks = intervalSecondsToInterval(collectionInterval);
|
internalTickCounter = collectionIntervalTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() {
|
float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() const {
|
||||||
return intervalToIntervalSeconds(collectionIntervalTicks);
|
return intervalTicksToSeconds(collectionIntervalTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeriodicHousekeepingHelper::checkOpNecessary() {
|
bool PeriodicHousekeepingHelper::checkOpNecessary() {
|
||||||
@ -31,19 +29,62 @@ bool PeriodicHousekeepingHelper::checkOpNecessary() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PeriodicHousekeepingHelper::intervalSecondsToInterval(
|
uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks(
|
||||||
float collectionIntervalSeconds) {
|
float collectionIntervalSeconds) {
|
||||||
return std::ceil(collectionIntervalSeconds * 1000
|
if(owner == nullptr) {
|
||||||
/ minimumPeriodicInterval);
|
return 0;
|
||||||
|
}
|
||||||
|
bool isDiagnostics = owner->isDiagnostics();
|
||||||
|
|
||||||
|
/* Avoid division by zero */
|
||||||
|
if(minimumPeriodicInterval == 0) {
|
||||||
|
if(isDiagnostics) {
|
||||||
|
/* Perform operation each cycle */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nonDiagIntervalFactor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dur_millis_t intervalInMs = collectionIntervalSeconds * 1000;
|
||||||
|
uint32_t divisor = minimumPeriodicInterval;
|
||||||
|
if(not isDiagnostics) {
|
||||||
|
/* We need to multiply the divisor because non-diagnostics only
|
||||||
|
allow a multiple of the minimum periodic interval */
|
||||||
|
divisor *= nonDiagIntervalFactor;
|
||||||
|
}
|
||||||
|
uint32_t ticks = std::ceil(static_cast<float>(intervalInMs) / divisor);
|
||||||
|
if(not isDiagnostics) {
|
||||||
|
/* Now we need to multiply the calculated ticks with the factor as as well
|
||||||
|
because the minimum tick count to generate a non-diagnostic is the factor itself.
|
||||||
|
|
||||||
|
Example calculation for non-diagnostic with
|
||||||
|
0.4 second interval and 0.2 second task interval.
|
||||||
|
Resultant tick count of 5 is equal to operation each second.
|
||||||
|
|
||||||
|
Examle calculation for non-diagnostic with 2.0 second interval and 0.2 second
|
||||||
|
task interval.
|
||||||
|
Resultant tick count of 10 is equal to operatin every 2 seconds.
|
||||||
|
|
||||||
|
Example calculation for diagnostic with 0.4 second interval and 0.3
|
||||||
|
second task interval. Resulting tick count of 2 is equal to operation
|
||||||
|
every 0.6 seconds. */
|
||||||
|
ticks *= nonDiagIntervalFactor;
|
||||||
|
}
|
||||||
|
return ticks;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float PeriodicHousekeepingHelper::intervalToIntervalSeconds(
|
float PeriodicHousekeepingHelper::intervalTicksToSeconds(
|
||||||
uint32_t collectionInterval) {
|
uint32_t collectionInterval) const {
|
||||||
return static_cast<float>(collectionInterval *
|
/* Number of ticks times the minimum interval is in milliseconds, so we divide by 1000 to get
|
||||||
minimumPeriodicInterval);
|
the value in seconds */
|
||||||
|
return static_cast<float>(collectionInterval * minimumPeriodicInterval / 1000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicHousekeepingHelper::changeCollectionInterval(
|
void PeriodicHousekeepingHelper::changeCollectionInterval(
|
||||||
float newIntervalSeconds) {
|
float newIntervalSeconds) {
|
||||||
collectionIntervalTicks = intervalSecondsToInterval(newIntervalSeconds);
|
collectionIntervalTicks = intervalSecondsToIntervalTicks(newIntervalSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,18 +10,19 @@ class PeriodicHousekeepingHelper {
|
|||||||
public:
|
public:
|
||||||
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
|
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
|
||||||
|
|
||||||
void initialize(float collectionInterval,
|
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||||
dur_millis_t minimumPeriodicInterval, bool isDiagnostics,
|
|
||||||
uint8_t nonDiagIntervalFactor);
|
uint8_t nonDiagIntervalFactor);
|
||||||
|
|
||||||
void changeCollectionInterval(float newInterval);
|
void changeCollectionInterval(float newInterval);
|
||||||
float getCollectionIntervalInSeconds();
|
float getCollectionIntervalInSeconds() const;
|
||||||
bool checkOpNecessary();
|
bool checkOpNecessary();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LocalPoolDataSetBase* owner = nullptr;
|
LocalPoolDataSetBase* owner = nullptr;
|
||||||
|
uint8_t nonDiagIntervalFactor = 0;
|
||||||
|
|
||||||
uint32_t intervalSecondsToInterval(float collectionIntervalSeconds);
|
uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds);
|
||||||
float intervalToIntervalSeconds(uint32_t collectionInterval);
|
float intervalTicksToSeconds(uint32_t collectionInterval) const;
|
||||||
|
|
||||||
dur_millis_t minimumPeriodicInterval = 0;
|
dur_millis_t minimumPeriodicInterval = 0;
|
||||||
uint32_t internalTickCounter = 1;
|
uint32_t internalTickCounter = 1;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "../ipc/QueueFactory.h"
|
#include "../ipc/QueueFactory.h"
|
||||||
#include "../ipc/MutexFactory.h"
|
#include "../ipc/MutexFactory.h"
|
||||||
#include "../serviceinterface/ServiceInterface.h"
|
#include "../serviceinterface/ServiceInterface.h"
|
||||||
|
#include "../datapool/PoolReadGuard.h"
|
||||||
|
|
||||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId,
|
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId,
|
||||||
uint32_t messageQueueDepth): SystemObject(setObjectId),
|
uint32_t messageQueueDepth): SystemObject(setObjectId),
|
||||||
@ -23,13 +24,17 @@ void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
||||||
internalErrorDataset.read(timeoutType, timeoutMs);
|
CommandMessage message;
|
||||||
|
ReturnValue_t result = commandQueue->receiveMessage(&message);
|
||||||
|
if(result != MessageQueueIF::EMPTY) {
|
||||||
|
poolManager.handleHousekeepingMessage(&message);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t newQueueHits = getAndResetQueueHits();
|
uint32_t newQueueHits = getAndResetQueueHits();
|
||||||
uint32_t newTmHits = getAndResetTmHits();
|
uint32_t newTmHits = getAndResetTmHits();
|
||||||
uint32_t newStoreHits = getAndResetStoreHits();
|
uint32_t newStoreHits = getAndResetStoreHits();
|
||||||
|
|
||||||
#if FSFW_VERBOSE_LEVEL == 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
if(diagnosticPrintout) {
|
if(diagnosticPrintout) {
|
||||||
if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -48,19 +53,17 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
PoolReadGuard readGuard(&internalErrorDataset);
|
||||||
|
if(readGuard.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
|
||||||
internalErrorDataset.queueHits.value += newQueueHits;
|
internalErrorDataset.queueHits.value += newQueueHits;
|
||||||
internalErrorDataset.storeHits.value += newStoreHits;
|
internalErrorDataset.storeHits.value += newStoreHits;
|
||||||
internalErrorDataset.tmHits.value += newTmHits;
|
internalErrorDataset.tmHits.value += newTmHits;
|
||||||
internalErrorDataset.setValidity(true, true);
|
internalErrorDataset.setValidity(true, true);
|
||||||
internalErrorDataset.commit(timeoutType, timeoutMs);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
poolManager.performHkOperation();
|
poolManager.performHkOperation();
|
||||||
|
|
||||||
CommandMessage message;
|
|
||||||
ReturnValue_t result = commandQueue->receiveMessage(&message);
|
|
||||||
if(result != MessageQueueIF::EMPTY) {
|
|
||||||
poolManager.handleHousekeepingMessage(&message);
|
|
||||||
}
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,14 +158,11 @@ MessageQueueId_t InternalErrorReporter::getCommandQueue() const {
|
|||||||
|
|
||||||
ReturnValue_t InternalErrorReporter::initializeLocalDataPool(
|
ReturnValue_t InternalErrorReporter::initializeLocalDataPool(
|
||||||
localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
|
localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
|
||||||
localDataPoolMap.emplace(errorPoolIds::TM_HITS,
|
localDataPoolMap.emplace(errorPoolIds::TM_HITS, new PoolEntry<uint32_t>());
|
||||||
new PoolEntry<uint32_t>());
|
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, new PoolEntry<uint32_t>());
|
||||||
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS,
|
localDataPoolMap.emplace(errorPoolIds::STORE_HITS, new PoolEntry<uint32_t>());
|
||||||
new PoolEntry<uint32_t>());
|
poolManager.subscribeForPeriodicPacket(internalErrorSid, false, getPeriodicOperationFrequency(),
|
||||||
localDataPoolMap.emplace(errorPoolIds::STORE_HITS,
|
true);
|
||||||
new PoolEntry<uint32_t>());
|
|
||||||
poolManager.subscribeForPeriodicPacket(internalErrorSid, false,
|
|
||||||
getPeriodicOperationFrequency(), true);
|
|
||||||
internalErrorDataset.setValidity(true, true);
|
internalErrorDataset.setValidity(true, true);
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
* All functions were kept virtual so this class can be extended easily
|
* All functions were kept virtual so this class can be extended easily
|
||||||
* to store custom internal errors (e.g. communication interface errors).
|
* to store custom internal errors (e.g. communication interface errors).
|
||||||
*/
|
*/
|
||||||
class InternalErrorReporter: public SystemObject,
|
class InternalErrorReporter:
|
||||||
|
public SystemObject,
|
||||||
public ExecutableObjectIF,
|
public ExecutableObjectIF,
|
||||||
public InternalErrorReporterIF,
|
public InternalErrorReporterIF,
|
||||||
public HasLocalDataPoolIF {
|
public HasLocalDataPoolIF {
|
||||||
|
@ -27,7 +27,7 @@ public:
|
|||||||
//! Returned if a reply method was called without partner
|
//! Returned if a reply method was called without partner
|
||||||
static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3);
|
static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3);
|
||||||
//! Returned if the target destination is invalid.
|
//! Returned if the target destination is invalid.
|
||||||
static constexpr ReturnValue_t DESTINVATION_INVALID = MAKE_RETURN_CODE(4);
|
static constexpr ReturnValue_t DESTINATION_INVALID = MAKE_RETURN_CODE(4);
|
||||||
|
|
||||||
virtual ~MessageQueueIF() {}
|
virtual ~MessageQueueIF() {}
|
||||||
/**
|
/**
|
||||||
|
@ -86,3 +86,7 @@ size_t MessageQueueMessage::getMaximumMessageSize() const {
|
|||||||
return this->MAX_MESSAGE_SIZE;
|
return this->MAX_MESSAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t MessageQueueMessage::getMaximumDataSize() const {
|
||||||
|
return this->MAX_DATA_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ public:
|
|||||||
virtual void setMessageSize(size_t messageSize) override;
|
virtual void setMessageSize(size_t messageSize) override;
|
||||||
virtual size_t getMinimumMessageSize() const override;
|
virtual size_t getMinimumMessageSize() const override;
|
||||||
virtual size_t getMaximumMessageSize() const override;
|
virtual size_t getMaximumMessageSize() const override;
|
||||||
|
virtual size_t getMaximumDataSize() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This is a debug method that prints the content.
|
* @brief This is a debug method that prints the content.
|
||||||
|
@ -72,6 +72,7 @@ public:
|
|||||||
virtual void setMessageSize(size_t messageSize) = 0;
|
virtual void setMessageSize(size_t messageSize) = 0;
|
||||||
virtual size_t getMinimumMessageSize() const = 0;
|
virtual size_t getMinimumMessageSize() const = 0;
|
||||||
virtual size_t getMaximumMessageSize() const = 0;
|
virtual size_t getMaximumMessageSize() const = 0;
|
||||||
|
virtual size_t getMaximumDataSize() const = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
60
ipc/MutexGuard.h
Normal file
60
ipc/MutexGuard.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef FRAMEWORK_IPC_MUTEXGUARD_H_
|
||||||
|
#define FRAMEWORK_IPC_MUTEXGUARD_H_
|
||||||
|
|
||||||
|
#include "MutexFactory.h"
|
||||||
|
#include "../serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
|
class MutexGuard {
|
||||||
|
public:
|
||||||
|
MutexGuard(MutexIF* mutex, MutexIF::TimeoutType timeoutType =
|
||||||
|
MutexIF::TimeoutType::BLOCKING, uint32_t timeoutMs = 0):
|
||||||
|
internalMutex(mutex) {
|
||||||
|
if(mutex == nullptr) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "MutexGuard: Passed mutex is invalid!" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("MutexGuard: Passed mutex is invalid!\n");
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = mutex->lockMutex(timeoutType,
|
||||||
|
timeoutMs);
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
if(result == MutexIF::MUTEX_TIMEOUT) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "MutexGuard: Lock of mutex failed with timeout of "
|
||||||
|
<< timeoutMs << " milliseconds!" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("MutexGuard: Lock of mutex failed with timeout of %lu milliseconds\n",
|
||||||
|
timeoutMs);
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "MutexGuard: Lock of Mutex failed with code " << result << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("MutexGuard: Lock of Mutex failed with code %d\n", result);
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t getLockResult() const {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
~MutexGuard() {
|
||||||
|
if(internalMutex != nullptr) {
|
||||||
|
internalMutex->unlockMutex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
MutexIF* internalMutex;
|
||||||
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FRAMEWORK_IPC_MUTEXGUARD_H_ */
|
@ -1,57 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_IPC_MUTEXHELPER_H_
|
|
||||||
#define FRAMEWORK_IPC_MUTEXHELPER_H_
|
|
||||||
|
|
||||||
#include "MutexFactory.h"
|
|
||||||
#include "../serviceinterface/ServiceInterface.h"
|
|
||||||
|
|
||||||
class MutexHelper {
|
|
||||||
public:
|
|
||||||
MutexHelper(MutexIF* mutex, MutexIF::TimeoutType timeoutType =
|
|
||||||
MutexIF::TimeoutType::BLOCKING, uint32_t timeoutMs = 0):
|
|
||||||
internalMutex(mutex) {
|
|
||||||
if(mutex == nullptr) {
|
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "MutexHelper: Passed mutex is invalid!" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("MutexHelper: Passed mutex is invalid!\n");
|
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
||||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ReturnValue_t status = mutex->lockMutex(timeoutType,
|
|
||||||
timeoutMs);
|
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
|
||||||
if(status == MutexIF::MUTEX_TIMEOUT) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "MutexHelper: Lock of mutex failed with timeout of "
|
|
||||||
<< timeoutMs << " milliseconds!" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("MutexHelper: Lock of mutex failed with timeout of %lu milliseconds\n",
|
|
||||||
timeoutMs);
|
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
||||||
|
|
||||||
}
|
|
||||||
else if(status != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "MutexHelper: Lock of Mutex failed with code " << status << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("MutexHelper: Lock of Mutex failed with code %d\n", status);
|
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* To avoid unused variable warning */
|
|
||||||
static_cast<void>(status);
|
|
||||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
|
||||||
}
|
|
||||||
|
|
||||||
~MutexHelper() {
|
|
||||||
if(internalMutex != nullptr) {
|
|
||||||
internalMutex->unlockMutex();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
MutexIF* internalMutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_IPC_MUTEXHELPER_H_ */
|
|
@ -10,10 +10,9 @@ elseif(${OS_FSFW} STREQUAL "host")
|
|||||||
if (WIN32)
|
if (WIN32)
|
||||||
add_subdirectory(windows)
|
add_subdirectory(windows)
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
target_sources(${LIB_FSFW_NAME}
|
# We still need to pull in some Linux specific sources
|
||||||
PUBLIC
|
target_sources(${LIB_FSFW_NAME} PUBLIC
|
||||||
linux/TcUnixUdpPollingTask.cpp
|
linux/tcpipHelpers.cpp
|
||||||
linux/TmTcUnixUdpBridge.cpp
|
|
||||||
)
|
)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
@ -32,3 +31,5 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(common)
|
@ -111,7 +111,7 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|||||||
|
|
||||||
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
|
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
|
||||||
timeval* to) {
|
timeval* to) {
|
||||||
struct tm time_tm;
|
struct tm time_tm = {};
|
||||||
|
|
||||||
time_tm.tm_year = from->year - 1900;
|
time_tm.tm_year = from->year - 1900;
|
||||||
time_tm.tm_mon = from->month - 1;
|
time_tm.tm_mon = from->month - 1;
|
||||||
|
@ -135,7 +135,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
|||||||
QueueHandle_t destination = nullptr;
|
QueueHandle_t destination = nullptr;
|
||||||
|
|
||||||
if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) {
|
if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) {
|
||||||
return MessageQueueIF::DESTINVATION_INVALID;
|
return MessageQueueIF::DESTINATION_INVALID;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
destination = reinterpret_cast<QueueHandle_t>(sendTo);
|
destination = reinterpret_cast<QueueHandle_t>(sendTo);
|
||||||
|
16
osal/common/CMakeLists.txt
Normal file
16
osal/common/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
if(DEFINED WIN32 OR DEFINED UNIX)
|
||||||
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
tcpipCommon.cpp
|
||||||
|
TcpIpBase.cpp
|
||||||
|
UdpTcPollingTask.cpp
|
||||||
|
UdpTmTcBridge.cpp
|
||||||
|
TcpTmTcServer.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
wsock32
|
||||||
|
ws2_32
|
||||||
|
)
|
||||||
|
endif()
|
54
osal/common/TcpIpBase.cpp
Normal file
54
osal/common/TcpIpBase.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "TcpIpBase.h"
|
||||||
|
|
||||||
|
#ifdef __unix__
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TcpIpBase::TcpIpBase() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TcpIpBase::initialize() {
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* Initiates Winsock DLL. */
|
||||||
|
WSAData wsaData;
|
||||||
|
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||||
|
int err = WSAStartup(wVersionRequested, &wsaData);
|
||||||
|
if (err != 0) {
|
||||||
|
/* Tell the user that we could not find a usable Winsock DLL. */
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: WSAStartup failed with error: " <<
|
||||||
|
err << std::endl;
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpIpBase::~TcpIpBase() {
|
||||||
|
closeSocket(serverSocket);
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int TcpIpBase::closeSocket(socket_t socket) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
return closesocket(socket);
|
||||||
|
#elif defined(__unix__)
|
||||||
|
return close(socket);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int TcpIpBase::getLastSocketError() {
|
||||||
|
#ifdef _WIN32
|
||||||
|
return WSAGetLastError();
|
||||||
|
#elif defined(__unix__)
|
||||||
|
return errno;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
50
osal/common/TcpIpBase.h
Normal file
50
osal/common/TcpIpBase.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef FSFW_OSAL_COMMON_TCPIPIF_H_
|
||||||
|
#define FSFW_OSAL_COMMON_TCPIPIF_H_
|
||||||
|
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
#elif defined(__unix__)
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class TcpIpBase {
|
||||||
|
protected:
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static constexpr int SHUT_RECV = SD_RECEIVE;
|
||||||
|
static constexpr int SHUT_SEND = SD_SEND;
|
||||||
|
static constexpr int SHUT_BOTH = SD_BOTH;
|
||||||
|
|
||||||
|
using socket_t = SOCKET;
|
||||||
|
#elif defined(__unix__)
|
||||||
|
using socket_t = int;
|
||||||
|
|
||||||
|
static constexpr int INVALID_SOCKET = -1;
|
||||||
|
static constexpr int SOCKET_ERROR = -1;
|
||||||
|
|
||||||
|
static constexpr int SHUT_RECV = SHUT_RD;
|
||||||
|
static constexpr int SHUT_SEND = SHUT_WR;
|
||||||
|
static constexpr int SHUT_BOTH = SHUT_RDWR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TcpIpBase();
|
||||||
|
virtual ~TcpIpBase();
|
||||||
|
|
||||||
|
ReturnValue_t initialize();
|
||||||
|
|
||||||
|
int closeSocket(socket_t socket);
|
||||||
|
|
||||||
|
int getLastSocketError();
|
||||||
|
|
||||||
|
socket_t serverSocket = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_COMMON_TCPIPIF_H_ */
|
132
osal/common/TcpTmTcServer.cpp
Normal file
132
osal/common/TcpTmTcServer.cpp
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#include "TcpTmTcServer.h"
|
||||||
|
#include "tcpipHelpers.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
#elif defined(__unix__)
|
||||||
|
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7301";
|
||||||
|
const std::string TcpTmTcServer::DEFAULT_TCP_CLIENT_PORT = "7302";
|
||||||
|
|
||||||
|
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
||||||
|
std::string customTcpServerPort):
|
||||||
|
SystemObject(objectId), tcpPort(customTcpServerPort) {
|
||||||
|
if(tcpPort == "") {
|
||||||
|
tcpPort = DEFAULT_TCP_SERVER_PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TcpTmTcServer::initialize() {
|
||||||
|
using namespace tcpip;
|
||||||
|
|
||||||
|
ReturnValue_t result = TcpIpBase::initialize();
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retval = 0;
|
||||||
|
struct addrinfo *addrResult = nullptr;
|
||||||
|
struct addrinfo hints = {};
|
||||||
|
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
|
retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult);
|
||||||
|
if (retval != 0) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TcWinTcpServer::TcpTmTcServer: Retrieving address info failed!" <<
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open TCP (stream) socket */
|
||||||
|
listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype,
|
||||||
|
addrResult->ai_protocol);
|
||||||
|
if(listenerTcpSocket == INVALID_SOCKET) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TcWinTcpServer::TcWinTcpServer: Socket creation failed!" << std::endl;
|
||||||
|
#endif
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
handleError(Protocol::TCP, ErrorSources::SOCKET_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||||
|
if(retval == SOCKET_ERROR) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TcWinTcpServer::TcpTmTcServer: Binding socket failed!" <<
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
handleError(Protocol::TCP, ErrorSources::BIND_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TcpTmTcServer::~TcpTmTcServer() {
|
||||||
|
closeSocket(listenerTcpSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
||||||
|
using namespace tcpip;
|
||||||
|
/* If a connection is accepted, the corresponding socket will be assigned to the new socket */
|
||||||
|
socket_t clientSocket = 0;
|
||||||
|
sockaddr clientSockAddr = {};
|
||||||
|
socklen_t connectorSockAddrLen = 0;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
/* Listen for connection requests permanently for lifetime of program */
|
||||||
|
while(true) {
|
||||||
|
retval = listen(listenerTcpSocket, currentBacklog);
|
||||||
|
if(retval == SOCKET_ERROR) {
|
||||||
|
handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
clientSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
|
||||||
|
|
||||||
|
if(clientSocket == INVALID_SOCKET) {
|
||||||
|
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
|
||||||
|
closeSocket(clientSocket);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
retval = recv(clientSocket, reinterpret_cast<char*>(receptionBuffer.data()),
|
||||||
|
receptionBuffer.size(), 0);
|
||||||
|
if(retval > 0) {
|
||||||
|
#if FSFW_TCP_RCV_WIRETAPPING_ENABLED == 1
|
||||||
|
sif::info << "TcpTmTcServer::performOperation: Received " << retval << " bytes."
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
handleError(Protocol::TCP, ErrorSources::RECV_CALL, 500);
|
||||||
|
}
|
||||||
|
else if(retval == 0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Done, shut down connection */
|
||||||
|
retval = shutdown(clientSocket, SHUT_SEND);
|
||||||
|
closeSocket(clientSocket);
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
53
osal/common/TcpTmTcServer.h
Normal file
53
osal/common/TcpTmTcServer.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_
|
||||||
|
#define FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_
|
||||||
|
|
||||||
|
#include "TcpIpBase.h"
|
||||||
|
#include "../../objectmanager/SystemObject.h"
|
||||||
|
#include "../../tasks/ExecutableObjectIF.h"
|
||||||
|
|
||||||
|
#ifdef __unix__
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//! Debugging preprocessor define.
|
||||||
|
#define FSFW_TCP_RCV_WIRETAPPING_ENABLED 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Windows TCP server used to receive telecommands on a Windows Host
|
||||||
|
* @details
|
||||||
|
* Based on: https://docs.microsoft.com/en-us/windows/win32/winsock/complete-server-code
|
||||||
|
*/
|
||||||
|
class TcpTmTcServer:
|
||||||
|
public SystemObject,
|
||||||
|
public TcpIpBase,
|
||||||
|
public ExecutableObjectIF {
|
||||||
|
public:
|
||||||
|
/* The ports chosen here should not be used by any other process. */
|
||||||
|
static const std::string DEFAULT_TCP_SERVER_PORT;
|
||||||
|
static const std::string DEFAULT_TCP_CLIENT_PORT;
|
||||||
|
|
||||||
|
TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
||||||
|
std::string customTcpServerPort = "");
|
||||||
|
virtual~ TcpTmTcServer();
|
||||||
|
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::string tcpPort;
|
||||||
|
socket_t listenerTcpSocket = 0;
|
||||||
|
struct sockaddr tcpAddress;
|
||||||
|
int tcpAddrLen = sizeof(tcpAddress);
|
||||||
|
int currentBacklog = 3;
|
||||||
|
|
||||||
|
std::vector<uint8_t> receptionBuffer;
|
||||||
|
int tcpSockOpt = 0;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ */
|
180
osal/common/UdpTcPollingTask.cpp
Normal file
180
osal/common/UdpTcPollingTask.cpp
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
#include "UdpTcPollingTask.h"
|
||||||
|
#include "tcpipHelpers.h"
|
||||||
|
#include "../../globalfunctions/arrayprinter.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Debugging preprocessor define.
|
||||||
|
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
|
||||||
|
|
||||||
|
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId,
|
||||||
|
object_id_t tmtcUnixUdpBridge, size_t maxRecvSize,
|
||||||
|
double timeoutSeconds): SystemObject(objectId),
|
||||||
|
tmtcBridgeId(tmtcUnixUdpBridge) {
|
||||||
|
if(frameSize > 0) {
|
||||||
|
this->frameSize = frameSize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->frameSize = DEFAULT_MAX_RECV_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up reception buffer with specified frame size.
|
||||||
|
For now, it is assumed that only one frame is held in the buffer! */
|
||||||
|
receptionBuffer.reserve(this->frameSize);
|
||||||
|
receptionBuffer.resize(this->frameSize);
|
||||||
|
|
||||||
|
if(timeoutSeconds == -1) {
|
||||||
|
receptionTimeout = DEFAULT_TIMEOUT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UdpTcPollingTask::~UdpTcPollingTask() {}
|
||||||
|
|
||||||
|
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
|
||||||
|
/* Sender Address is cached here. */
|
||||||
|
struct sockaddr senderAddress;
|
||||||
|
socklen_t senderAddressSize = sizeof(senderAddress);
|
||||||
|
|
||||||
|
/* Poll for new UDP datagrams in permanent loop. */
|
||||||
|
while(true) {
|
||||||
|
int bytesReceived = recvfrom(
|
||||||
|
this->serverSocket,
|
||||||
|
reinterpret_cast<char*>(receptionBuffer.data()),
|
||||||
|
frameSize,
|
||||||
|
receptionFlags,
|
||||||
|
&senderAddress,
|
||||||
|
&senderAddressSize
|
||||||
|
);
|
||||||
|
if(bytesReceived == SOCKET_ERROR) {
|
||||||
|
/* Handle error */
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "UdpTcPollingTask::performOperation: Reception error." << std::endl;
|
||||||
|
#endif
|
||||||
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::RECVFROM_CALL, 1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::debug << "UdpTcPollingTask::performOperation: " << bytesReceived <<
|
||||||
|
" bytes received" << std::endl;
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
#endif /* FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1 */
|
||||||
|
|
||||||
|
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
||||||
|
|
||||||
|
}
|
||||||
|
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
||||||
|
store_address_t storeId;
|
||||||
|
|
||||||
|
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
|
||||||
|
arrayprinter::print(receptionBuffer.data(), bytesRead);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRead);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning<< "UdpTcPollingTask::transferPusToSoftwareBus: Data storage failed." <<
|
||||||
|
std::endl;
|
||||||
|
sif::warning << "Packet size: " << bytesRead << std::endl;
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
TmTcMessage message(storeId);
|
||||||
|
|
||||||
|
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "UdpTcPollingTask::handleSuccessfullTcRead: "
|
||||||
|
" Sending message to queue failed" << std::endl;
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
|
tcStore->deleteData(storeId);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t UdpTcPollingTask::initialize() {
|
||||||
|
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
||||||
|
if (tcStore == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "UdpTcPollingTask::initialize: TC store uninitialized!" << std::endl;
|
||||||
|
#endif
|
||||||
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmtcBridge = objectManager->get<UdpTmTcBridge>(tmtcBridgeId);
|
||||||
|
if(tmtcBridge == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "UdpTcPollingTask::initialize: Invalid TMTC bridge object!" <<
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t result = TcpIpBase::initialize();
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t UdpTcPollingTask::initializeAfterTaskCreation() {
|
||||||
|
/* Initialize the destination after task creation. This ensures
|
||||||
|
that the destination has already been set in the TMTC bridge. */
|
||||||
|
targetTcDestination = tmtcBridge->getRequestQueue();
|
||||||
|
/* The server socket is set up in the bridge intialization. Calling this function here
|
||||||
|
ensures that it is set up regardless of which class was initialized first */
|
||||||
|
this->serverSocket = tmtcBridge->serverSocket;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
DWORD timeoutMs = timeoutSeconds * 1000.0;
|
||||||
|
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
|
||||||
|
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
|
||||||
|
if(result == -1) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting "
|
||||||
|
"receive timeout failed with " << strerror(errno) << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#elif defined(__unix__)
|
||||||
|
timeval tval;
|
||||||
|
tval = timevalOperations::toTimeval(timeoutSeconds);
|
||||||
|
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
|
||||||
|
&tval, sizeof(receptionTimeout));
|
||||||
|
if(result == -1) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
|
||||||
|
"receive timeout failed with " << strerror(errno) << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
||||||
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
||||||
|
|
||||||
#include "TmTcWinUdpBridge.h"
|
#include "UdpTmTcBridge.h"
|
||||||
#include "../../objectmanager/SystemObject.h"
|
#include "../../objectmanager/SystemObject.h"
|
||||||
#include "../../tasks/ExecutableObjectIF.h"
|
#include "../../tasks/ExecutableObjectIF.h"
|
||||||
#include "../../storagemanager/StorageManagerIF.h"
|
#include "../../storagemanager/StorageManagerIF.h"
|
||||||
@ -9,25 +9,22 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This class can be used to implement the polling of a Unix socket,
|
* @brief This class should be used with the UdpTmTcBridge to implement a UDP server
|
||||||
* using UDP for now.
|
* for receiving and sending PUS TMTC.
|
||||||
* @details
|
|
||||||
* The task will be blocked while the specified number of bytes has not been
|
|
||||||
* received, so TC reception is handled inside a separate task.
|
|
||||||
* This class caches the IP address of the sender. It is assumed there
|
|
||||||
* is only one sender for now.
|
|
||||||
*/
|
*/
|
||||||
class TcWinUdpPollingTask: public SystemObject,
|
class UdpTcPollingTask:
|
||||||
|
public TcpIpBase,
|
||||||
|
public SystemObject,
|
||||||
public ExecutableObjectIF {
|
public ExecutableObjectIF {
|
||||||
friend class TmTcWinUdpBridge;
|
friend class TmTcWinUdpBridge;
|
||||||
public:
|
public:
|
||||||
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
|
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
|
||||||
//! 0.5 default milliseconds timeout for now.
|
//! 0.5 default milliseconds timeout for now.
|
||||||
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
|
static constexpr timeval DEFAULT_TIMEOUT = {0, 500};
|
||||||
|
|
||||||
TcWinUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
||||||
size_t frameSize = 0, double timeoutSeconds = -1);
|
size_t maxRecvSize = 0, double timeoutSeconds = -1);
|
||||||
virtual~ TcWinUdpPollingTask();
|
virtual~ UdpTcPollingTask();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turn on optional timeout for UDP polling. In the default mode,
|
* Turn on optional timeout for UDP polling. In the default mode,
|
||||||
@ -46,14 +43,11 @@ protected:
|
|||||||
private:
|
private:
|
||||||
//! TMTC bridge is cached.
|
//! TMTC bridge is cached.
|
||||||
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
||||||
TmTcWinUdpBridge* tmtcBridge = nullptr;
|
UdpTmTcBridge* tmtcBridge = nullptr;
|
||||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||||
//! Reception flags: https://linux.die.net/man/2/recvfrom.
|
|
||||||
int receptionFlags = 0;
|
|
||||||
|
|
||||||
//! Server socket, which is member of TMTC bridge and is assigned in
|
//! See: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom
|
||||||
//! constructor
|
int receptionFlags = 0;
|
||||||
SOCKET serverUdpSocket = 0;
|
|
||||||
|
|
||||||
std::vector<uint8_t> receptionBuffer;
|
std::vector<uint8_t> receptionBuffer;
|
||||||
|
|
||||||
@ -61,7 +55,6 @@ private:
|
|||||||
timeval receptionTimeout;
|
timeval receptionTimeout;
|
||||||
|
|
||||||
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
||||||
void handleReadError();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
174
osal/common/UdpTmTcBridge.cpp
Normal file
174
osal/common/UdpTmTcBridge.cpp
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#include "tcpipHelpers.h"
|
||||||
|
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||||
|
#include <fsfw/ipc/MutexGuard.h>
|
||||||
|
#include <fsfw/osal/common/UdpTmTcBridge.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
#elif defined(__unix__)
|
||||||
|
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Debugging preprocessor define.
|
||||||
|
#define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0
|
||||||
|
|
||||||
|
const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
|
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
|
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort):
|
||||||
|
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||||
|
if(udpServerPort == "") {
|
||||||
|
this->udpServerPort = DEFAULT_UDP_SERVER_PORT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->udpServerPort = udpServerPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
|
communicationLinkUp = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t UdpTmTcBridge::initialize() {
|
||||||
|
ReturnValue_t result = TmTcBridge::initialize();
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TmTcUdpBridge::initialize: TmTcBridge initialization failed!"
|
||||||
|
<< std::endl;
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* Initiates Winsock DLL. */
|
||||||
|
WSAData wsaData;
|
||||||
|
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||||
|
int err = WSAStartup(wVersionRequested, &wsaData);
|
||||||
|
if (err != 0) {
|
||||||
|
/* Tell the user that we could not find a usable */
|
||||||
|
/* Winsock DLL. */
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: " <<
|
||||||
|
err << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: %d\n",
|
||||||
|
err);
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct addrinfo *addrResult = nullptr;
|
||||||
|
struct addrinfo hints = {};
|
||||||
|
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
hints.ai_protocol = IPPROTO_UDP;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
|
/* Set up UDP socket:
|
||||||
|
https://en.wikipedia.org/wiki/Getaddrinfo
|
||||||
|
Passing nullptr as the first parameter and specifying AI_PASSIVE in hints will cause
|
||||||
|
getaddrinfo to assign the address 0.0.0.0 (any address) */
|
||||||
|
int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult);
|
||||||
|
if (retval != 0) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Retrieving address info failed!" <<
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol);
|
||||||
|
if(serverSocket == INVALID_SOCKET) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Could not open UDP socket!" <<
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
|
tcpip::printAddress(addrResult->ai_addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||||
|
if(retval != 0) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TmTcUdpBridge::TmTcUdpBridge: Could not bind "
|
||||||
|
"local port (" << udpServerPort << ") to server socket!" << std::endl;
|
||||||
|
#endif
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
UdpTmTcBridge::~UdpTmTcBridge() {
|
||||||
|
if(mutex != nullptr) {
|
||||||
|
MutexFactory::instance()->deleteMutex(mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
/* The target address can be set by different threads so this lock ensures thread-safety */
|
||||||
|
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
|
||||||
|
|
||||||
|
#if FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
|
tcpip::printAddress(&clientAddress);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int bytesSent = sendto(
|
||||||
|
serverSocket,
|
||||||
|
reinterpret_cast<const char*>(data),
|
||||||
|
dataLen,
|
||||||
|
flags,
|
||||||
|
&clientAddress,
|
||||||
|
clientAddressLen
|
||||||
|
);
|
||||||
|
if(bytesSent == SOCKET_ERROR) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TmTcUdpBridge::sendTm: Send operation failed." << std::endl;
|
||||||
|
#endif
|
||||||
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL);
|
||||||
|
}
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
|
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent << " bytes were"
|
||||||
|
" sent." << std::endl;
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpTmTcBridge::checkAndSetClientAddress(sockaddr& newAddress) {
|
||||||
|
/* The target address can be set by different threads so this lock ensures thread-safety */
|
||||||
|
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
|
||||||
|
|
||||||
|
#if FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
|
tcpip::printAddress(&newAddress);
|
||||||
|
tcpip::printAddress(&clientAddress);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
registerCommConnect();
|
||||||
|
|
||||||
|
/* Set new IP address to reply to */
|
||||||
|
clientAddress = newAddress;
|
||||||
|
clientAddressLen = sizeof(clientAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType,
|
||||||
|
dur_millis_t timeoutMs) {
|
||||||
|
this->timeoutType = timeoutType;
|
||||||
|
this->mutexTimeoutMs = timeoutMs;
|
||||||
|
}
|
60
osal/common/UdpTmTcBridge.h
Normal file
60
osal/common/UdpTmTcBridge.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
|
||||||
|
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
|
||||||
|
|
||||||
|
#include "TcpIpBase.h"
|
||||||
|
#include "../../tmtcservices/TmTcBridge.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
#elif defined(__unix__)
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This class should be used with the UdpTcPollingTask to implement a UDP server
|
||||||
|
* for receiving and sending PUS TMTC.
|
||||||
|
*/
|
||||||
|
class UdpTmTcBridge:
|
||||||
|
public TmTcBridge,
|
||||||
|
public TcpIpBase {
|
||||||
|
friend class UdpTcPollingTask;
|
||||||
|
public:
|
||||||
|
/* The ports chosen here should not be used by any other process. */
|
||||||
|
static const std::string DEFAULT_UDP_SERVER_PORT;
|
||||||
|
|
||||||
|
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
|
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort = "");
|
||||||
|
virtual~ UdpTmTcBridge();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set properties of internal mutex.
|
||||||
|
*/
|
||||||
|
void setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs);
|
||||||
|
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
|
void checkAndSetClientAddress(sockaddr& clientAddress);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string udpServerPort;
|
||||||
|
|
||||||
|
struct sockaddr clientAddress;
|
||||||
|
socklen_t clientAddressLen = 0;
|
||||||
|
|
||||||
|
//! Access to the client address is mutex protected as it is set by another task.
|
||||||
|
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||||
|
dur_millis_t mutexTimeoutMs = 20;
|
||||||
|
MutexIF* mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */
|
||||||
|
|
75
osal/common/tcpipCommon.cpp
Normal file
75
osal/common/tcpipCommon.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include "tcpipCommon.h"
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string &protStr,
|
||||||
|
std::string &srcString) {
|
||||||
|
if(protocol == Protocol::TCP) {
|
||||||
|
protStr = "TCP";
|
||||||
|
}
|
||||||
|
else if(protocol == Protocol::UDP) {
|
||||||
|
protStr = "UDP";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
protStr = "Unknown protocol";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(errorSrc == ErrorSources::SETSOCKOPT_CALL) {
|
||||||
|
srcString = "setsockopt call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::SOCKET_CALL) {
|
||||||
|
srcString = "socket call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::LISTEN_CALL) {
|
||||||
|
srcString = "listen call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::ACCEPT_CALL) {
|
||||||
|
srcString = "accept call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::RECVFROM_CALL) {
|
||||||
|
srcString = "recvfrom call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::GETADDRINFO_CALL) {
|
||||||
|
srcString = "getaddrinfo call";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
srcString = "unknown call";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcpip::printAddress(struct sockaddr* addr) {
|
||||||
|
char ipAddress[INET6_ADDRSTRLEN] = {};
|
||||||
|
const char* stringPtr = NULL;
|
||||||
|
switch(addr->sa_family) {
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in *addrIn = reinterpret_cast<struct sockaddr_in*>(addr);
|
||||||
|
stringPtr = inet_ntop(AF_INET, &(addrIn->sin_addr), ipAddress, INET_ADDRSTRLEN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 *addrIn = reinterpret_cast<struct sockaddr_in6*>(addr);
|
||||||
|
stringPtr = inet_ntop(AF_INET6, &(addrIn->sin6_addr), ipAddress, INET6_ADDRSTRLEN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
if(stringPtr == NULL) {
|
||||||
|
sif::debug << "Could not convert IP address to text representation, error code "
|
||||||
|
<< errno << std::endl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sif::debug << "IP Address Sender: " << ipAddress << std::endl;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if(stringPtr == NULL) {
|
||||||
|
sif::printDebug("Could not convert IP address to text representation, error code %d\n",
|
||||||
|
errno);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sif::printDebug("IP Address Sender: %s\n", ipAddress);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
42
osal/common/tcpipCommon.h
Normal file
42
osal/common/tcpipCommon.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef FSFW_OSAL_COMMON_TCPIPCOMMON_H_
|
||||||
|
#define FSFW_OSAL_COMMON_TCPIPCOMMON_H_
|
||||||
|
|
||||||
|
#include "../../timemanager/clockDefinitions.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace tcpip {
|
||||||
|
|
||||||
|
const char* const DEFAULT_SERVER_PORT = "7301";
|
||||||
|
|
||||||
|
enum class Protocol {
|
||||||
|
UDP,
|
||||||
|
TCP
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ErrorSources {
|
||||||
|
GETADDRINFO_CALL,
|
||||||
|
SOCKET_CALL,
|
||||||
|
SETSOCKOPT_CALL,
|
||||||
|
BIND_CALL,
|
||||||
|
RECV_CALL,
|
||||||
|
RECVFROM_CALL,
|
||||||
|
LISTEN_CALL,
|
||||||
|
ACCEPT_CALL,
|
||||||
|
SENDTO_CALL
|
||||||
|
};
|
||||||
|
|
||||||
|
void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr,
|
||||||
|
std::string& srcString);
|
||||||
|
|
||||||
|
void printAddress(struct sockaddr* addr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_COMMON_TCPIPCOMMON_H_ */
|
15
osal/common/tcpipHelpers.h
Normal file
15
osal/common/tcpipHelpers.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_
|
||||||
|
#define FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_
|
||||||
|
|
||||||
|
#include "../../timemanager/clockDefinitions.h"
|
||||||
|
#include "tcpipCommon.h"
|
||||||
|
|
||||||
|
namespace tcpip {
|
||||||
|
|
||||||
|
void handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration = 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_ */
|
@ -10,6 +10,7 @@ target_sources(${LIB_FSFW_NAME}
|
|||||||
QueueMapManager.cpp
|
QueueMapManager.cpp
|
||||||
SemaphoreFactory.cpp
|
SemaphoreFactory.cpp
|
||||||
TaskFactory.cpp
|
TaskFactory.cpp
|
||||||
|
taskHelpers.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
|
#include "taskHelpers.h"
|
||||||
#include "../../osal/host/FixedTimeslotTask.h"
|
#include "../../osal/host/FixedTimeslotTask.h"
|
||||||
|
|
||||||
#include "../../ipc/MutexFactory.h"
|
#include "../../ipc/MutexFactory.h"
|
||||||
#include "../../osal/host/Mutex.h"
|
#include "../../osal/host/Mutex.h"
|
||||||
#include "../../osal/host/FixedTimeslotTask.h"
|
#include "../../osal/host/FixedTimeslotTask.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
#include "../../tasks/ExecutableObjectIF.h"
|
#include "../../tasks/ExecutableObjectIF.h"
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@ -12,6 +11,7 @@
|
|||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include "../windows/winTaskHelpers.h"
|
||||||
#elif defined(LINUX)
|
#elif defined(LINUX)
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
@ -24,34 +24,12 @@ FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
|
|||||||
// It is propably possible to set task priorities by using the native
|
// It is propably possible to set task priorities by using the native
|
||||||
// task handles for Windows / Linux
|
// task handles for Windows / Linux
|
||||||
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
|
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
|
||||||
#if defined(WIN32)
|
#if defined(_WIN32)
|
||||||
/* List of possible priority classes:
|
tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
|
||||||
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
|
#elif defined(__unix__)
|
||||||
* nf-processthreadsapi-setpriorityclass
|
// TODO: We could reuse existing code here.
|
||||||
* And respective thread priority numbers:
|
|
||||||
* https://docs.microsoft.com/en-us/windows/
|
|
||||||
* win32/procthread/scheduling-priorities */
|
|
||||||
int result = SetPriorityClass(
|
|
||||||
reinterpret_cast<HANDLE>(mainThread.native_handle()),
|
|
||||||
ABOVE_NORMAL_PRIORITY_CLASS);
|
|
||||||
if(result != 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
|
|
||||||
<< GetLastError() << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
result = SetThreadPriority(
|
|
||||||
reinterpret_cast<HANDLE>(mainThread.native_handle()),
|
|
||||||
THREAD_PRIORITY_NORMAL);
|
|
||||||
if(result != 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
|
|
||||||
<< GetLastError() << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#elif defined(LINUX)
|
|
||||||
// TODO: we can just copy and paste the code from the linux OSAL here.
|
|
||||||
#endif
|
#endif
|
||||||
|
tasks::insertTaskName(mainThread.get_id(), taskName);
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedTimeslotTask::~FixedTimeslotTask(void) {
|
FixedTimeslotTask::~FixedTimeslotTask(void) {
|
||||||
@ -60,7 +38,6 @@ FixedTimeslotTask::~FixedTimeslotTask(void) {
|
|||||||
if(mainThread.joinable()) {
|
if(mainThread.joinable()) {
|
||||||
mainThread.join();
|
mainThread.join();
|
||||||
}
|
}
|
||||||
delete this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
||||||
@ -141,8 +118,11 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "Component " << std::hex << componentId <<
|
sif::error << "Component " << std::hex << "0x" << componentId << "not found, "
|
||||||
" not found, not adding it to pst" << std::endl;
|
"not adding it to PST.." << std::dec << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("Component 0x%08x not found, not adding it to PST..\n",
|
||||||
|
static_cast<unsigned int>(componentId));
|
||||||
#endif
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||||
#include "../../ipc/MutexFactory.h"
|
#include "../../ipc/MutexFactory.h"
|
||||||
#include "../../ipc/MutexHelper.h"
|
#include "../../ipc/MutexGuard.h"
|
||||||
|
|
||||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
|
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
|
||||||
messageSize(maxMessageSize), messageDepth(messageDepth) {
|
messageSize(maxMessageSize), messageDepth(messageDepth) {
|
||||||
@ -63,12 +63,9 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
if(messageQueue.empty()) {
|
if(messageQueue.empty()) {
|
||||||
return MessageQueueIF::EMPTY;
|
return MessageQueueIF::EMPTY;
|
||||||
}
|
}
|
||||||
// not sure this will work..
|
MutexGuard mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20);
|
||||||
//*message = std::move(messageQueue.front());
|
std::copy(messageQueue.front().data(), messageQueue.front().data() + messageSize,
|
||||||
MutexHelper mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20);
|
message->getBuffer());
|
||||||
MessageQueueMessage* currentMessage = &messageQueue.front();
|
|
||||||
std::copy(currentMessage->getBuffer(),
|
|
||||||
currentMessage->getBuffer() + messageSize, message->getBuffer());
|
|
||||||
messageQueue.pop();
|
messageQueue.pop();
|
||||||
// The last partner is the first uint32_t field in the message
|
// The last partner is the first uint32_t field in the message
|
||||||
this->lastPartner = message->getSender();
|
this->lastPartner = message->getSender();
|
||||||
@ -82,7 +79,7 @@ MessageQueueId_t MessageQueue::getLastPartner() const {
|
|||||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||||
*count = messageQueue.size();
|
*count = messageQueue.size();
|
||||||
// Clears the queue.
|
// Clears the queue.
|
||||||
messageQueue = std::queue<MessageQueueMessage>();
|
messageQueue = std::queue<std::vector<uint8_t>>();
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +105,9 @@ bool MessageQueue::isDefaultDestinationSet() const {
|
|||||||
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||||
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
||||||
bool ignoreFault) {
|
bool ignoreFault) {
|
||||||
|
if(message == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
message->setSender(sentFrom);
|
message->setSender(sentFrom);
|
||||||
if(message->getMessageSize() > message->getMaximumMessageSize()) {
|
if(message->getMessageSize() > message->getMaximumMessageSize()) {
|
||||||
// Actually, this should never happen or an error will be emitted
|
// Actually, this should never happen or an error will be emitted
|
||||||
@ -130,21 +130,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
|||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
|
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
|
||||||
MutexHelper mutexLock(targetQueue->queueLock,
|
MutexGuard mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20);
|
||||||
MutexIF::TimeoutType::WAITING, 20);
|
targetQueue->messageQueue.push(std::vector<uint8_t>(message->getMaximumMessageSize()));
|
||||||
// not ideal, works for now though.
|
memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(),
|
||||||
MessageQueueMessage* mqmMessage =
|
message->getMaximumMessageSize());
|
||||||
dynamic_cast<MessageQueueMessage*>(message);
|
|
||||||
if(message != nullptr) {
|
|
||||||
targetQueue->messageQueue.push(*mqmMessage);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message"
|
|
||||||
"is not MessageQueueMessage!" << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return MessageQueueIF::FULL;
|
return MessageQueueIF::FULL;
|
||||||
|
@ -212,7 +212,7 @@ protected:
|
|||||||
//static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
//static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::queue<MessageQueueMessage> messageQueue;
|
std::queue<std::vector<uint8_t>> messageQueue;
|
||||||
/**
|
/**
|
||||||
* @brief The class stores the queue id it got assigned.
|
* @brief The class stores the queue id it got assigned.
|
||||||
* If initialization fails, the queue id is set to zero.
|
* If initialization fails, the queue id is set to zero.
|
||||||
|
@ -24,5 +24,7 @@ MutexIF* MutexFactory::createMutex() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MutexFactory::deleteMutex(MutexIF* mutex) {
|
void MutexFactory::deleteMutex(MutexIF* mutex) {
|
||||||
|
if(mutex != nullptr) {
|
||||||
delete mutex;
|
delete mutex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "Mutex.h"
|
#include "Mutex.h"
|
||||||
#include "PeriodicTask.h"
|
#include "PeriodicTask.h"
|
||||||
|
#include "taskHelpers.h"
|
||||||
|
|
||||||
#include "../../ipc/MutexFactory.h"
|
#include "../../ipc/MutexFactory.h"
|
||||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||||
@ -10,7 +11,8 @@
|
|||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
#include <processthreadsapi.h>
|
#include <processthreadsapi.h>
|
||||||
#elif defined(LINUX)
|
#include <fsfw/osal/windows/winTaskHelpers.h>
|
||||||
|
#elif defined(__unix__)
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -19,37 +21,15 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
|
|||||||
void (*setDeadlineMissedFunc)()) :
|
void (*setDeadlineMissedFunc)()) :
|
||||||
started(false), taskName(name), period(setPeriod),
|
started(false), taskName(name), period(setPeriod),
|
||||||
deadlineMissedFunc(setDeadlineMissedFunc) {
|
deadlineMissedFunc(setDeadlineMissedFunc) {
|
||||||
// It is propably possible to set task priorities by using the native
|
// It is probably possible to set task priorities by using the native
|
||||||
// task handles for Windows / Linux
|
// task handles for Windows / Linux
|
||||||
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
|
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
|
||||||
#if defined(WIN32)
|
#if defined(_WIN32)
|
||||||
/* List of possible priority classes:
|
tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
|
||||||
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
|
#elif defined(__unix__)
|
||||||
* nf-processthreadsapi-setpriorityclass
|
// TODO: We could reuse existing code here.
|
||||||
* And respective thread priority numbers:
|
|
||||||
* https://docs.microsoft.com/en-us/windows/
|
|
||||||
* win32/procthread/scheduling-priorities */
|
|
||||||
int result = SetPriorityClass(
|
|
||||||
reinterpret_cast<HANDLE>(mainThread.native_handle()),
|
|
||||||
ABOVE_NORMAL_PRIORITY_CLASS);
|
|
||||||
if(result != 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
|
|
||||||
<< GetLastError() << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
result = SetThreadPriority(
|
|
||||||
reinterpret_cast<HANDLE>(mainThread.native_handle()),
|
|
||||||
THREAD_PRIORITY_NORMAL);
|
|
||||||
if(result != 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
|
|
||||||
<< GetLastError() << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#elif defined(LINUX)
|
|
||||||
// we can just copy and paste the code from linux here.
|
|
||||||
#endif
|
#endif
|
||||||
|
tasks::insertTaskName(mainThread.get_id(), taskName);
|
||||||
}
|
}
|
||||||
|
|
||||||
PeriodicTask::~PeriodicTask(void) {
|
PeriodicTask::~PeriodicTask(void) {
|
||||||
@ -58,7 +38,6 @@ PeriodicTask::~PeriodicTask(void) {
|
|||||||
if(mainThread.joinable()) {
|
if(mainThread.joinable()) {
|
||||||
mainThread.join();
|
mainThread.join();
|
||||||
}
|
}
|
||||||
delete this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicTask::taskEntryPoint(void* argument) {
|
void PeriodicTask::taskEntryPoint(void* argument) {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "../../serviceinterface/ServiceInterface.h"
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
#include "../../ipc/MutexFactory.h"
|
#include "../../ipc/MutexFactory.h"
|
||||||
#include "../../ipc/MutexHelper.h"
|
#include "../../ipc/MutexGuard.h"
|
||||||
|
|
||||||
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
|
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
|
||||||
|
|
||||||
@ -10,6 +10,10 @@ QueueMapManager::QueueMapManager() {
|
|||||||
mapLock = MutexFactory::instance()->createMutex();
|
mapLock = MutexFactory::instance()->createMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueueMapManager::~QueueMapManager() {
|
||||||
|
MutexFactory::instance()->deleteMutex(mapLock);
|
||||||
|
}
|
||||||
|
|
||||||
QueueMapManager* QueueMapManager::instance() {
|
QueueMapManager* QueueMapManager::instance() {
|
||||||
if (mqManagerInstance == nullptr){
|
if (mqManagerInstance == nullptr){
|
||||||
mqManagerInstance = new QueueMapManager();
|
mqManagerInstance = new QueueMapManager();
|
||||||
@ -43,7 +47,7 @@ ReturnValue_t QueueMapManager::addMessageQueue(
|
|||||||
|
|
||||||
MessageQueueIF* QueueMapManager::getMessageQueue(
|
MessageQueueIF* QueueMapManager::getMessageQueue(
|
||||||
MessageQueueId_t messageQueueId) const {
|
MessageQueueId_t messageQueueId) const {
|
||||||
MutexHelper(mapLock, MutexIF::TimeoutType::WAITING, 50);
|
MutexGuard(mapLock, MutexIF::TimeoutType::WAITING, 50);
|
||||||
auto queueIter = queueMap.find(messageQueueId);
|
auto queueIter = queueMap.find(messageQueueId);
|
||||||
if(queueIter != queueMap.end()) {
|
if(queueIter != queueMap.end()) {
|
||||||
return queueIter->second;
|
return queueIter->second;
|
||||||
|
@ -36,6 +36,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
//! External instantiation is forbidden.
|
//! External instantiation is forbidden.
|
||||||
QueueMapManager();
|
QueueMapManager();
|
||||||
|
~QueueMapManager();
|
||||||
|
|
||||||
uint32_t queueCounter = 0;
|
uint32_t queueCounter = 0;
|
||||||
MutexIF* mapLock;
|
MutexIF* mapLock;
|
||||||
QueueMap queueMap;
|
QueueMap queueMap;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#include "../../tasks/SemaphoreFactory.h"
|
#include "../../tasks/SemaphoreFactory.h"
|
||||||
#include "../../osal/linux/BinarySemaphore.h"
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
#include "../../osal/linux/CountingSemaphore.h"
|
|
||||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
|
|
||||||
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
|
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
|
||||||
|
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
|
#include "taskHelpers.h"
|
||||||
|
#include "../../tasks/TaskFactory.h"
|
||||||
#include "../../osal/host/FixedTimeslotTask.h"
|
#include "../../osal/host/FixedTimeslotTask.h"
|
||||||
#include "../../osal/host/PeriodicTask.h"
|
#include "../../osal/host/PeriodicTask.h"
|
||||||
#include "../../tasks/TaskFactory.h"
|
|
||||||
#include "../../returnvalues/HasReturnvaluesIF.h"
|
#include "../../returnvalues/HasReturnvaluesIF.h"
|
||||||
#include "../../tasks/PeriodicTaskIF.h"
|
#include "../../tasks/PeriodicTaskIF.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
||||||
|
|
||||||
// Will propably not be used for hosted implementation
|
// Not used for the host implementation for now because C++ thread abstraction is used
|
||||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
|
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
|
||||||
|
|
||||||
TaskFactory::TaskFactory() {
|
TaskFactory::TaskFactory() {
|
||||||
@ -49,8 +51,12 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TaskFactory::printMissedDeadline() {
|
void TaskFactory::printMissedDeadline() {
|
||||||
/* TODO: Implement */
|
std::string name = tasks::getTaskName(std::this_thread::get_id());
|
||||||
return;
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TaskFactory::printMissedDeadline: " << name << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning("TaskFactory::printMissedDeadline: %s\n", name);
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
27
osal/host/taskHelpers.cpp
Normal file
27
osal/host/taskHelpers.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "taskHelpers.h"
|
||||||
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
std::mutex nameMapLock;
|
||||||
|
std::map<std::thread::id, std::string> taskNameMap;
|
||||||
|
|
||||||
|
ReturnValue_t tasks::insertTaskName(std::thread::id threadId, std::string taskName) {
|
||||||
|
std::lock_guard<std::mutex> lg(nameMapLock);
|
||||||
|
auto returnPair = taskNameMap.emplace(threadId, taskName);
|
||||||
|
if(not returnPair.second) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string tasks::getTaskName(std::thread::id threadId) {
|
||||||
|
std::lock_guard<std::mutex> lg(nameMapLock);
|
||||||
|
auto resultIter = taskNameMap.find(threadId);
|
||||||
|
if(resultIter != taskNameMap.end()) {
|
||||||
|
return resultIter->second;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "Unknown task";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
16
osal/host/taskHelpers.h
Normal file
16
osal/host/taskHelpers.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef FSFW_OSAL_HOST_TASKHELPERS_H_
|
||||||
|
#define FSFW_OSAL_HOST_TASKHELPERS_H_
|
||||||
|
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace tasks {
|
||||||
|
|
||||||
|
ReturnValue_t insertTaskName(std::thread::id threadId, std::string taskName);
|
||||||
|
std::string getTaskName(std::thread::id threadId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_HOST_TASKHELPERS_H_ */
|
@ -13,9 +13,8 @@ target_sources(${LIB_FSFW_NAME}
|
|||||||
QueueFactory.cpp
|
QueueFactory.cpp
|
||||||
SemaphoreFactory.cpp
|
SemaphoreFactory.cpp
|
||||||
TaskFactory.cpp
|
TaskFactory.cpp
|
||||||
TcUnixUdpPollingTask.cpp
|
|
||||||
TmTcUnixUdpBridge.cpp
|
|
||||||
Timer.cpp
|
Timer.cpp
|
||||||
|
tcpipHelpers.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
@ -190,13 +190,15 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}else if(status==0){
|
}
|
||||||
|
else if (status==0) {
|
||||||
//Success but no message received
|
//Success but no message received
|
||||||
return MessageQueueIF::EMPTY;
|
return MessageQueueIF::EMPTY;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
//No message was received. Keep lastPartner anyway, I might send
|
//No message was received. Keep lastPartner anyway, I might send
|
||||||
//something later. But still, delete packet content.
|
//something later. But still, delete packet content.
|
||||||
memset(message->getData(), 0, message->getMaximumMessageSize());
|
memset(message->getData(), 0, message->getMaximumDataSize());
|
||||||
switch(errno){
|
switch(errno){
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
//O_NONBLOCK or MQ_NONBLOCK was set and there are no messages
|
//O_NONBLOCK or MQ_NONBLOCK was set and there are no messages
|
||||||
@ -371,7 +373,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
|||||||
<<"mq_send to: " << sendTo << " sent from "
|
<<"mq_send to: " << sendTo << " sent from "
|
||||||
<< sentFrom << std::endl;
|
<< sentFrom << std::endl;
|
||||||
#endif
|
#endif
|
||||||
return DESTINVATION_INVALID;
|
return DESTINATION_INVALID;
|
||||||
}
|
}
|
||||||
case EINTR:
|
case EINTR:
|
||||||
//The call was interrupted by a signal.
|
//The call was interrupted by a signal.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):
|
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):
|
||||||
thread(0),priority(priority_),stackSize(stackSize_) {
|
thread(0), priority(priority_), stackSize(stackSize_) {
|
||||||
name[0] = '\0';
|
name[0] = '\0';
|
||||||
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
|
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
|
||||||
}
|
}
|
||||||
@ -184,8 +184,11 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
|
|||||||
strerror(status) << std::endl;
|
strerror(status) << std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifndef FSFW_USE_REALTIME_FOR_LINUX
|
||||||
// TODO FIFO -> This needs root privileges for the process
|
#error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1"
|
||||||
|
#endif
|
||||||
|
#if FSFW_USE_REALTIME_FOR_LINUX == 1
|
||||||
|
// FIFO -> This needs root privileges for the process
|
||||||
status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO);
|
status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO);
|
||||||
if(status != 0){
|
if(status != 0){
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -203,7 +206,7 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
|
|||||||
strerror(status) << std::endl;
|
strerror(status) << std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
//Set Signal Mask for suspend until startTask is called
|
//Set Signal Mask for suspend until startTask is called
|
||||||
sigset_t waitSignal;
|
sigset_t waitSignal;
|
||||||
sigemptyset(&waitSignal);
|
sigemptyset(&waitSignal);
|
||||||
@ -220,8 +223,16 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
|
|||||||
status = pthread_create(&thread,&attributes,fnc_,arg_);
|
status = pthread_create(&thread,&attributes,fnc_,arg_);
|
||||||
if(status != 0){
|
if(status != 0){
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "Posix Thread create failed with: " <<
|
sif::error << "PosixThread::createTask: Failed with: " <<
|
||||||
strerror(status) << std::endl;
|
strerror(status) << std::endl;
|
||||||
|
sif::error << "For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " <<
|
||||||
|
"\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set "
|
||||||
|
"/etc/security/limit.conf" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("PosixThread::createTask: Create failed with: %s\n", strerror(status));
|
||||||
|
sif::printError("For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call "
|
||||||
|
"\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set "
|
||||||
|
"/etc/security/limit.conf\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "PeriodicPosixTask.h"
|
#include "PeriodicPosixTask.h"
|
||||||
|
|
||||||
#include "../../tasks/TaskFactory.h"
|
#include "../../tasks/TaskFactory.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
#include "../../returnvalues/HasReturnvaluesIF.h"
|
#include "../../returnvalues/HasReturnvaluesIF.h"
|
||||||
|
|
||||||
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
||||||
|
@ -1,158 +0,0 @@
|
|||||||
#include "TcUnixUdpPollingTask.h"
|
|
||||||
#include "../../globalfunctions/arrayprinter.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
|
|
||||||
object_id_t tmtcUnixUdpBridge, size_t frameSize,
|
|
||||||
double timeoutSeconds): SystemObject(objectId),
|
|
||||||
tmtcBridgeId(tmtcUnixUdpBridge) {
|
|
||||||
|
|
||||||
if(frameSize > 0) {
|
|
||||||
this->frameSize = frameSize;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up reception buffer with specified frame size.
|
|
||||||
// For now, it is assumed that only one frame is held in the buffer!
|
|
||||||
receptionBuffer.reserve(this->frameSize);
|
|
||||||
receptionBuffer.resize(this->frameSize);
|
|
||||||
|
|
||||||
if(timeoutSeconds == -1) {
|
|
||||||
receptionTimeout = DEFAULT_TIMEOUT;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {}
|
|
||||||
|
|
||||||
ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
|
|
||||||
// Poll for new UDP datagrams in permanent loop.
|
|
||||||
while(1) {
|
|
||||||
//! Sender Address is cached here.
|
|
||||||
struct sockaddr_in senderAddress;
|
|
||||||
socklen_t senderSockLen = sizeof(senderAddress);
|
|
||||||
ssize_t bytesReceived = recvfrom(serverUdpSocket,
|
|
||||||
receptionBuffer.data(), frameSize, receptionFlags,
|
|
||||||
reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen);
|
|
||||||
if(bytesReceived < 0) {
|
|
||||||
// handle error
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcSocketPollingTask::performOperation: Reception"
|
|
||||||
"error." << std::endl;
|
|
||||||
#endif
|
|
||||||
handleReadError();
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived
|
|
||||||
// << " bytes received" << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
|
||||||
|
|
||||||
}
|
|
||||||
tmtcBridge->registerCommConnect();
|
|
||||||
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
|
||||||
}
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
|
||||||
store_address_t storeId;
|
|
||||||
ReturnValue_t result = tcStore->addData(&storeId,
|
|
||||||
receptionBuffer.data(), bytesRead);
|
|
||||||
// arrayprinter::print(receptionBuffer.data(), bytesRead);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
|
|
||||||
"storage failed" << std::endl;
|
|
||||||
sif::error << "Packet size: " << bytesRead << std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
TmTcMessage message(storeId);
|
|
||||||
|
|
||||||
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Serial Polling: Sending message to queue failed"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
tcStore->deleteData(storeId);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t TcUnixUdpPollingTask::initialize() {
|
|
||||||
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
|
||||||
if (tcStore == nullptr) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmtcBridge = objectManager->get<TmTcUnixUdpBridge>(tmtcBridgeId);
|
|
||||||
if(tmtcBridge == nullptr) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
|
|
||||||
" TMTC bridge object!" << std::endl;
|
|
||||||
#endif
|
|
||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
serverUdpSocket = tmtcBridge->serverSocket;
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() {
|
|
||||||
// Initialize the destination after task creation. This ensures
|
|
||||||
// that the destination will be set in the TMTC bridge.
|
|
||||||
targetTcDestination = tmtcBridge->getRequestQueue();
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) {
|
|
||||||
timeval tval;
|
|
||||||
tval = timevalOperations::toTimeval(timeoutSeconds);
|
|
||||||
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
|
|
||||||
&tval, sizeof(receptionTimeout));
|
|
||||||
if(result == -1) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
|
|
||||||
"receive timeout failed with " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: sleep after error detection to prevent spam
|
|
||||||
void TcUnixUdpPollingTask::handleReadError() {
|
|
||||||
switch(errno) {
|
|
||||||
case(EAGAIN): {
|
|
||||||
// todo: When working in timeout mode, this will occur more often
|
|
||||||
// and is not an error.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcUnixUdpPollingTask::handleReadError: "
|
|
||||||
<< strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
|
|
||||||
#define FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
|
|
||||||
|
|
||||||
#include "../../objectmanager/SystemObject.h"
|
|
||||||
#include "../../osal/linux/TmTcUnixUdpBridge.h"
|
|
||||||
#include "../../tasks/ExecutableObjectIF.h"
|
|
||||||
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This class can be used to implement the polling of a Unix socket,
|
|
||||||
* using UDP for now.
|
|
||||||
* @details
|
|
||||||
* The task will be blocked while the specified number of bytes has not been
|
|
||||||
* received, so TC reception is handled inside a separate task.
|
|
||||||
* This class caches the IP address of the sender. It is assumed there
|
|
||||||
* is only one sender for now.
|
|
||||||
*/
|
|
||||||
class TcUnixUdpPollingTask: public SystemObject,
|
|
||||||
public ExecutableObjectIF {
|
|
||||||
friend class TmTcUnixUdpBridge;
|
|
||||||
public:
|
|
||||||
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
|
|
||||||
//! 0.5 default milliseconds timeout for now.
|
|
||||||
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
|
|
||||||
|
|
||||||
TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
|
||||||
size_t frameSize = 0, double timeoutSeconds = -1);
|
|
||||||
virtual~ TcUnixUdpPollingTask();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn on optional timeout for UDP polling. In the default mode,
|
|
||||||
* the receive function will block until a packet is received.
|
|
||||||
* @param timeoutSeconds
|
|
||||||
*/
|
|
||||||
void setTimeout(double timeoutSeconds);
|
|
||||||
|
|
||||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
|
||||||
virtual ReturnValue_t initialize() override;
|
|
||||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
StorageManagerIF* tcStore = nullptr;
|
|
||||||
|
|
||||||
private:
|
|
||||||
//! TMTC bridge is cached.
|
|
||||||
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
|
||||||
TmTcUnixUdpBridge* tmtcBridge = nullptr;
|
|
||||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
|
||||||
//! Reception flags: https://linux.die.net/man/2/recvfrom.
|
|
||||||
int receptionFlags = 0;
|
|
||||||
|
|
||||||
//! Server socket, which is member of TMTC bridge and is assigned in
|
|
||||||
//! constructor
|
|
||||||
int serverUdpSocket = 0;
|
|
||||||
|
|
||||||
std::vector<uint8_t> receptionBuffer;
|
|
||||||
|
|
||||||
size_t frameSize = 0;
|
|
||||||
timeval receptionTimeout;
|
|
||||||
|
|
||||||
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
|
||||||
void handleReadError();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
|
@ -1,206 +0,0 @@
|
|||||||
#include "TmTcUnixUdpBridge.h"
|
|
||||||
#include "../../serviceinterface/ServiceInterface.h"
|
|
||||||
#include "../../ipc/MutexHelper.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
|
|
||||||
TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId,
|
|
||||||
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
|
|
||||||
uint16_t serverPort, uint16_t clientPort):
|
|
||||||
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
|
||||||
|
|
||||||
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
|
|
||||||
if(serverPort != 0xFFFF) {
|
|
||||||
setServerPort = serverPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
|
|
||||||
if(clientPort != 0xFFFF) {
|
|
||||||
setClientPort = clientPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
|
|
||||||
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
||||||
if(serverSocket < 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open"
|
|
||||||
" UDP socket!" << std::endl;
|
|
||||||
#endif
|
|
||||||
handleSocketError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
serverAddress.sin_family = AF_INET;
|
|
||||||
|
|
||||||
// Accept packets from any interface.
|
|
||||||
//serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0");
|
|
||||||
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
serverAddress.sin_port = htons(setServerPort);
|
|
||||||
serverAddressLen = sizeof(serverAddress);
|
|
||||||
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions,
|
|
||||||
sizeof(serverSocketOptions));
|
|
||||||
|
|
||||||
clientAddress.sin_family = AF_INET;
|
|
||||||
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
clientAddress.sin_port = htons(setClientPort);
|
|
||||||
clientAddressLen = sizeof(clientAddress);
|
|
||||||
|
|
||||||
int result = bind(serverSocket,
|
|
||||||
reinterpret_cast<struct sockaddr*>(&serverAddress),
|
|
||||||
serverAddressLen);
|
|
||||||
if(result == -1) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind "
|
|
||||||
"local port " << setServerPort << " to server socket!"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
handleBindError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
|
||||||
int flags = 0;
|
|
||||||
|
|
||||||
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
|
|
||||||
|
|
||||||
if(ipAddrAnySet){
|
|
||||||
clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
|
|
||||||
//clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1");
|
|
||||||
clientAddressLen = sizeof(serverAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
// char ipAddress [15];
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
|
||||||
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags,
|
|
||||||
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
|
|
||||||
if(bytesSent < 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
handleSendError();
|
|
||||||
}
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
|
|
||||||
// " sent." << std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
|
|
||||||
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
|
|
||||||
|
|
||||||
// char ipAddress [15];
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
|
||||||
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
|
||||||
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
|
|
||||||
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set new IP address if it has changed.
|
|
||||||
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
|
|
||||||
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
|
|
||||||
clientAddressLen = sizeof(clientAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TmTcUnixUdpBridge::handleSocketError() {
|
|
||||||
// See: https://man7.org/linux/man-pages/man2/socket.2.html
|
|
||||||
switch(errno) {
|
|
||||||
case(EACCES):
|
|
||||||
case(EINVAL):
|
|
||||||
case(EMFILE):
|
|
||||||
case(ENFILE):
|
|
||||||
case(EAFNOSUPPORT):
|
|
||||||
case(ENOBUFS):
|
|
||||||
case(ENOMEM):
|
|
||||||
case(EPROTONOSUPPORT):
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed"
|
|
||||||
<< " with " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleSocketError: Unknown error"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcUnixUdpBridge::handleBindError() {
|
|
||||||
// See: https://man7.org/linux/man-pages/man2/bind.2.html
|
|
||||||
switch(errno) {
|
|
||||||
case(EACCES): {
|
|
||||||
/*
|
|
||||||
Ephermeral ports can be shown with following command:
|
|
||||||
sysctl -A | grep ip_local_port_range
|
|
||||||
*/
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleBindError: Port access issue."
|
|
||||||
"Ports 1-1024 are reserved on UNIX systems and require root "
|
|
||||||
"rights while ephermeral ports should not be used as well."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case(EADDRINUSE):
|
|
||||||
case(EBADF):
|
|
||||||
case(EINVAL):
|
|
||||||
case(ENOTSOCK):
|
|
||||||
case(EADDRNOTAVAIL):
|
|
||||||
case(EFAULT):
|
|
||||||
case(ELOOP):
|
|
||||||
case(ENAMETOOLONG):
|
|
||||||
case(ENOENT):
|
|
||||||
case(ENOMEM):
|
|
||||||
case(ENOTDIR):
|
|
||||||
case(EROFS): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed"
|
|
||||||
<< " with " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleBindError: Unknown error"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcUnixUdpBridge::handleSendError() {
|
|
||||||
switch(errno) {
|
|
||||||
default: {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleSendError: "
|
|
||||||
<< strerror(errno) << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("TmTcUnixBridge::handleSendError: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcUnixUdpBridge::setClientAddressToAny(bool ipAddrAnySet){
|
|
||||||
this->ipAddrAnySet = ipAddrAnySet;
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
|
|
||||||
#define FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
|
|
||||||
|
|
||||||
#include "../../tmtcservices/AcceptsTelecommandsIF.h"
|
|
||||||
#include "../../tmtcservices/TmTcBridge.h"
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netinet/udp.h>
|
|
||||||
|
|
||||||
class TmTcUnixUdpBridge: public TmTcBridge {
|
|
||||||
friend class TcUnixUdpPollingTask;
|
|
||||||
public:
|
|
||||||
// The ports chosen here should not be used by any other process.
|
|
||||||
// List of used ports on Linux: /etc/services
|
|
||||||
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
|
|
||||||
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
|
|
||||||
|
|
||||||
TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
|
||||||
object_id_t tmStoreId, object_id_t tcStoreId,
|
|
||||||
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
|
|
||||||
virtual~ TmTcUnixUdpBridge();
|
|
||||||
|
|
||||||
void checkAndSetClientAddress(sockaddr_in& clientAddress);
|
|
||||||
|
|
||||||
void setClientAddressToAny(bool ipAddrAnySet);
|
|
||||||
protected:
|
|
||||||
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int serverSocket = 0;
|
|
||||||
|
|
||||||
const int serverSocketOptions = 0;
|
|
||||||
|
|
||||||
struct sockaddr_in clientAddress;
|
|
||||||
socklen_t clientAddressLen = 0;
|
|
||||||
|
|
||||||
struct sockaddr_in serverAddress;
|
|
||||||
socklen_t serverAddressLen = 0;
|
|
||||||
|
|
||||||
bool ipAddrAnySet = false;
|
|
||||||
|
|
||||||
//! Access to the client address is mutex protected as it is set
|
|
||||||
//! by another task.
|
|
||||||
MutexIF* mutex;
|
|
||||||
|
|
||||||
void handleSocketError();
|
|
||||||
void handleBindError();
|
|
||||||
void handleSendError();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */
|
|
109
osal/linux/tcpipHelpers.cpp
Normal file
109
osal/linux/tcpipHelpers.cpp
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#include "../common/tcpipHelpers.h"
|
||||||
|
|
||||||
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
|
#include "../../tasks/TaskFactory.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration) {
|
||||||
|
int errCode = errno;
|
||||||
|
std::string protocolString;
|
||||||
|
std::string errorSrcString;
|
||||||
|
determineErrorStrings(protocol, errorSrc, protocolString, errorSrcString);
|
||||||
|
std::string infoString;
|
||||||
|
switch(errCode) {
|
||||||
|
case(EACCES): {
|
||||||
|
infoString = "EACCES";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EINVAL): {
|
||||||
|
infoString = "EINVAL";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EAGAIN): {
|
||||||
|
infoString = "EAGAIN";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EMFILE): {
|
||||||
|
infoString = "EMFILE";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENFILE): {
|
||||||
|
infoString = "ENFILE";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EAFNOSUPPORT): {
|
||||||
|
infoString = "EAFNOSUPPORT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOBUFS): {
|
||||||
|
infoString = "ENOBUFS";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOMEM): {
|
||||||
|
infoString = "ENOMEM";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EPROTONOSUPPORT): {
|
||||||
|
infoString = "EPROTONOSUPPORT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EADDRINUSE): {
|
||||||
|
infoString = "EADDRINUSE";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EBADF): {
|
||||||
|
infoString = "EBADF";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOTSOCK): {
|
||||||
|
infoString = "ENOTSOCK";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EADDRNOTAVAIL): {
|
||||||
|
infoString = "EADDRNOTAVAIL";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EFAULT): {
|
||||||
|
infoString = "EFAULT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ELOOP): {
|
||||||
|
infoString = "ELOOP";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENAMETOOLONG): {
|
||||||
|
infoString = "ENAMETOOLONG";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOENT): {
|
||||||
|
infoString = "ENOENT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOTDIR): {
|
||||||
|
infoString = "ENOTDIR";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EROFS): {
|
||||||
|
infoString = "EROFS";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
infoString = "Error code: " + std::to_string(errCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
|
||||||
|
" | " << infoString << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString.c_str(),
|
||||||
|
errorSrcString.c_str(), infoString.c_str());
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
|
||||||
|
if(sleepDuration > 0) {
|
||||||
|
TaskFactory::instance()->delayTask(sleepDuration);
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#include "RtemsBasic.h"
|
#include "RtemsBasic.h"
|
||||||
|
|
||||||
#include "../../timemanager/Clock.h"
|
#include "../../timemanager/Clock.h"
|
||||||
#include "../../ipc/MutexHelper.h"
|
#include "../../ipc/MutexGuard.h"
|
||||||
|
|
||||||
#include <rtems/score/todimpl.h>
|
#include <rtems/score/todimpl.h>
|
||||||
#include <rtems/rtems/clockimpl.h>
|
#include <rtems/rtems/clockimpl.h>
|
||||||
@ -183,7 +183,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
|
|||||||
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
|
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
MutexHelper helper(timeMutex);
|
MutexGuard helper(timeMutex);
|
||||||
|
|
||||||
|
|
||||||
leapSeconds = leapSeconds_;
|
leapSeconds = leapSeconds_;
|
||||||
@ -196,7 +196,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
|||||||
if(timeMutex==nullptr){
|
if(timeMutex==nullptr){
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
MutexHelper helper(timeMutex);
|
MutexGuard helper(timeMutex);
|
||||||
|
|
||||||
*leapSeconds_ = leapSeconds;
|
*leapSeconds_ = leapSeconds;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
} else {
|
} else {
|
||||||
//No message was received. Keep lastPartner anyway, I might send something later.
|
//No message was received. Keep lastPartner anyway, I might send something later.
|
||||||
//But still, delete packet content.
|
//But still, delete packet content.
|
||||||
memset(message->getData(), 0, message->getMaximumMessageSize());
|
memset(message->getData(), 0, message->getMaximumDataSize());
|
||||||
}
|
}
|
||||||
return convertReturnCode(status);
|
return convertReturnCode(status);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,4 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
PRIVATE
|
tcpipHelpers.cpp
|
||||||
TcWinUdpPollingTask.cpp
|
winTaskHelpers.cpp
|
||||||
TmTcWinUdpBridge.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME}
|
|
||||||
PRIVATE
|
|
||||||
wsock32
|
|
||||||
ws2_32
|
|
||||||
)
|
)
|
@ -1,177 +0,0 @@
|
|||||||
#include "TcWinUdpPollingTask.h"
|
|
||||||
#include "../../globalfunctions/arrayprinter.h"
|
|
||||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
TcWinUdpPollingTask::TcWinUdpPollingTask(object_id_t objectId,
|
|
||||||
object_id_t tmtcUnixUdpBridge, size_t frameSize,
|
|
||||||
double timeoutSeconds): SystemObject(objectId),
|
|
||||||
tmtcBridgeId(tmtcUnixUdpBridge) {
|
|
||||||
if(frameSize > 0) {
|
|
||||||
this->frameSize = frameSize;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up reception buffer with specified frame size.
|
|
||||||
// For now, it is assumed that only one frame is held in the buffer!
|
|
||||||
receptionBuffer.reserve(this->frameSize);
|
|
||||||
receptionBuffer.resize(this->frameSize);
|
|
||||||
|
|
||||||
if(timeoutSeconds == -1) {
|
|
||||||
receptionTimeout = DEFAULT_TIMEOUT;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TcWinUdpPollingTask::~TcWinUdpPollingTask() {}
|
|
||||||
|
|
||||||
ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) {
|
|
||||||
// Poll for new UDP datagrams in permanent loop.
|
|
||||||
while(true) {
|
|
||||||
//! Sender Address is cached here.
|
|
||||||
struct sockaddr_in senderAddress;
|
|
||||||
int senderAddressSize = sizeof(senderAddress);
|
|
||||||
ssize_t bytesReceived = recvfrom(serverUdpSocket,
|
|
||||||
reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
|
|
||||||
receptionFlags, reinterpret_cast<sockaddr*>(&senderAddress),
|
|
||||||
&senderAddressSize);
|
|
||||||
if(bytesReceived == SOCKET_ERROR) {
|
|
||||||
// handle error
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcWinUdpPollingTask::performOperation: Reception"
|
|
||||||
" error." << std::endl;
|
|
||||||
#endif
|
|
||||||
handleReadError();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
//sif::debug << "TcWinUdpPollingTask::performOperation: " << bytesReceived
|
|
||||||
// << " bytes received" << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
|
||||||
|
|
||||||
}
|
|
||||||
tmtcBridge->registerCommConnect();
|
|
||||||
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
|
||||||
}
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
|
||||||
store_address_t storeId;
|
|
||||||
ReturnValue_t result = tcStore->addData(&storeId,
|
|
||||||
receptionBuffer.data(), bytesRead);
|
|
||||||
// arrayprinter::print(receptionBuffer.data(), bytesRead);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
|
|
||||||
"storage failed" << std::endl;
|
|
||||||
sif::error << "Packet size: " << bytesRead << std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
TmTcMessage message(storeId);
|
|
||||||
|
|
||||||
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Serial Polling: Sending message to queue failed"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
tcStore->deleteData(storeId);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t TcWinUdpPollingTask::initialize() {
|
|
||||||
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
|
||||||
if (tcStore == nullptr) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmtcBridge = objectManager->get<TmTcWinUdpBridge>(tmtcBridgeId);
|
|
||||||
if(tmtcBridge == nullptr) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
|
|
||||||
" TMTC bridge object!" << std::endl;
|
|
||||||
#endif
|
|
||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
serverUdpSocket = tmtcBridge->serverSocket;
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
//sif::info << "TcWinUdpPollingTask::initialize: Server UDP socket "
|
|
||||||
// << serverUdpSocket << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t TcWinUdpPollingTask::initializeAfterTaskCreation() {
|
|
||||||
// Initialize the destination after task creation. This ensures
|
|
||||||
// that the destination has already been set in the TMTC bridge.
|
|
||||||
targetTcDestination = tmtcBridge->getRequestQueue();
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcWinUdpPollingTask::setTimeout(double timeoutSeconds) {
|
|
||||||
DWORD timeoutMs = timeoutSeconds * 1000.0;
|
|
||||||
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
|
|
||||||
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
|
|
||||||
if(result == -1) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting "
|
|
||||||
"receive timeout failed with " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcWinUdpPollingTask::handleReadError() {
|
|
||||||
int error = WSAGetLastError();
|
|
||||||
switch(error) {
|
|
||||||
case(WSANOTINITIALISED): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TcWinUdpPollingTask::handleReadError: WSANOTINITIALISED: "
|
|
||||||
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case(WSAEFAULT): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TcWinUdpPollingTask::handleReadError: WSADEFAULT: "
|
|
||||||
<< "Bad address " << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case(WSAEINVAL): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TcWinUdpPollingTask::handleReadError: WSAEINVAL: "
|
|
||||||
<< "Invalid input parameters. " << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TcWinUdpPollingTask::handleReadError: Error code: "
|
|
||||||
<< error << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// to prevent spam.
|
|
||||||
Sleep(1000);
|
|
||||||
}
|
|
@ -1,212 +0,0 @@
|
|||||||
#include <fsfw/ipc/MutexHelper.h>
|
|
||||||
#include "TmTcWinUdpBridge.h"
|
|
||||||
|
|
||||||
TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId,
|
|
||||||
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
|
|
||||||
uint16_t serverPort, uint16_t clientPort):
|
|
||||||
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
|
||||||
communicationLinkUp = false;
|
|
||||||
|
|
||||||
// Initiates Winsock DLL.
|
|
||||||
WSAData wsaData;
|
|
||||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
|
||||||
int err = WSAStartup(wVersionRequested, &wsaData);
|
|
||||||
if (err != 0) {
|
|
||||||
/* Tell the user that we could not find a usable */
|
|
||||||
/* Winsock DLL. */
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge:"
|
|
||||||
"WSAStartup failed with error: " << err << std::endl;
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
|
|
||||||
if(serverPort != 0xFFFF) {
|
|
||||||
setServerPort = serverPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
|
|
||||||
if(clientPort != 0xFFFF) {
|
|
||||||
setClientPort = clientPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
|
|
||||||
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
||||||
if(serverSocket == INVALID_SOCKET) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not open"
|
|
||||||
" UDP socket!" << std::endl;
|
|
||||||
#endif
|
|
||||||
handleSocketError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
serverAddress.sin_family = AF_INET;
|
|
||||||
|
|
||||||
// Accept packets from any interface. (potentially insecure).
|
|
||||||
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
serverAddress.sin_port = htons(setServerPort);
|
|
||||||
serverAddressLen = sizeof(serverAddress);
|
|
||||||
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,
|
|
||||||
reinterpret_cast<const char*>(&serverSocketOptions),
|
|
||||||
sizeof(serverSocketOptions));
|
|
||||||
|
|
||||||
clientAddress.sin_family = AF_INET;
|
|
||||||
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
clientAddress.sin_port = htons(setClientPort);
|
|
||||||
clientAddressLen = sizeof(clientAddress);
|
|
||||||
|
|
||||||
int result = bind(serverSocket,
|
|
||||||
reinterpret_cast<struct sockaddr*>(&serverAddress),
|
|
||||||
serverAddressLen);
|
|
||||||
if(result != 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind "
|
|
||||||
"local port " << setServerPort << " to server socket!"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
handleBindError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TmTcWinUdpBridge::~TmTcWinUdpBridge() {
|
|
||||||
WSACleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
|
||||||
int flags = 0;
|
|
||||||
|
|
||||||
//clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
|
|
||||||
//clientAddressLen = sizeof(serverAddress);
|
|
||||||
|
|
||||||
// char ipAddress [15];
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
|
||||||
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ssize_t bytesSent = sendto(serverSocket,
|
|
||||||
reinterpret_cast<const char*>(data), dataLen, flags,
|
|
||||||
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
|
|
||||||
if(bytesSent == SOCKET_ERROR) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcWinUdpBridge::sendTm: Send operation failed."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
handleSendError();
|
|
||||||
}
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
|
|
||||||
// " sent." << std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
|
|
||||||
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
|
|
||||||
|
|
||||||
// char ipAddress [15];
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
|
||||||
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
|
||||||
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
|
|
||||||
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
|
||||||
#endif
|
|
||||||
registerCommConnect();
|
|
||||||
|
|
||||||
// Set new IP address if it has changed.
|
|
||||||
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
|
|
||||||
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
|
|
||||||
clientAddressLen = sizeof(clientAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcWinUdpBridge::handleSocketError() {
|
|
||||||
int errCode = WSAGetLastError();
|
|
||||||
switch(errCode) {
|
|
||||||
case(WSANOTINITIALISED): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleSocketError: WSANOTINITIALISED: "
|
|
||||||
<< "WSAStartup(...) call necessary" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
/*
|
|
||||||
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
|
||||||
windows-sockets-error-codes-2
|
|
||||||
*/
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleSocketError: Error code: "
|
|
||||||
<< errCode << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcWinUdpBridge::handleBindError() {
|
|
||||||
int errCode = WSAGetLastError();
|
|
||||||
switch(errCode) {
|
|
||||||
case(WSANOTINITIALISED): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleBindError: WSANOTINITIALISED: "
|
|
||||||
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case(WSAEADDRINUSE): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "TmTcWinUdpBridge::handleBindError: WSAEADDRINUSE: "
|
|
||||||
<< "Port is already in use!" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
/*
|
|
||||||
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
|
||||||
windows-sockets-error-codes-2
|
|
||||||
*/
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleBindError: Error code: "
|
|
||||||
<< errCode << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcWinUdpBridge::handleSendError() {
|
|
||||||
int errCode = WSAGetLastError();
|
|
||||||
switch(errCode) {
|
|
||||||
case(WSANOTINITIALISED): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleSendError: WSANOTINITIALISED: "
|
|
||||||
<< "WSAStartup(...) call necessary" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case(WSAEADDRNOTAVAIL): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleSendError: WSAEADDRNOTAVAIL: "
|
|
||||||
<< "Check target address. " << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
/*
|
|
||||||
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
|
||||||
windows-sockets-error-codes-2
|
|
||||||
*/
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleSendError: Error code: "
|
|
||||||
<< errCode << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
|||||||
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
|
|
||||||
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
|
|
||||||
|
|
||||||
#include "../../tmtcservices/TmTcBridge.h"
|
|
||||||
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
class TmTcWinUdpBridge: public TmTcBridge {
|
|
||||||
friend class TcWinUdpPollingTask;
|
|
||||||
public:
|
|
||||||
// The ports chosen here should not be used by any other process.
|
|
||||||
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
|
|
||||||
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
|
|
||||||
|
|
||||||
TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
|
||||||
object_id_t tmStoreId, object_id_t tcStoreId,
|
|
||||||
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
|
|
||||||
virtual~ TmTcWinUdpBridge();
|
|
||||||
|
|
||||||
void checkAndSetClientAddress(sockaddr_in clientAddress);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SOCKET serverSocket = 0;
|
|
||||||
|
|
||||||
const int serverSocketOptions = 0;
|
|
||||||
|
|
||||||
struct sockaddr_in clientAddress;
|
|
||||||
int clientAddressLen = 0;
|
|
||||||
|
|
||||||
struct sockaddr_in serverAddress;
|
|
||||||
int serverAddressLen = 0;
|
|
||||||
|
|
||||||
//! Access to the client address is mutex protected as it is set
|
|
||||||
//! by another task.
|
|
||||||
MutexIF* mutex;
|
|
||||||
|
|
||||||
void handleSocketError();
|
|
||||||
void handleBindError();
|
|
||||||
void handleSendError();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */
|
|
||||||
|
|
63
osal/windows/tcpipHelpers.cpp
Normal file
63
osal/windows/tcpipHelpers.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include "../common/tcpipHelpers.h"
|
||||||
|
#include <FSFWConfig.h>
|
||||||
|
|
||||||
|
#include "../../tasks/TaskFactory.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
int errCode = WSAGetLastError();
|
||||||
|
std::string protocolString;
|
||||||
|
std::string errorSrcString;
|
||||||
|
determineErrorStrings(protocol, errorSrc, protocolString, errorSrcString);
|
||||||
|
|
||||||
|
std::string infoString;
|
||||||
|
switch(errCode) {
|
||||||
|
case(WSANOTINITIALISED): {
|
||||||
|
infoString = "WSANOTINITIALISED";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEADDRINUSE): {
|
||||||
|
infoString = "WSAEADDRINUSE";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEFAULT): {
|
||||||
|
infoString = "WSAEFAULT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEADDRNOTAVAIL): {
|
||||||
|
infoString = "WSAEADDRNOTAVAIL";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEINVAL): {
|
||||||
|
infoString = "WSAEINVAL";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
/*
|
||||||
|
https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
|
||||||
|
*/
|
||||||
|
infoString = "Error code: " + std::to_string(errCode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
|
||||||
|
" | " << infoString << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString,
|
||||||
|
errorSrcString, infoString);
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
|
|
||||||
|
if(sleepDuration > 0) {
|
||||||
|
TaskFactory::instance()->delayTask(sleepDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
107
osal/windows/winTaskHelpers.cpp
Normal file
107
osal/windows/winTaskHelpers.cpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#include <fsfw/osal/windows/winTaskHelpers.h>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
TaskPriority tasks::makeWinPriority(PriorityClass prioClass, PriorityNumber prioNumber) {
|
||||||
|
return (static_cast<uint16_t>(prioClass) << 16) | static_cast<uint16_t> (prioNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tasks::getWinPriorityParameters(TaskPriority priority,
|
||||||
|
DWORD& priorityClass, int& priorityNumber) {
|
||||||
|
PriorityClass classInternal = static_cast<PriorityClass>(priority >> 16 & 0xff);
|
||||||
|
PriorityNumber numberInternal = static_cast<PriorityNumber>(priority & 0xff);
|
||||||
|
switch(classInternal) {
|
||||||
|
case(CLASS_IDLE): {
|
||||||
|
priorityClass = IDLE_PRIORITY_CLASS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(CLASS_BELOW_NORMAL): {
|
||||||
|
priorityClass = BELOW_NORMAL_PRIORITY_CLASS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(CLASS_NORMAL): {
|
||||||
|
priorityClass = NORMAL_PRIORITY_CLASS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(CLASS_ABOVE_NORMAL): {
|
||||||
|
priorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(CLASS_HIGH): {
|
||||||
|
priorityClass = HIGH_PRIORITY_CLASS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(CLASS_REALTIME): {
|
||||||
|
priorityClass = REALTIME_PRIORITY_CLASS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
priorityClass = NORMAL_PRIORITY_CLASS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(numberInternal) {
|
||||||
|
case(IDLE): {
|
||||||
|
priorityNumber = THREAD_PRIORITY_IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(LOWEST): {
|
||||||
|
priorityNumber = THREAD_PRIORITY_LOWEST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(BELOW_NORMAL): {
|
||||||
|
priorityNumber = THREAD_PRIORITY_BELOW_NORMAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(NORMAL): {
|
||||||
|
priorityNumber = THREAD_PRIORITY_NORMAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ABOVE_NORMAL): {
|
||||||
|
priorityNumber = THREAD_PRIORITY_ABOVE_NORMAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(HIGHEST): {
|
||||||
|
priorityNumber = THREAD_PRIORITY_HIGHEST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(CRITICAL): {
|
||||||
|
priorityNumber = THREAD_PRIORITY_TIME_CRITICAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
priorityNumber = THREAD_PRIORITY_NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t tasks::setTaskPriority(HANDLE nativeHandle, TaskPriority priority) {
|
||||||
|
/* List of possible priority classes:
|
||||||
|
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setpriorityclass
|
||||||
|
And respective thread priority numbers:
|
||||||
|
https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
|
||||||
|
*/
|
||||||
|
DWORD dwPriorityClass = 0;
|
||||||
|
int nPriorityNumber = 0;
|
||||||
|
tasks::getWinPriorityParameters(priority, dwPriorityClass, nPriorityNumber);
|
||||||
|
int result = SetPriorityClass(
|
||||||
|
reinterpret_cast<HANDLE>(nativeHandle),
|
||||||
|
dwPriorityClass);
|
||||||
|
if(result != 0) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
|
||||||
|
<< GetLastError() << std::endl;
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
result = SetThreadPriority(
|
||||||
|
reinterpret_cast<HANDLE>(nativeHandle),
|
||||||
|
nPriorityNumber);
|
||||||
|
if(result != 0) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
|
||||||
|
<< GetLastError() << std::endl;
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
37
osal/windows/winTaskHelpers.h
Normal file
37
osal/windows/winTaskHelpers.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "../../tasks/TaskFactory.h"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
namespace tasks {
|
||||||
|
|
||||||
|
enum PriorityClass: uint16_t {
|
||||||
|
CLASS_IDLE,
|
||||||
|
CLASS_BELOW_NORMAL,
|
||||||
|
CLASS_NORMAL,
|
||||||
|
CLASS_ABOVE_NORMAL,
|
||||||
|
CLASS_HIGH,
|
||||||
|
CLASS_REALTIME
|
||||||
|
};
|
||||||
|
enum PriorityNumber: uint16_t {
|
||||||
|
IDLE,
|
||||||
|
LOWEST,
|
||||||
|
BELOW_NORMAL,
|
||||||
|
NORMAL,
|
||||||
|
ABOVE_NORMAL,
|
||||||
|
HIGHEST,
|
||||||
|
CRITICAL
|
||||||
|
};
|
||||||
|
TaskPriority makeWinPriority(PriorityClass prioClass = PriorityClass::CLASS_NORMAL,
|
||||||
|
PriorityNumber prioNumber = PriorityNumber::NORMAL);
|
||||||
|
void getWinPriorityParameters(TaskPriority priority, DWORD& priorityClass,
|
||||||
|
int& priorityNumber);
|
||||||
|
|
||||||
|
ReturnValue_t setTaskPriority(HANDLE nativeHandle, TaskPriority priority);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
#include "PowerComponent.h"
|
#include "PowerComponent.h"
|
||||||
#include "../serialize/SerializeAdapter.h"
|
#include "../serialize/SerializeAdapter.h"
|
||||||
|
|
||||||
|
|
||||||
PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF),
|
PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF),
|
||||||
doIHaveTwoSwitches(false) {
|
doIHaveTwoSwitches(false) {
|
||||||
}
|
}
|
||||||
@ -8,23 +9,23 @@ PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF),
|
|||||||
PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min,
|
PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min,
|
||||||
float max, uint8_t switchId1, bool twoSwitches, uint8_t switchId2) :
|
float max, uint8_t switchId1, bool twoSwitches, uint8_t switchId2) :
|
||||||
deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2),
|
deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2),
|
||||||
doIHaveTwoSwitches(twoSwitches), min(min), max(max),
|
doIHaveTwoSwitches(twoSwitches), minPower(min), maxPower(max),
|
||||||
moduleId(moduleId) {
|
moduleId(moduleId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size,
|
ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size,
|
||||||
size_t maxSize, Endianness streamEndianness) const {
|
size_t maxSize, Endianness streamEndianness) const {
|
||||||
ReturnValue_t result = SerializeAdapter::serialize(&min, buffer,
|
ReturnValue_t result = SerializeAdapter::serialize(&minPower, buffer,
|
||||||
size, maxSize, streamEndianness);
|
size, maxSize, streamEndianness);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return SerializeAdapter::serialize(&max, buffer, size, maxSize,
|
return SerializeAdapter::serialize(&maxPower, buffer, size, maxSize,
|
||||||
streamEndianness);
|
streamEndianness);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PowerComponent::getSerializedSize() const {
|
size_t PowerComponent::getSerializedSize() const {
|
||||||
return sizeof(min) + sizeof(max);
|
return sizeof(minPower) + sizeof(maxPower);
|
||||||
}
|
}
|
||||||
|
|
||||||
object_id_t PowerComponent::getDeviceObjectId() {
|
object_id_t PowerComponent::getDeviceObjectId() {
|
||||||
@ -44,21 +45,21 @@ bool PowerComponent::hasTwoSwitches() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float PowerComponent::getMin() {
|
float PowerComponent::getMin() {
|
||||||
return min;
|
return minPower;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PowerComponent::getMax() {
|
float PowerComponent::getMax() {
|
||||||
return max;
|
return maxPower;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
Endianness streamEndianness) {
|
Endianness streamEndianness) {
|
||||||
ReturnValue_t result = SerializeAdapter::deSerialize(&min, buffer,
|
ReturnValue_t result = SerializeAdapter::deSerialize(&minPower, buffer,
|
||||||
size, streamEndianness);
|
size, streamEndianness);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return SerializeAdapter::deSerialize(&max, buffer, size, streamEndianness);
|
return SerializeAdapter::deSerialize(&maxPower, buffer, size, streamEndianness);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PowerComponent::getParameter(uint8_t domainId, uint8_t uniqueId,
|
ReturnValue_t PowerComponent::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||||
@ -69,10 +70,10 @@ ReturnValue_t PowerComponent::getParameter(uint8_t domainId, uint8_t uniqueId,
|
|||||||
}
|
}
|
||||||
switch (uniqueId) {
|
switch (uniqueId) {
|
||||||
case 0:
|
case 0:
|
||||||
parameterWrapper->set<>(min);
|
parameterWrapper->set<>(minPower);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
parameterWrapper->set<>(max);
|
parameterWrapper->set<>(maxPower);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return INVALID_IDENTIFIER_ID;
|
return INVALID_IDENTIFIER_ID;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
class PowerComponent: public PowerComponentIF {
|
class PowerComponent: public PowerComponentIF {
|
||||||
public:
|
public:
|
||||||
PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max,
|
PowerComponent(object_id_t setId, uint8_t moduleId, float minPower, float maxPower,
|
||||||
uint8_t switchId1, bool twoSwitches = false,
|
uint8_t switchId1, bool twoSwitches = false,
|
||||||
uint8_t switchId2 = 0xFF);
|
uint8_t switchId2 = 0xFF);
|
||||||
|
|
||||||
@ -41,8 +41,8 @@ private:
|
|||||||
|
|
||||||
const bool doIHaveTwoSwitches;
|
const bool doIHaveTwoSwitches;
|
||||||
|
|
||||||
float min = 0.0;
|
float minPower = 0.0;
|
||||||
float max = 0.0;
|
float maxPower = 0.0;
|
||||||
|
|
||||||
uint8_t moduleId = 0;
|
uint8_t moduleId = 0;
|
||||||
|
|
||||||
|
@ -61,8 +61,7 @@ ReturnValue_t CService200ModeCommanding::prepareCommand(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModeMessage::setModeMessage(dynamic_cast<CommandMessage*>(message),
|
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(),
|
||||||
ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(),
|
|
||||||
modeCommandPacket.getSubmode());
|
modeCommandPacket.getSubmode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,9 @@ Service1TelecommandVerification::Service1TelecommandVerification(
|
|||||||
tmQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
tmQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
Service1TelecommandVerification::~Service1TelecommandVerification() {}
|
Service1TelecommandVerification::~Service1TelecommandVerification() {
|
||||||
|
QueueFactory::instance()->deleteMessageQueue(tmQueue);
|
||||||
|
}
|
||||||
|
|
||||||
MessageQueueId_t Service1TelecommandVerification::getVerificationQueue(){
|
MessageQueueId_t Service1TelecommandVerification::getVerificationQueue(){
|
||||||
return tmQueue->getId();
|
return tmQueue->getId();
|
||||||
|
@ -75,9 +75,8 @@ ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue
|
|||||||
#else
|
#else
|
||||||
sif::printError("Service20ParameterManagement::checkInterfaceAndAcquire"
|
sif::printError("Service20ParameterManagement::checkInterfaceAndAcquire"
|
||||||
"MessageQueue: Can't access object\n");
|
"MessageQueue: Can't access object\n");
|
||||||
sif::printError("Object ID: 0x%08x\n", objectId);
|
sif::printError("Object ID: 0x%08x\n", *objectId);
|
||||||
sif::printError("Make sure it implements "
|
sif::printError("Make sure it implements ReceivesParameterMessagesIF!\n");
|
||||||
"ReceivesParameterMessagesIF!\n");
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return CommandingServiceBase::INVALID_OBJECT;
|
return CommandingServiceBase::INVALID_OBJECT;
|
||||||
|
@ -159,7 +159,7 @@ ReturnValue_t Service3Housekeeping::prepareCollectionIntervalModificationCommand
|
|||||||
CommandMessage *command, object_id_t objectId, bool isDiagnostics,
|
CommandMessage *command, object_id_t objectId, bool isDiagnostics,
|
||||||
const uint8_t *tcData, size_t tcDataLen) {
|
const uint8_t *tcData, size_t tcDataLen) {
|
||||||
if(tcDataLen < sizeof(sid_t) + sizeof(float)) {
|
if(tcDataLen < sizeof(sid_t) + sizeof(float)) {
|
||||||
// SID plus the size of the new collection intervL.
|
/* SID plus the size of the new collection interval. */
|
||||||
return CommandingServiceBase::INVALID_TC;
|
return CommandingServiceBase::INVALID_TC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,9 @@ Service5EventReporting::Service5EventReporting(object_id_t objectId,
|
|||||||
eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
Service5EventReporting::~Service5EventReporting(){}
|
Service5EventReporting::~Service5EventReporting() {
|
||||||
|
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t Service5EventReporting::performService() {
|
ReturnValue_t Service5EventReporting::performService() {
|
||||||
EventMessage message;
|
EventMessage message;
|
||||||
|
@ -53,12 +53,14 @@ ReturnValue_t Service8FunctionManagement::checkInterfaceAndAcquireMessageQueue(
|
|||||||
ReturnValue_t Service8FunctionManagement::prepareCommand(
|
ReturnValue_t Service8FunctionManagement::prepareCommand(
|
||||||
CommandMessage* message, uint8_t subservice, const uint8_t* tcData,
|
CommandMessage* message, uint8_t subservice, const uint8_t* tcData,
|
||||||
size_t tcDataLen, uint32_t* state, object_id_t objectId) {
|
size_t tcDataLen, uint32_t* state, object_id_t objectId) {
|
||||||
return prepareDirectCommand(dynamic_cast<CommandMessage*>(message),
|
return prepareDirectCommand(message, tcData, tcDataLen);
|
||||||
tcData, tcDataLen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Service8FunctionManagement::prepareDirectCommand(
|
ReturnValue_t Service8FunctionManagement::prepareDirectCommand(
|
||||||
CommandMessage *message, const uint8_t *tcData, size_t tcDataLen) {
|
CommandMessage *message, const uint8_t *tcData, size_t tcDataLen) {
|
||||||
|
if(message == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
if(tcDataLen < sizeof(object_id_t) + sizeof(ActionId_t)) {
|
if(tcDataLen < sizeof(object_id_t) + sizeof(ActionId_t)) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::debug << "Service8FunctionManagement::prepareDirectCommand:"
|
sif::debug << "Service8FunctionManagement::prepareDirectCommand:"
|
||||||
|
@ -43,8 +43,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
DirectCommand(const DirectCommand &command);
|
DirectCommand(const DirectCommand &command);
|
||||||
object_id_t objectId;
|
object_id_t objectId = 0;
|
||||||
ActionId_t actionId;
|
ActionId_t actionId = 0;
|
||||||
uint32_t parametersSize; //!< [EXPORT] : [IGNORE]
|
uint32_t parametersSize; //!< [EXPORT] : [IGNORE]
|
||||||
const uint8_t * parameterBuffer; //!< [EXPORT] : [MAXSIZE] 65535 Bytes
|
const uint8_t * parameterBuffer; //!< [EXPORT] : [MAXSIZE] 65535 Bytes
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
SerializeElement() :
|
SerializeElement() :
|
||||||
LinkedElement<SerializeIF>(this) {
|
LinkedElement<SerializeIF>(this), entry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||||
|
@ -15,7 +15,7 @@ PoolManager::~PoolManager(void) {
|
|||||||
|
|
||||||
ReturnValue_t PoolManager::reserveSpace(const size_t size,
|
ReturnValue_t PoolManager::reserveSpace(const size_t size,
|
||||||
store_address_t* address, bool ignoreFault) {
|
store_address_t* address, bool ignoreFault) {
|
||||||
MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING,
|
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING,
|
||||||
mutexTimeoutMs);
|
mutexTimeoutMs);
|
||||||
ReturnValue_t status = LocalPool::reserveSpace(size,
|
ReturnValue_t status = LocalPool::reserveSpace(size,
|
||||||
address,ignoreFault);
|
address,ignoreFault);
|
||||||
@ -32,7 +32,7 @@ ReturnValue_t PoolManager::deleteData(
|
|||||||
". id is "<< storeId.packetIndex << std::endl;
|
". id is "<< storeId.packetIndex << std::endl;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING,
|
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING,
|
||||||
mutexTimeoutMs);
|
mutexTimeoutMs);
|
||||||
return LocalPool::deleteData(storeId);
|
return LocalPool::deleteData(storeId);
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ ReturnValue_t PoolManager::deleteData(
|
|||||||
|
|
||||||
ReturnValue_t PoolManager::deleteData(uint8_t* buffer,
|
ReturnValue_t PoolManager::deleteData(uint8_t* buffer,
|
||||||
size_t size, store_address_t* storeId) {
|
size_t size, store_address_t* storeId) {
|
||||||
MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20);
|
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20);
|
||||||
ReturnValue_t status = LocalPool::deleteData(buffer,
|
ReturnValue_t status = LocalPool::deleteData(buffer,
|
||||||
size, storeId);
|
size, storeId);
|
||||||
return status;
|
return status;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "LocalPool.h"
|
#include "LocalPool.h"
|
||||||
#include "StorageAccessor.h"
|
#include "StorageAccessor.h"
|
||||||
#include "../ipc/MutexHelper.h"
|
#include "../ipc/MutexGuard.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user