Update from upstream #85

Merged
meierj merged 91 commits from mueller/update-from-upstream into develop 2022-05-16 22:08:28 +02:00
60 changed files with 657 additions and 248 deletions
Showing only changes of commit eb494707af - Show all commits

View File

@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Changes ## Changes
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
compiler supports it
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed - HAL Linux SPI: Set the Clock Default State when setting new SPI speed
and mode and mode
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
@ -28,6 +31,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
creation call. It allows passing context information and an arbitrary user argument into creation call. It allows passing context information and an arbitrary user argument into
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
- Clock:
- `timeval` to `TimeOfDay_t`
- Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/)
- Moved the statics used by Clock in ClockCommon.cpp to this file
- Better check for leap seconds
- Added Unittests for Clock (only getter)
## Removed ## Removed
@ -46,8 +55,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Fixed ## Fixed
- Move some CMake directives further up top so they are not ignored
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/621
- Small bugfix in STM32 HAL for SPI - Small bugfix in STM32 HAL for SPI
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599
- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO
configuration fails, the function will exit prematurely with a dedicated error code
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/602
# [v4.0.0] # [v4.0.0]

View File

@ -1,5 +1,15 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
set(LIB_FSFW_NAME fsfw)
project(${LIB_FSFW_NAME})
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
elseif(${CMAKE_CXX_STANDARD} LESS 17)
message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++17 support")
endif()
set(FSFW_VERSION 4) set(FSFW_VERSION 4)
set(FSFW_SUBVERSION 0) set(FSFW_SUBVERSION 0)
set(FSFW_REVISION 0) set(FSFW_REVISION 0)
@ -10,14 +20,15 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING
"ETL library major version requirement" "ETL library major version requirement"
) )
set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.2 CACHE STRING set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING
"ETL library exact version requirement" "ETL library exact version requirement"
) )
set(FSFW_ETL_LINK_TARGET etl::etl)
set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING
"Catch2 library major version requirement" "Catch2 library major version requirement"
) )
set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview4 CACHE STRING set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5 CACHE STRING
"Catch2 library exact version requirement" "Catch2 library exact version requirement"
) )
@ -54,11 +65,10 @@ option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF)
# Contrib sources # Contrib sources
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF) option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
set(LIB_FSFW_NAME fsfw)
set(FSFW_TEST_TGT fsfw-tests) set(FSFW_TEST_TGT fsfw-tests)
set(FSFW_DUMMY_TGT fsfw-dummy) set(FSFW_DUMMY_TGT fsfw-dummy)
project(${LIB_FSFW_NAME})
add_library(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME})
if(FSFW_BUILD_UNITTESTS) if(FSFW_BUILD_UNITTESTS)
@ -76,9 +86,7 @@ if(FSFW_BUILD_UNITTESTS)
GIT_TAG ${FSFW_CATCH2_LIB_VERSION} GIT_TAG ${FSFW_CATCH2_LIB_VERSION}
) )
FetchContent_MakeAvailable(Catch2) list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
#fixes regression -preview4, to be confirmed in later releases
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
endif() endif()
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg) set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
@ -123,7 +131,22 @@ if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
GIT_TAG ${FSFW_ETL_LIB_VERSION} GIT_TAG ${FSFW_ETL_LIB_VERSION}
) )
FetchContent_MakeAvailable(etl) list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME})
endif()
# The documentation for FetchContent recommends declaring all the dependencies
# before making them available. We make all declared dependency available here
# after their declaration
if(FSFW_FETCH_CONTENT_TARGETS)
FetchContent_MakeAvailable(${FSFW_FETCH_CONTENT_TARGETS})
if(TARGET ${FSFW_ETL_LIB_NAME})
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
endif()
if(TARGET Catch2)
# Fixes regression -preview4, to be confirmed in later releases
# Related GitHub issue: https://github.com/catchorg/Catch2/issues/2417
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
endif()
endif() endif()
set(FSFW_CORE_INC_PATH "inc") set(FSFW_CORE_INC_PATH "inc")
@ -138,12 +161,6 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
) )
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
elseif(${CMAKE_CXX_STANDARD} LESS 11)
message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++11 support")
endif()
# Backwards comptability # Backwards comptability
if(OS_FSFW AND NOT FSFW_OSAL) if(OS_FSFW AND NOT FSFW_OSAL)
@ -387,7 +404,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE
) )
target_link_libraries(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LINK_TARGET}
${FSFW_ADDITIONAL_LINK_LIBS} ${FSFW_ADDITIONAL_LINK_LIBS}
) )

View File

@ -6,3 +6,9 @@ RUN apt-get --yes upgrade
#tzdata is a dependency, won't install otherwise #tzdata is a dependency, won't install otherwise
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
RUN git clone https://github.com/catchorg/Catch2.git && \
cd Catch2 && \
git checkout v3.0.0-preview5 && \
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
cmake --build build/ --target install

View File

@ -3,7 +3,7 @@ pipeline {
BUILDDIR = 'build-tests' BUILDDIR = 'build-tests'
} }
agent { agent {
docker { image 'fsfw-ci:d1'} docker { image 'fsfw-ci:d2'}
} }
stages { stages {
stage('Clean') { stage('Clean') {

View File

@ -1,9 +1,9 @@
#include "MgmLIS3MDLHandler.h" #include "MgmLIS3MDLHandler.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include <cmath> #include <cmath>
#include "fsfw/datapool/PoolReadGuard.h"
MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication, MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication,
CookieIF *comCookie, uint32_t transitionDelay) CookieIF *comCookie, uint32_t transitionDelay)
: DeviceHandlerBase(objectId, deviceCommunication, comCookie), : DeviceHandlerBase(objectId, deviceCommunication, comCookie),

View File

@ -12,9 +12,14 @@ if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
if(FSFW_HAL_LINUX_ADD_LIBGPIOD) if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
add_subdirectory(gpio) add_subdirectory(gpio)
endif() endif()
add_subdirectory(spi)
add_subdirectory(i2c)
add_subdirectory(uart) add_subdirectory(uart)
# Adding those does not really make sense on Apple systems which
# are generally host systems. It won't even compile as the headers
# are missing
if(NOT APPLE)
add_subdirectory(i2c)
add_subdirectory(spi)
endif()
endif() endif()
add_subdirectory(uio) add_subdirectory(uio)

View File

@ -44,6 +44,7 @@ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
} }
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
ReturnValue_t result = RETURN_OK;
for (auto& gpioConfig : mapToAdd) { for (auto& gpioConfig : mapToAdd) {
auto& gpioType = gpioConfig.second->gpioType; auto& gpioType = gpioConfig.second->gpioType;
switch (gpioType) { switch (gpioType) {
@ -55,7 +56,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
if (regularGpio == nullptr) { if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
configureGpioByChip(gpioConfig.first, *regularGpio); result = configureGpioByChip(gpioConfig.first, *regularGpio);
break; break;
} }
case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): { case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): {
@ -63,7 +64,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
if (regularGpio == nullptr) { if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
configureGpioByLabel(gpioConfig.first, *regularGpio); result = configureGpioByLabel(gpioConfig.first, *regularGpio);
break; break;
} }
case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): { case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
@ -71,7 +72,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
if (regularGpio == nullptr) { if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
configureGpioByLineName(gpioConfig.first, *regularGpio); result = configureGpioByLineName(gpioConfig.first, *regularGpio);
break; break;
} }
case (gpio::GpioTypes::CALLBACK): { case (gpio::GpioTypes::CALLBACK): {
@ -83,8 +84,11 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
gpioCallback->initValue, gpioCallback->callbackArgs); gpioCallback->initValue, gpioCallback->callbackArgs);
} }
} }
if (result != RETURN_OK) {
return GPIO_INIT_FAILED;
} }
return RETURN_OK; }
return result;
} }
ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId, ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,

View File

@ -29,6 +29,8 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4); HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED = static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5); HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
static constexpr ReturnValue_t GPIO_INIT_FAILED =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 6);
LinuxLibgpioIF(object_id_t objectId); LinuxLibgpioIF(object_id_t objectId);
virtual ~LinuxLibgpioIF(); virtual ~LinuxLibgpioIF();

View File

@ -1,4 +1,4 @@
#include "fsfw_hal/linux/spi/SpiCookie.h" #include "SpiCookie.h"
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed) const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)

View File

@ -265,6 +265,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
cfsetispeed(options, B230400); cfsetispeed(options, B230400);
cfsetospeed(options, B230400); cfsetospeed(options, B230400);
break; break;
#ifndef __APPLE__
case UartBaudRate::RATE_460800: case UartBaudRate::RATE_460800:
cfsetispeed(options, B460800); cfsetispeed(options, B460800);
cfsetospeed(options, B460800); cfsetospeed(options, B460800);
@ -313,6 +314,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
cfsetispeed(options, B4000000); cfsetispeed(options, B4000000);
cfsetospeed(options, B4000000); cfsetospeed(options, B4000000);
break; break;
#endif // ! __APPLE__
default: default:
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl; sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;

View File

@ -24,9 +24,7 @@ void UartCookie::setParityEven() { parity = Parity::EVEN; }
Parity UartCookie::getParity() const { return parity; } Parity UartCookie::getParity() const { return parity; }
void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { bitsPerWord = bitsPerWord_; }
bitsPerWord = bitsPerWord_;
}
BitsPerWord UartCookie::getBitsPerWord() const { return bitsPerWord; } BitsPerWord UartCookie::getBitsPerWord() const { return bitsPerWord; }

View File

@ -44,7 +44,7 @@ class HeaderSerializer : public SerializeIF, public PduHeaderIF {
cfdp::WidthInBytes getLenEntityIds() const override; cfdp::WidthInBytes getLenEntityIds() const override;
cfdp::WidthInBytes getLenSeqNum() const override; cfdp::WidthInBytes getLenSeqNum() const override;
cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override; cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override;
bool hasSegmentMetadataFlag() const; bool hasSegmentMetadataFlag() const override;
void setSegmentationControl(cfdp::SegmentationControl); void setSegmentationControl(cfdp::SegmentationControl);
void getSourceId(cfdp::EntityId& sourceId) const override; void getSourceId(cfdp::EntityId& sourceId) const override;

View File

@ -9,7 +9,7 @@
*/ */
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> {
#if !defined(_MSC_VER) #if !defined(_MSC_VER) && !defined(__clang__)
static_assert(MAX_SIZE <= (std::pow(2, sizeof(count_t) * 8) - 1), static_assert(MAX_SIZE <= (std::pow(2, sizeof(count_t) * 8) - 1),
"count_t is not large enough to hold MAX_SIZE"); "count_t is not large enough to hold MAX_SIZE");
#endif #endif

View File

@ -10,16 +10,23 @@ class HybridIterator : public LinkedElement<T>::Iterator, public ArrayList<T, co
HybridIterator() {} HybridIterator() {}
HybridIterator(typename LinkedElement<T>::Iterator *iter) HybridIterator(typename LinkedElement<T>::Iterator *iter)
: LinkedElement<T>::Iterator(*iter), value(iter->value), linked(true) {} : LinkedElement<T>::Iterator(*iter), linked(true) {
if (iter != nullptr) {
value = iter->value;
}
}
HybridIterator(LinkedElement<T> *start) HybridIterator(LinkedElement<T> *start) : LinkedElement<T>::Iterator(start), linked(true) {
: LinkedElement<T>::Iterator(start), value(start->value), linked(true) {} if (start != nullptr) {
value = start->value;
}
}
HybridIterator(typename ArrayList<T, count_t>::Iterator start, HybridIterator(typename ArrayList<T, count_t>::Iterator start,
typename ArrayList<T, count_t>::Iterator end) typename ArrayList<T, count_t>::Iterator end)
: ArrayList<T, count_t>::Iterator(start), value(start.value), linked(false), end(end.value) { : ArrayList<T, count_t>::Iterator(start), value(start.value), linked(false), end(end.value) {
if (value == this->end) { if (value == this->end) {
value = NULL; value = nullptr;
} }
} }

View File

@ -55,7 +55,7 @@ class ControllerBase : public HasModesIF,
virtual void performControlOperation() = 0; virtual void performControlOperation() = 0;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0; uint32_t *msToReachTheMode) override = 0;
const object_id_t parentId; const object_id_t parentId;
@ -80,9 +80,9 @@ class ControllerBase : public HasModesIF,
/** Mode helpers */ /** Mode helpers */
virtual void modeChanged(Mode_t mode, Submode_t submode); virtual void modeChanged(Mode_t mode, Submode_t submode);
virtual void startTransition(Mode_t mode, Submode_t submode); virtual void startTransition(Mode_t mode, Submode_t submode) override;
virtual void getMode(Mode_t *mode, Submode_t *submode); virtual void getMode(Mode_t *mode, Submode_t *submode) override;
virtual void setToExternalControl(); virtual void setToExternalControl() override;
virtual void announceMode(bool recursive); virtual void announceMode(bool recursive);
/** HK helpers */ /** HK helpers */
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);

View File

@ -109,7 +109,7 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF, public HasRetu
*/ */
virtual ReturnValue_t unlockDataPool() override; virtual ReturnValue_t unlockDataPool() override;
virtual uint16_t getFillCount() const; virtual uint16_t getFillCount() const override;
/* SerializeIF implementations */ /* SerializeIF implementations */
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize, virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,

View File

@ -787,7 +787,7 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
// Serialize set packet into store. // Serialize set packet into store.
size_t size = 0; size_t size = 0;
result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG); result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG);
if(result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeId); ipcStore->deleteData(storeId);
return result; return result;
} }
@ -806,7 +806,7 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
} }
result = hkQueue->reply(&reply); result = hkQueue->reply(&reply);
if(result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeId); ipcStore->deleteData(storeId);
} }
return result; return result;

View File

@ -94,13 +94,14 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
const 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 *validityPtr = nullptr; uint8_t *validityPtr = nullptr;
#ifdef _MSC_VER #if defined(_MSC_VER) || defined(__clang__)
/* Use a std::vector here because MSVC will (rightly) not create a fixed size array // Use a std::vector here because MSVC will (rightly) not create a fixed size array
with a non constant size specifier */ // with a non constant size specifier. The Apple compiler (LLVM) will not accept
std::vector<uint8_t> validityMask(validityMaskSize); // the initialization of a variable sized array
std::vector<uint8_t> validityMask(validityMaskSize, 0);
validityPtr = validityMask.data(); validityPtr = validityMask.data();
#else #else
uint8_t validityMask[validityMaskSize] = {0}; uint8_t validityMask[validityMaskSize] = {};
validityPtr = validityMask; validityPtr = validityMask;
#endif #endif
uint8_t validBufferIndex = 0; uint8_t validBufferIndex = 0;

View File

@ -23,8 +23,8 @@ class LocalPoolObjectBase : public PoolVariableIF, public HasReturnvaluesIF, pub
LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr, LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
void setReadWriteMode(pool_rwm_t newReadWriteMode); void setReadWriteMode(pool_rwm_t newReadWriteMode) override;
pool_rwm_t getReadWriteMode() const; pool_rwm_t getReadWriteMode() const override;
bool isValid() const override; bool isValid() const override;
void setValid(bool valid) override; void setValid(bool valid) override;

View File

@ -459,8 +459,7 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
DeviceCommandMap::iterator command = cookieInfo.pendingCommand; DeviceCommandMap::iterator command = cookieInfo.pendingCommand;
if (command->second.useAlternativeReplyId) { if (command->second.useAlternativeReplyId) {
replyId = command->second.alternativeReplyId; replyId = command->second.alternativeReplyId;
} } else {
else {
replyId = commandId; replyId = commandId;
} }
DeviceReplyIter iter = deviceReplyMap.find(replyId); DeviceReplyIter iter = deviceReplyMap.find(replyId);

View File

@ -163,7 +163,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param counter Specifies which Action to perform * @param counter Specifies which Action to perform
* @return RETURN_OK for successful execution * @return RETURN_OK for successful execution
*/ */
virtual ReturnValue_t performOperation(uint8_t counter); virtual ReturnValue_t performOperation(uint8_t counter) override;
/** /**
* @brief Initializes the device handler * @brief Initializes the device handler
@ -173,7 +173,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* Calls fillCommandAndReplyMap(). * Calls fillCommandAndReplyMap().
* @return * @return
*/ */
virtual ReturnValue_t initialize(); virtual ReturnValue_t initialize() override;
/** /**
* @brief Intialization steps performed after all tasks have been created. * @brief Intialization steps performed after all tasks have been created.
@ -1058,11 +1058,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param parameter1 Optional parameter 1 * @param parameter1 Optional parameter 1
* @param parameter2 Optional parameter 2 * @param parameter2 Optional parameter 2
*/ */
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0); void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) override;
/** /**
* Same as triggerEvent, but for forwarding if object is used as proxy. * Same as triggerEvent, but for forwarding if object is used as proxy.
*/ */
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const override;
/** /**
* Checks if current mode is transitional mode. * Checks if current mode is transitional mode.

View File

@ -25,7 +25,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {} : BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {} MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
virtual ~MatchTree() {} virtual ~MatchTree() {}
virtual bool match(T number) { return matchesTree(number); } virtual bool match(T number) override { return matchesTree(number); }
bool matchesTree(T number) { bool matchesTree(T number) {
iterator iter = this->begin(); iterator iter = this->begin();
if (iter == this->end()) { if (iter == this->end()) {
@ -179,6 +179,9 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
virtual ReturnValue_t cleanUpElement(iterator position) { return HasReturnvaluesIF::RETURN_OK; } virtual ReturnValue_t cleanUpElement(iterator position) { return HasReturnvaluesIF::RETURN_OK; }
bool matchSubtree(iterator iter, T number) { bool matchSubtree(iterator iter, T number) {
if (iter == nullptr) {
return false;
}
bool isMatch = iter->match(number); bool isMatch = iter->match(number);
if (isMatch) { if (isMatch) {
if (iter.left() == this->end()) { if (iter.left() == this->end()) {

View File

@ -15,7 +15,7 @@ class RangeMatcher : public SerializeableMatcherIF<T> {
RangeMatcher(T lowerBound, T upperBound, bool inverted = false) RangeMatcher(T lowerBound, T upperBound, bool inverted = false)
: inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {} : inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {}
bool match(T input) { bool match(T input) override {
if (inverted) { if (inverted) {
return !doMatch(input); return !doMatch(input);
} else { } else {

View File

@ -1,9 +1,9 @@
#include "MessageQueueBase.h" #include "MessageQueueBase.h"
MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* args)
MqArgs* args): id(id) { : id(id) {
this->defaultDest = defaultDest; this->defaultDest = defaultDest;
if(args != nullptr) { if (args != nullptr) {
this->args = *args; this->args = *args;
} }
} }
@ -29,29 +29,19 @@ ReturnValue_t MessageQueueBase::receiveMessage(MessageQueueMessageIF* message,
return status; return status;
} }
MessageQueueId_t MessageQueueBase::getLastPartner() const { MessageQueueId_t MessageQueueBase::getLastPartner() const { return last; }
return last;
}
MessageQueueId_t MessageQueueBase::getId() const { MessageQueueId_t MessageQueueBase::getId() const { return id; }
return id;
}
MqArgs& MessageQueueBase::getMqArgs() { MqArgs& MessageQueueBase::getMqArgs() { return args; }
return args;
}
void MessageQueueBase::setDefaultDestination(MessageQueueId_t defaultDestination) { void MessageQueueBase::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDest = defaultDestination; this->defaultDest = defaultDestination;
} }
MessageQueueId_t MessageQueueBase::getDefaultDestination() const { MessageQueueId_t MessageQueueBase::getDefaultDestination() const { return defaultDest; }
return defaultDest;
}
bool MessageQueueBase::isDefaultDestinationSet() const { bool MessageQueueBase::isDefaultDestinationSet() const { return (defaultDest != NO_QUEUE); }
return (defaultDest != NO_QUEUE);
}
ReturnValue_t MessageQueueBase::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, ReturnValue_t MessageQueueBase::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault) { bool ignoreFault) {

View File

@ -1,11 +1,11 @@
#ifndef FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ #ifndef FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
#define FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ #define FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
#include <fsfw/ipc/definitions.h>
#include <fsfw/ipc/MessageQueueIF.h> #include <fsfw/ipc/MessageQueueIF.h>
#include <fsfw/ipc/definitions.h>
class MessageQueueBase: public MessageQueueIF { class MessageQueueBase : public MessageQueueIF {
public: public:
MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* mqArgs); MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* mqArgs);
virtual ~MessageQueueBase(); virtual ~MessageQueueBase();
@ -22,20 +22,19 @@ public:
virtual ReturnValue_t reply(MessageQueueMessageIF* message) override; virtual ReturnValue_t reply(MessageQueueMessageIF* message) override;
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) override; MessageQueueId_t* receivedFrom) override;
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
MessageQueueId_t sentFrom, bool ignoreFault = false) override; bool ignoreFault = false) override;
// OSAL specific, forward the abstract function // OSAL specific, forward the abstract function
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0; virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0;
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault = false) = 0; MessageQueueId_t sentFrom, bool ignoreFault = false) = 0;
protected:
protected:
MessageQueueId_t id = MessageQueueIF::NO_QUEUE; MessageQueueId_t id = MessageQueueIF::NO_QUEUE;
MessageQueueId_t last = MessageQueueIF::NO_QUEUE; MessageQueueId_t last = MessageQueueIF::NO_QUEUE;
MessageQueueId_t defaultDest = MessageQueueIF::NO_QUEUE; MessageQueueId_t defaultDest = MessageQueueIF::NO_QUEUE;
MqArgs args = {}; MqArgs args = {};
}; };
#endif /* FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ */ #endif /* FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ */

View File

@ -2,6 +2,7 @@
#define FSFW_IPC_MESSAGEQUEUEIF_H_ #define FSFW_IPC_MESSAGEQUEUEIF_H_
#include <fsfw/ipc/definitions.h> #include <fsfw/ipc/definitions.h>
#include <cstdint> #include <cstdint>
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
@ -45,7 +46,8 @@ class MessageQueueIF {
virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0; virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0;
/** /**
* @brief This function reads available messages from the message queue and returns the sender. * @brief This function reads available messages from the message queue and returns the
* sender.
* @details * @details
* It works identically to the other receiveMessage call, but in addition * It works identically to the other receiveMessage call, but in addition
* returns the sender's queue id. * returns the sender's queue id.

View File

@ -34,7 +34,7 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
SerializeElement<T> limitValue; SerializeElement<T> limitValue;
SerializeElement<ReturnValue_t> oldState; SerializeElement<ReturnValue_t> oldState;
SerializeElement<ReturnValue_t> newState; SerializeElement<ReturnValue_t> newState;
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE] = {};
SerializeElement<SerialBufferAdapter<uint8_t>> timestampSerializer; SerializeElement<SerialBufferAdapter<uint8_t>> timestampSerializer;
TimeStamperIF* timeStamper; TimeStamperIF* timeStamper;
MonitoringReportContent() MonitoringReportContent()
@ -46,7 +46,6 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
limitValue(0), limitValue(0),
oldState(0), oldState(0),
newState(0), newState(0),
rawTimestamp({0}),
timestampSerializer(rawTimestamp, sizeof(rawTimestamp)), timestampSerializer(rawTimestamp, sizeof(rawTimestamp)),
timeStamper(NULL) { timeStamper(NULL) {
setAllNext(); setAllNext();

View File

@ -48,9 +48,9 @@ class SystemObject : public SystemObjectIF {
virtual ~SystemObject(); virtual ~SystemObject();
object_id_t getObjectId() const override; object_id_t getObjectId() const override;
virtual ReturnValue_t initialize() override; virtual ReturnValue_t initialize() override;
virtual ReturnValue_t checkObjectConnections(); virtual ReturnValue_t checkObjectConnections() override;
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const override;
}; };
#endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */ #endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */

View File

@ -16,11 +16,13 @@
//! Debugging preprocessor define. //! Debugging preprocessor define.
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0 #define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
const timeval UdpTcPollingTask::DEFAULT_TIMEOUT = {0, 500000};
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
size_t maxRecvSize, double timeoutSeconds) size_t maxRecvSize, double timeoutSeconds)
: SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) { : SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) {
if (frameSize > 0) { if (maxRecvSize > 0) {
this->frameSize = frameSize; this->frameSize = maxRecvSize;
} else { } else {
this->frameSize = DEFAULT_MAX_RECV_SIZE; this->frameSize = DEFAULT_MAX_RECV_SIZE;
} }
@ -31,22 +33,20 @@ UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBrid
receptionBuffer.resize(this->frameSize); receptionBuffer.resize(this->frameSize);
if (timeoutSeconds == -1) { if (timeoutSeconds == -1) {
receptionTimeout = DEFAULT_TIMEOUT; receptionTimeout = UdpTcPollingTask::DEFAULT_TIMEOUT;
} else { } else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds); receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
} }
} }
UdpTcPollingTask::~UdpTcPollingTask() {} [[noreturn]] ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
/* Sender Address is cached here. */ /* Sender Address is cached here. */
struct sockaddr senderAddress; struct sockaddr senderAddress {};
socklen_t senderAddressSize = sizeof(senderAddress); socklen_t senderAddressSize = sizeof(senderAddress);
/* Poll for new UDP datagrams in permanent loop. */ /* Poll for new UDP datagrams in permanent loop. */
while (true) { while (true) {
int bytesReceived = ssize_t bytesReceived =
recvfrom(this->serverSocket, reinterpret_cast<char*>(receptionBuffer.data()), frameSize, recvfrom(this->serverSocket, reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
receptionFlags, &senderAddress, &senderAddressSize); receptionFlags, &senderAddress, &senderAddressSize);
if (bytesReceived == SOCKET_ERROR) { if (bytesReceived == SOCKET_ERROR) {
@ -70,7 +70,6 @@ ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
} }
tmtcBridge->checkAndSetClientAddress(senderAddress); tmtcBridge->checkAndSetClientAddress(senderAddress);
} }
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) { ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
@ -155,7 +154,7 @@ void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
#endif #endif
} }
#elif defined(PLATFORM_UNIX) #elif defined(PLATFORM_UNIX)
timeval tval; timeval tval {};
tval = timevalOperations::toTimeval(timeoutSeconds); tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout)); int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout));
if (result == -1) { if (result == -1) {

View File

@ -21,11 +21,11 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
public: public:
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500; 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 = {0, 500}; static const timeval DEFAULT_TIMEOUT;
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize = 0, UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize = 0,
double timeoutSeconds = -1); double timeoutSeconds = -1);
virtual ~UdpTcPollingTask(); ~UdpTcPollingTask() override = default;
/** /**
* Turn on optional timeout for UDP polling. In the default mode, * Turn on optional timeout for UDP polling. In the default mode,
@ -34,9 +34,9 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
*/ */
void setTimeout(double timeoutSeconds); void setTimeout(double timeoutSeconds);
virtual ReturnValue_t performOperation(uint8_t opCode) override; [[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initialize() override; ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override; ReturnValue_t initializeAfterTaskCreation() override;
protected: protected:
StorageManagerIF* tcStore = nullptr; StorageManagerIF* tcStore = nullptr;
@ -51,7 +51,7 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
std::vector<uint8_t> receptionBuffer; std::vector<uint8_t> receptionBuffer;
size_t frameSize = 0; size_t frameSize = 0;
timeval receptionTimeout; timeval receptionTimeout{};
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
}; };

View File

@ -20,13 +20,13 @@
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
std::string udpServerPort, object_id_t tmStoreId, const std::string& udpServerPort_, object_id_t tmStoreId,
object_id_t tcStoreId) object_id_t tcStoreId)
: TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { : TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
if (udpServerPort == "") { if (udpServerPort_.empty()) {
this->udpServerPort = DEFAULT_SERVER_PORT; udpServerPort = DEFAULT_SERVER_PORT;
} else { } else {
this->udpServerPort = udpServerPort; udpServerPort = udpServerPort_;
} }
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
@ -117,7 +117,7 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
tcpip::printAddress(&clientAddress); tcpip::printAddress(&clientAddress);
#endif #endif
int bytesSent = sendto(serverSocket, reinterpret_cast<const char *>(data), dataLen, flags, ssize_t bytesSent = sendto(serverSocket, reinterpret_cast<const char *>(data), dataLen, flags,
&clientAddress, clientAddressLen); &clientAddress, clientAddressLen);
if (bytesSent == SOCKET_ERROR) { if (bytesSent == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -150,7 +150,7 @@ void UdpTmTcBridge::checkAndSetClientAddress(sockaddr &newAddress) {
clientAddressLen = sizeof(clientAddress); clientAddressLen = sizeof(clientAddress);
} }
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs) { void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType_, dur_millis_t timeoutMs) {
this->timeoutType = timeoutType; timeoutType = timeoutType_;
this->mutexTimeoutMs = timeoutMs; mutexTimeoutMs = timeoutMs;
} }

View File

@ -29,10 +29,10 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
/* The ports chosen here should not be used by any other process. */ /* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_SERVER_PORT; static const std::string DEFAULT_SERVER_PORT;
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort = "", UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, const std::string& udpServerPort = "",
object_id_t tmStoreId = objects::TM_STORE, object_id_t tmStoreId = objects::TM_STORE,
object_id_t tcStoreId = objects::TC_STORE); object_id_t tcStoreId = objects::TC_STORE);
virtual ~UdpTmTcBridge(); ~UdpTmTcBridge() override;
/** /**
* Set properties of internal mutex. * Set properties of internal mutex.
@ -46,12 +46,12 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
std::string getUdpPort() const; std::string getUdpPort() const;
protected: protected:
virtual ReturnValue_t sendTm(const uint8_t* data, size_t dataLen) override; ReturnValue_t sendTm(const uint8_t* data, size_t dataLen) override;
private: private:
std::string udpServerPort; std::string udpServerPort;
struct sockaddr clientAddress; struct sockaddr clientAddress = {};
socklen_t clientAddressLen = 0; socklen_t clientAddressLen = 0;
//! Access to the client address is mutex protected as it is set by another task. //! Access to the client address is mutex protected as it is set by another task.

View File

@ -11,9 +11,6 @@
// TODO sanitize input? // TODO sanitize input?
// TODO much of this code can be reused for tick-only systems // TODO much of this code can be reused for tick-only systems
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void) { return 1000; } uint32_t Clock::getTicksPerSecond(void) { return 1000; }
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {

View File

@ -2,6 +2,7 @@
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ #define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
#include <fsfw/ipc/MessageQueueBase.h> #include <fsfw/ipc/MessageQueueBase.h>
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "TaskManagement.h" #include "TaskManagement.h"
#include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/internalerror/InternalErrorReporterIF.h"

View File

@ -1,5 +1,4 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE
Clock.cpp Clock.cpp
FixedTimeslotTask.cpp FixedTimeslotTask.cpp
MessageQueue.cpp MessageQueue.cpp
@ -16,9 +15,13 @@ target_sources(${LIB_FSFW_NAME}
if(UNIX) if(UNIX)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME} target_link_libraries(${LIB_FSFW_NAME} PRIVATE
PRIVATE
rt
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
) )
if(NOT APPLE)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
rt
)
endif()
endif() endif()

View File

@ -2,6 +2,7 @@
#include <chrono> #include <chrono>
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/platform.h" #include "fsfw/platform.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
@ -11,9 +12,6 @@
#include <fstream> #include <fstream>
#endif #endif
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
using SystemClock = std::chrono::system_clock; using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void) { uint32_t Clock::getTicksPerSecond(void) {
@ -127,6 +125,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now); auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto fraction = now - seconds; auto fraction = now - seconds;
time_t tt = SystemClock::to_time_t(now); time_t tt = SystemClock::to_time_t(now);
ReturnValue_t result = checkOrCreateClockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
MutexGuard helper(timeMutex);
// gmtime writes its output in a global buffer which is not Thread Safe
// Therefore we have to use a Mutex here
struct tm* timeInfo; struct tm* timeInfo;
timeInfo = gmtime(&tt); timeInfo = gmtime(&tt);
time->year = timeInfo->tm_year + 1900; time->year = timeInfo->tm_year + 1900;

View File

@ -1,17 +1,17 @@
#ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ #ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ #define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#include "fsfw/ipc/MessageQueueBase.h" #include <memory>
#include <queue>
#include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/internalerror/InternalErrorReporterIF.h"
#include "fsfw/ipc/MessageQueueBase.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MessageQueueMessage.h"
#include "fsfw/ipc/MutexIF.h" #include "fsfw/ipc/MutexIF.h"
#include "fsfw/ipc/definitions.h" #include "fsfw/ipc/definitions.h"
#include "fsfw/timemanager/Clock.h" #include "fsfw/timemanager/Clock.h"
#include <memory>
#include <queue>
/** /**
* @brief This class manages sending and receiving of * @brief This class manages sending and receiving of
* message queue messages. * message queue messages.

View File

@ -14,16 +14,16 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
TaskFactory.cpp TaskFactory.cpp
tcpipHelpers.cpp tcpipHelpers.cpp
unixUtility.cpp unixUtility.cpp
) )
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PUBLIC
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
)
if(NOT APPLE)
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
rt rt
) )
endif()
target_link_libraries(${LIB_FSFW_NAME} INTERFACE
${CMAKE_THREAD_LIBS_INIT}
)

View File

@ -8,11 +8,9 @@
#include <fstream> #include <fstream>
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
uint32_t Clock::getTicksPerSecond(void) { uint32_t Clock::getTicksPerSecond(void) {
uint32_t ticks = sysconf(_SC_CLK_TCK); uint32_t ticks = sysconf(_SC_CLK_TCK);
return ticks; return ticks;
@ -117,7 +115,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// TODO errno // TODO errno
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = checkOrCreateClockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
MutexGuard helper(timeMutex);
// gmtime writes its output in a global buffer which is not Thread Safe
// Therefore we have to use a Mutex here
struct tm* timeInfo; struct tm* timeInfo;
timeInfo = gmtime(&timeUnix.tv_sec); timeInfo = gmtime(&timeUnix.tv_sec);
time->year = timeInfo->tm_year + 1900; time->year = timeInfo->tm_year + 1900;

View File

@ -61,8 +61,7 @@ class MessageQueue : public MessageQueueBase {
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
ReturnValue_t flush(uint32_t* count) override; ReturnValue_t flush(uint32_t* count) override;
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, MessageQueueId_t sentFrom, bool ignoreFault = false) override;
bool ignoreFault = false) override;
protected: protected:
/** /**

View File

@ -6,9 +6,6 @@
#include "fsfw/ipc/MutexGuard.h" #include "fsfw/ipc/MutexGuard.h"
#include "fsfw/osal/rtems/RtemsBasic.h" #include "fsfw/osal/rtems/RtemsBasic.h"
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void) { uint32_t Clock::getTicksPerSecond(void) {
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return static_cast<uint32_t>(ticks_per_second); return static_cast<uint32_t>(ticks_per_second);

View File

@ -2,6 +2,7 @@
#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ #define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
#include <fsfw/ipc/MessageQueueBase.h> #include <fsfw/ipc/MessageQueueBase.h>
#include "RtemsBasic.h" #include "RtemsBasic.h"
#include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/internalerror/InternalErrorReporterIF.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"

View File

@ -59,14 +59,13 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
*/ */
ReturnValue_t addComponent(object_id_t object) override; ReturnValue_t addComponent(object_id_t object) override;
/** /**
* Adds an object to the list of objects to be executed. * Adds an object to the list of objects to be executed.
* The objects are executed in the order added. * The objects are executed in the order added.
* @param object pointer to the object to add. * @param object pointer to the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added. * @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/ */
ReturnValue_t addComponent(ExecutableObjectIF* object) override; ReturnValue_t addComponent(ExecutableObjectIF *object) override;
uint32_t getPeriodMs() const override; uint32_t getPeriodMs() const override;

View File

@ -54,7 +54,7 @@ class Fuse : public SystemObject,
ReturnValue_t check(); ReturnValue_t check();
uint8_t getFuseId() const; uint8_t getFuseId() const;
ReturnValue_t initialize(); ReturnValue_t initialize() override;
DeviceList devices; DeviceList devices;
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const override; SerializeIF::Endianness streamEndianness) const override;

View File

@ -43,7 +43,7 @@ class Service3Housekeeping : public CommandingServiceBase, public AcceptsHkPacke
CommandMessage* optionalNextCommand, object_id_t objectId, CommandMessage* optionalNextCommand, object_id_t objectId,
bool* isStep) override; bool* isStep) override;
virtual MessageQueueId_t getHkQueue() const; virtual MessageQueueId_t getHkQueue() const override;
private: private:
enum class Subservice { enum class Subservice {

View File

@ -30,11 +30,11 @@ ReturnValue_t Subsystem::checkSequence(HybridIterator<ModeListEntry> iter,
return FALLBACK_SEQUENCE_DOES_NOT_EXIST; return FALLBACK_SEQUENCE_DOES_NOT_EXIST;
} }
if (iter.value == NULL) { if (iter.value == nullptr) {
return NO_TARGET_TABLE; return NO_TARGET_TABLE;
} }
for (; iter.value != NULL; ++iter) { for (; iter.value != nullptr; ++iter) {
if (!existsModeTable(iter->getTableId())) { if (!existsModeTable(iter->getTableId())) {
return TABLE_DOES_NOT_EXIST; return TABLE_DOES_NOT_EXIST;
} else { } else {
@ -66,13 +66,18 @@ HybridIterator<ModeListEntry> Subsystem::getCurrentTable() {
void Subsystem::performChildOperation() { void Subsystem::performChildOperation() {
if (isInTransition) { if (isInTransition) {
if (commandsOutstanding <= 0) { // all children of the current table were commanded and replied if (commandsOutstanding <= 0) { // all children of the current table were commanded and replied
if (currentSequenceIterator.value == NULL) { // we're through with this sequence if (currentSequenceIterator.value == nullptr) { // we're through with this sequence
if (checkStateAgainstTable(currentTargetTable, targetSubmode) == RETURN_OK) { if (checkStateAgainstTable(currentTargetTable, targetSubmode) == RETURN_OK) {
setMode(targetMode, targetSubmode); setMode(targetMode, targetSubmode);
isInTransition = false; isInTransition = false;
return; return;
} else { } else {
transitionFailed(TARGET_TABLE_NOT_REACHED, getSequence(targetMode)->getTableId()); Mode_t tableId = 0;
auto seq = getSequence(targetMode);
if (seq.value != nullptr) {
tableId = seq->getTableId();
}
transitionFailed(TARGET_TABLE_NOT_REACHED, tableId);
return; return;
} }
} }
@ -248,10 +253,13 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) {
case ModeSequenceMessage::READ_TABLE: { case ModeSequenceMessage::READ_TABLE: {
ReturnValue_t result; ReturnValue_t result;
Mode_t table = ModeSequenceMessage::getSequenceId(message); Mode_t table = ModeSequenceMessage::getSequenceId(message);
EntryPointer *entry = NULL; EntryPointer *entry = nullptr;
result = modeTables.find(table, &entry); result = modeTables.find(table, &entry);
if (result != RETURN_OK) { if (result != RETURN_OK or entry == nullptr) {
replyToCommand(result, 0); replyToCommand(result, 0);
if (entry == nullptr) {
return result;
}
} }
SerializeIF *elements[2]; SerializeIF *elements[2];

View File

@ -1,14 +1,13 @@
#ifndef FSFW_SUBSYSTEM_SUBSYSTEM_H_ #ifndef FSFW_SUBSYSTEM_SUBSYSTEM_H_
#define FSFW_SUBSYSTEM_SUBSYSTEM_H_ #define FSFW_SUBSYSTEM_SUBSYSTEM_H_
#include <FSFWConfig.h>
#include "../container/FixedArrayList.h" #include "../container/FixedArrayList.h"
#include "../container/FixedMap.h" #include "../container/FixedMap.h"
#include "../container/HybridIterator.h" #include "../container/HybridIterator.h"
#include "../container/SinglyLinkedList.h" #include "../container/SinglyLinkedList.h"
#include "../serialize/SerialArrayListAdapter.h" #include "../serialize/SerialArrayListAdapter.h"
#include "SubsystemBase.h" #include "SubsystemBase.h"
#include "fsfw/FSFW.h"
#include "modes/ModeDefinitions.h" #include "modes/ModeDefinitions.h"
/** /**
@ -127,18 +126,18 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
ReturnValue_t deleteTable(Mode_t id); ReturnValue_t deleteTable(Mode_t id);
virtual void performChildOperation(); virtual void performChildOperation() override;
virtual ReturnValue_t handleCommandMessage(CommandMessage *message); virtual ReturnValue_t handleCommandMessage(CommandMessage *message) override;
bool isFallbackSequence(Mode_t SequenceId); bool isFallbackSequence(Mode_t SequenceId);
bool isTableUsed(Mode_t tableId); bool isTableUsed(Mode_t tableId);
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode); uint32_t *msToReachTheMode) override;
virtual void startTransition(Mode_t mode, Submode_t submode); virtual void startTransition(Mode_t mode, Submode_t submode) override;
void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count); void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count);

View File

@ -123,15 +123,15 @@ class SubsystemBase : public SystemObject,
virtual void performChildOperation() = 0; virtual void performChildOperation() = 0;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0; uint32_t *msToReachTheMode) override = 0;
virtual void startTransition(Mode_t mode, Submode_t submode) = 0; virtual void startTransition(Mode_t mode, Submode_t submode) override = 0;
virtual void getMode(Mode_t *mode, Submode_t *submode); virtual void getMode(Mode_t *mode, Submode_t *submode) override;
virtual void setToExternalControl(); virtual void setToExternalControl() override;
virtual void announceMode(bool recursive); virtual void announceMode(bool recursive) override;
virtual void modeChanged(); virtual void modeChanged();
}; };

View File

@ -6,10 +6,6 @@
#include "fsfw/FSFW.h" #include "fsfw/FSFW.h"
CCSDSTime::CCSDSTime() {}
CCSDSTime::~CCSDSTime() {}
ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) { ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) {
ReturnValue_t result = checkTimeOfDay(from); ReturnValue_t result = checkTimeOfDay(from);
if (result != RETURN_OK) { if (result != RETURN_OK) {
@ -91,7 +87,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* f
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return convertTimevalToTimeOfDay(to, &time); return Clock::convertTimevalToTimeOfDay(&time, to);
} }
ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from, ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from,
@ -428,7 +424,7 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, const uint8_t* from, size_t
from++; from++;
ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1); ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1);
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
if (foundLength != NULL) { if (foundLength != nullptr) {
*foundLength += 1; *foundLength += 1;
} }
} }
@ -489,11 +485,6 @@ ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) {
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t CCSDSTime::convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, timeval* from) {
// This is rather tricky. Implement only if needed. Also, if so, move to OSAL.
return UNSUPPORTED_TIME_FORMAT;
}
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength, ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength,
size_t maxLength) { size_t maxLength) {
uint8_t pField = *from; uint8_t pField = *from;
@ -583,7 +574,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime:
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return CCSDSTime::convertTimevalToTimeOfDay(to, &tempTimeval); return Clock::convertTimevalToTimeOfDay(&tempTimeval, to);
} }
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from, ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
@ -593,18 +584,18 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8
uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1; uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1;
uint8_t nFine = (pField & 0b11); uint8_t nFine = (pField & 0b11);
size_t totalLength = nCoarse + nFine; size_t totalLength = nCoarse + nFine;
if (foundLength != NULL) { if (foundLength != nullptr) {
*foundLength = totalLength; *foundLength = totalLength;
} }
if (totalLength > maxLength) { if (totalLength > maxLength) {
return LENGTH_MISMATCH; return LENGTH_MISMATCH;
} }
for (int count = 0; count < nCoarse; count++) { for (int count = nCoarse; count > 0; count--) {
secs += *from << ((nCoarse * 8 - 8) * (1 + count)); secs += *from << (count * 8 - 8);
from++; from++;
} }
for (int count = 0; count < nFine; count++) { for (int count = nFine; count > 0; count--) {
subSeconds += *from << ((nFine * 8 - 8) * (1 + count)); subSeconds += *from << (count * 8 - 8);
from++; from++;
} }
// Move to POSIX epoch. // Move to POSIX epoch.

View File

@ -161,18 +161,37 @@ class CCSDSTime : public HasReturnvaluesIF {
*/ */
static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
/**
* @brief Currently unsupported conversion due to leapseconds
*
* @param to Time Of Day (UTC)
* @param from Buffer to take the CUC from
* @param length Length of buffer
* @return ReturnValue_t UNSUPPORTED_TIME_FORMAT in any case ATM
*/
static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, uint8_t length); static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, uint8_t length);
/**
* @brief Converts from CCSDS CUC to timeval
*
* If input is CCSDS Epoch this is TAI! -> No leapsecond support.
*
* Currently, it only supports seconds + 2 Byte Subseconds (1/65536 seconds)
*
*
* @param to Timeval to write the result to
* @param from Buffer to read from
* @param foundLength Length found by this function (can be nullptr if unused)
* @param maxLength Max length of the buffer to be read
* @return ReturnValue_t - RETURN_OK if successful
* - LENGTH_MISMATCH if expected length is larger than maxLength
*/
static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from, static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from,
size_t *foundLength, size_t maxLength); size_t *foundLength, size_t maxLength);
static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from, static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from,
size_t *foundLength, size_t maxLength); size_t *foundLength, size_t maxLength);
@ -192,8 +211,8 @@ class CCSDSTime : public HasReturnvaluesIF {
static uint32_t subsecondsToMicroseconds(uint16_t subseconds); static uint32_t subsecondsToMicroseconds(uint16_t subseconds);
private: private:
CCSDSTime(); CCSDSTime(){};
virtual ~CCSDSTime(); virtual ~CCSDSTime(){};
/** /**
* checks a ccs time stream for validity * checks a ccs time stream for validity
* *
@ -223,7 +242,6 @@ class CCSDSTime : public HasReturnvaluesIF {
uint8_t *day); uint8_t *day);
static bool isLeapYear(uint32_t year); static bool isLeapYear(uint32_t year);
static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t *to, timeval *from);
}; };
#endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */ #endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */

View File

@ -99,6 +99,13 @@ class Clock {
*/ */
static ReturnValue_t getDateAndTime(TimeOfDay_t *time); static ReturnValue_t getDateAndTime(TimeOfDay_t *time);
/**
* Convert to time of day struct given the POSIX timeval struct
* @param from
* @param to
* @return
*/
static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to);
/** /**
* Converts a time of day struct to POSIX seconds. * Converts a time of day struct to POSIX seconds.
* @param time The time of day as input * @param time The time of day as input
@ -166,6 +173,7 @@ class Clock {
static MutexIF *timeMutex; static MutexIF *timeMutex;
static uint16_t leapSeconds; static uint16_t leapSeconds;
static bool leapSecondsSet;
}; };
#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */ #endif /* FSFW_TIMEMANAGER_CLOCK_H_ */

View File

@ -1,7 +1,13 @@
#include <ctime>
#include "fsfw/ipc/MutexGuard.h" #include "fsfw/ipc/MutexGuard.h"
#include "fsfw/timemanager/Clock.h" #include "fsfw/timemanager/Clock.h"
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval *tt) { uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr;
bool Clock::leapSecondsSet = false;
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
uint16_t leapSeconds; uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds); ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
@ -27,12 +33,16 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
MutexGuard helper(timeMutex); MutexGuard helper(timeMutex);
leapSeconds = leapSeconds_; leapSeconds = leapSeconds_;
leapSecondsSet = true;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) { ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if (timeMutex == nullptr) { if (not leapSecondsSet) {
return HasReturnvaluesIF::RETURN_FAILED;
}
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
MutexGuard helper(timeMutex); MutexGuard helper(timeMutex);
@ -42,9 +52,32 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) {
struct tm* timeInfo;
// According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s
// in the Windows CRT is incompatible with the C standard but this should not be an issue for
// this implementation
ReturnValue_t result = checkOrCreateClockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
MutexGuard helper(timeMutex);
// gmtime writes its output in a global buffer which is not Thread Safe
// Therefore we have to use a Mutex here
timeInfo = gmtime(&from->tv_sec);
to->year = timeInfo->tm_year + 1900;
to->month = timeInfo->tm_mon + 1;
to->day = timeInfo->tm_mday;
to->hour = timeInfo->tm_hour;
to->minute = timeInfo->tm_min;
to->second = timeInfo->tm_sec;
to->usecond = from->tv_usec;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::checkOrCreateClockMutex() { ReturnValue_t Clock::checkOrCreateClockMutex() {
if (timeMutex == nullptr) { if (timeMutex == nullptr) {
MutexFactory *mutexFactory = MutexFactory::instance(); MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) { if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -19,8 +19,8 @@ SpacePacket::SpacePacket(uint16_t packetDataLength, bool isTelecommand, uint16_t
SpacePacket::~SpacePacket(void) {} SpacePacket::~SpacePacket(void) {}
bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) { bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) {
if (packet_size <= sizeof(this->data)) { if (packet_size <= sizeof(this->localData)) {
memcpy(&this->localData.byteStream, p_Data, packet_size); memcpy(this->localData.byteStream, p_Data, packet_size);
return true; return true;
} else { } else {
return false; return false;

View File

@ -95,7 +95,7 @@ class CommandingServiceBase : public SystemObject,
*/ */
virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual uint16_t getIdentifier(); virtual uint16_t getIdentifier() override;
/** /**
* Returns the requestQueue MessageQueueId_t * Returns the requestQueue MessageQueueId_t
@ -104,7 +104,7 @@ class CommandingServiceBase : public SystemObject,
* *
* @return requestQueue messageQueueId_t * @return requestQueue messageQueueId_t
*/ */
virtual MessageQueueId_t getRequestQueue(); virtual MessageQueueId_t getRequestQueue() override;
/** /**
* Returns the commandQueue MessageQueueId_t * Returns the commandQueue MessageQueueId_t

View File

@ -3,4 +3,5 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
testOpDivider.cpp testOpDivider.cpp
testBitutil.cpp testBitutil.cpp
testCRC.cpp testCRC.cpp
testTimevalOperations.cpp
) )

View File

@ -0,0 +1,124 @@
#include <fsfw/globalfunctions/timevalOperations.h>
#include <catch2/catch_approx.hpp>
#include <catch2/catch_test_macros.hpp>
#include "fsfw_tests/unit/CatchDefinitions.h"
TEST_CASE("TimevalTest", "[timevalOperations]") {
SECTION("Comparison") {
timeval t1;
t1.tv_sec = 1648227422;
t1.tv_usec = 123456;
timeval t2;
t2.tv_sec = 1648227422;
t2.tv_usec = 123456;
REQUIRE(t1 == t2);
REQUIRE(t2 == t1);
REQUIRE_FALSE(t1 != t2);
REQUIRE_FALSE(t2 != t1);
REQUIRE(t1 <= t2);
REQUIRE(t2 <= t1);
REQUIRE(t1 >= t2);
REQUIRE(t2 >= t1);
REQUIRE_FALSE(t1 < t2);
REQUIRE_FALSE(t2 < t1);
REQUIRE_FALSE(t1 > t2);
REQUIRE_FALSE(t2 > t1);
timeval t3;
t3.tv_sec = 1648227422;
t3.tv_usec = 123457;
REQUIRE_FALSE(t1 == t3);
REQUIRE(t1 != t3);
REQUIRE(t1 <= t3);
REQUIRE_FALSE(t3 <= t1);
REQUIRE_FALSE(t1 >= t3);
REQUIRE(t3 >= t1);
REQUIRE(t1 < t3);
REQUIRE_FALSE(t3 < t1);
REQUIRE_FALSE(t1 > t3);
REQUIRE(t3 > t1);
timeval t4;
t4.tv_sec = 1648227423;
t4.tv_usec = 123456;
REQUIRE_FALSE(t1 == t4);
REQUIRE(t1 != t4);
REQUIRE(t1 <= t4);
REQUIRE_FALSE(t4 <= t1);
REQUIRE_FALSE(t1 >= t4);
REQUIRE(t4 >= t1);
REQUIRE(t1 < t4);
REQUIRE_FALSE(t4 < t1);
REQUIRE_FALSE(t1 > t4);
REQUIRE(t4 > t1);
}
SECTION("Operators") {
timeval t1;
t1.tv_sec = 1648227422;
t1.tv_usec = 123456;
timeval t2;
t2.tv_sec = 1648227422;
t2.tv_usec = 123456;
timeval t3 = t1 - t2;
REQUIRE(t3.tv_sec == 0);
REQUIRE(t3.tv_usec == 0);
timeval t4 = t1 - t3;
REQUIRE(t4.tv_sec == 1648227422);
REQUIRE(t4.tv_usec == 123456);
timeval t5 = t3 - t1;
REQUIRE(t5.tv_sec == -1648227422);
REQUIRE(t5.tv_usec == -123456);
timeval t6;
t6.tv_sec = 1648227400;
t6.tv_usec = 999999;
timeval t7 = t6 + t1;
REQUIRE(t7.tv_sec == (1648227422ull + 1648227400ull + 1ull));
REQUIRE(t7.tv_usec == 123455);
timeval t8 = t1 - t6;
REQUIRE(t8.tv_sec == 1648227422 - 1648227400 - 1);
REQUIRE(t8.tv_usec == 123457);
double scalar = 2;
timeval t9 = t1 * scalar;
REQUIRE(t9.tv_sec == 3296454844);
REQUIRE(t9.tv_usec == 246912);
timeval t10 = scalar * t1;
REQUIRE(t10.tv_sec == 3296454844);
REQUIRE(t10.tv_usec == 246912);
timeval t11 = t6 * scalar;
REQUIRE(t11.tv_sec == (3296454800 + 1));
REQUIRE(t11.tv_usec == 999998);
timeval t12 = t1 / scalar;
REQUIRE(t12.tv_sec == 824113711);
REQUIRE(t12.tv_usec == 61728);
timeval t13 = t6 / scalar;
REQUIRE(t13.tv_sec == 824113700);
// Rounding issue
REQUIRE(t13.tv_usec == 499999);
double scalar2 = t9 / t1;
REQUIRE(scalar2 == Catch::Approx(2.0));
double scalar3 = t1 / t6;
REQUIRE(scalar3 == Catch::Approx(1.000000013));
double scalar4 = t3 / t1;
REQUIRE(scalar4 == Catch::Approx(0));
double scalar5 = t12 / t1;
REQUIRE(scalar5 == Catch::Approx(0.5));
}
SECTION("timevalOperations::toTimeval") {
double seconds = 1648227422.123456;
timeval t1 = timevalOperations::toTimeval(seconds);
REQUIRE(t1.tv_sec == 1648227422);
// Allow 1 usec rounding tolerance
REQUIRE(t1.tv_usec >= 123455);
REQUIRE(t1.tv_usec <= 123457);
}
}

View File

@ -4,8 +4,8 @@
#include <cstring> #include <cstring>
#include <queue> #include <queue>
#include "fsfw/ipc/MessageQueueBase.h"
#include "fsfw/ipc/CommandMessage.h" #include "fsfw/ipc/CommandMessage.h"
#include "fsfw/ipc/MessageQueueBase.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MessageQueueMessage.h"
#include "fsfw_tests/unit/CatchDefinitions.h" #include "fsfw_tests/unit/CatchDefinitions.h"

View File

@ -1,4 +1,5 @@
target_sources(${FSFW_TEST_TGT} PRIVATE target_sources(${FSFW_TEST_TGT} PRIVATE
TestMessageQueue.cpp TestMessageQueue.cpp
TestSemaphore.cpp TestSemaphore.cpp
TestClock.cpp
) )

View File

@ -0,0 +1,86 @@
#include <fsfw/globalfunctions/timevalOperations.h>
#include <fsfw/timemanager/Clock.h>
#include <array>
#include <catch2/catch_approx.hpp>
#include <catch2/catch_test_macros.hpp>
#include "fsfw_tests/unit/CatchDefinitions.h"
TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") {
SECTION("Test getClock") {
timeval time;
ReturnValue_t result = Clock::getClock_timeval(&time);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
Clock::TimeOfDay_t timeOfDay;
result = Clock::getDateAndTime(&timeOfDay);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
timeval timeOfDayAsTimeval;
result = Clock::convertTimeOfDayToTimeval(&timeOfDay, &timeOfDayAsTimeval);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
// We require timeOfDayAsTimeval to be larger than time as it
// was request a few ns later
double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time);
CHECK(difference >= 0.0);
CHECK(difference <= 0.005);
// Conversion in the other direction
Clock::TimeOfDay_t timevalAsTimeOfDay;
result = Clock::convertTimevalToTimeOfDay(&time, &timevalAsTimeOfDay);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
CHECK(timevalAsTimeOfDay.year <= timeOfDay.year);
// TODO We should write TimeOfDay operators!
}
SECTION("Leap seconds") {
uint16_t leapSeconds = 0;
ReturnValue_t result = Clock::getLeapSeconds(&leapSeconds);
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
REQUIRE(leapSeconds == 0);
result = Clock::setLeapSeconds(18);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
result = Clock::getLeapSeconds(&leapSeconds);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(leapSeconds == 18);
}
SECTION("usec Test") {
timeval timeAsTimeval;
ReturnValue_t result = Clock::getClock_timeval(&timeAsTimeval);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
uint64_t timeAsUsec = 0;
result = Clock::getClock_usecs(&timeAsUsec);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
double timeAsUsecDouble = static_cast<double>(timeAsUsec) / 1000000.0;
timeval timeAsUsecTimeval = timevalOperations::toTimeval(timeAsUsecDouble);
double difference = timevalOperations::toDouble(timeAsUsecTimeval - timeAsTimeval);
// We accept 5 ms difference
CHECK(difference >= 0.0);
CHECK(difference <= 0.005);
uint64_t timevalAsUint64 = static_cast<uint64_t>(timeAsTimeval.tv_sec) * 1000000ull +
static_cast<uint64_t>(timeAsTimeval.tv_usec);
CHECK((timeAsUsec - timevalAsUint64) >= 0);
CHECK((timeAsUsec - timevalAsUint64) <= (5 * 1000));
}
SECTION("Test j2000") {
double j2000;
timeval time;
time.tv_sec = 1648208539;
time.tv_usec = 0;
ReturnValue_t result = Clock::convertTimevalToJD2000(time, &j2000);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
double correctJ2000 = 2459663.98772 - 2451545.0;
CHECK(j2000 == Catch::Approx(correctJ2000).margin(1.2 * 1e-8));
}
SECTION("Convert to TT") {
timeval utcTime;
utcTime.tv_sec = 1648208539;
utcTime.tv_usec = 999000;
timeval tt;
ReturnValue_t result = Clock::setLeapSeconds(27);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
result = Clock::convertUTCToTT(utcTime, &tt);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
CHECK(tt.tv_usec == 183000);
// The plus 1 is a own forced overflow of usecs
CHECK(tt.tv_sec == (1648208539 + 27 + 10 + 32 + 1));
}
}

View File

@ -81,7 +81,8 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
std::string timeAscii = "2022-12-31T23:59:59.123Z"; std::string timeAscii = "2022-12-31T23:59:59.123Z";
Clock::TimeOfDay_t timeTo; Clock::TimeOfDay_t timeTo;
const uint8_t* timeChar = reinterpret_cast<const uint8_t*>(timeAscii.c_str()); const uint8_t* timeChar = reinterpret_cast<const uint8_t*>(timeAscii.c_str());
CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length()); auto result = CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length());
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(timeTo.year == 2022); REQUIRE(timeTo.year == 2022);
REQUIRE(timeTo.month == 12); REQUIRE(timeTo.month == 12);
REQUIRE(timeTo.day == 31); REQUIRE(timeTo.day == 31);
@ -89,6 +90,19 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
REQUIRE(timeTo.minute == 59); REQUIRE(timeTo.minute == 59);
REQUIRE(timeTo.second == 59); REQUIRE(timeTo.second == 59);
REQUIRE(timeTo.usecond == Catch::Approx(123000)); REQUIRE(timeTo.usecond == Catch::Approx(123000));
std::string timeAscii2 = "2022-365T23:59:59.123Z";
const uint8_t* timeChar2 = reinterpret_cast<const uint8_t*>(timeAscii2.c_str());
Clock::TimeOfDay_t timeTo2;
result = CCSDSTime::convertFromCcsds(&timeTo2, timeChar2, timeAscii2.length());
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(timeTo2.year == 2022);
REQUIRE(timeTo2.month == 12);
REQUIRE(timeTo2.day == 31);
REQUIRE(timeTo2.hour == 23);
REQUIRE(timeTo2.minute == 59);
REQUIRE(timeTo2.second == 59);
REQUIRE(timeTo2.usecond == Catch::Approx(123000));
} }
SECTION("CDS Conversions") { SECTION("CDS Conversions") {
@ -119,6 +133,7 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
CHECK(cdsTime.msDay_h == 0xE0); CHECK(cdsTime.msDay_h == 0xE0);
CHECK(cdsTime.msDay_l == 0xC5); CHECK(cdsTime.msDay_l == 0xC5);
CHECK(cdsTime.msDay_ll == 0xC3); CHECK(cdsTime.msDay_ll == 0xC3);
CHECK(cdsTime.pField == CCSDSTime::P_FIELD_CDS_SHORT);
// Conversion back to timeval // Conversion back to timeval
timeval timeReturnAsTimeval; timeval timeReturnAsTimeval;
@ -128,5 +143,77 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
timeval difference = timeAsTimeval - timeReturnAsTimeval; timeval difference = timeAsTimeval - timeReturnAsTimeval;
CHECK(difference.tv_usec == 456); CHECK(difference.tv_usec == 456);
CHECK(difference.tv_sec == 0); CHECK(difference.tv_sec == 0);
Clock::TimeOfDay_t timeReturnAsTimeOfDay;
result = CCSDSTime::convertFromCDS(&timeReturnAsTimeOfDay, &cdsTime);
CHECK(result == HasReturnvaluesIF::RETURN_OK);
CHECK(timeReturnAsTimeOfDay.year == 2020);
CHECK(timeReturnAsTimeOfDay.month == 2);
CHECK(timeReturnAsTimeOfDay.day == 29);
CHECK(timeReturnAsTimeOfDay.hour == 13);
CHECK(timeReturnAsTimeOfDay.minute == 24);
CHECK(timeReturnAsTimeOfDay.second == 45);
// micro seconds precision is lost
CHECK(timeReturnAsTimeOfDay.usecond == 123000);
Clock::TimeOfDay_t timeReturnAsTodFromBuffer;
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(&cdsTime);
result = CCSDSTime::convertFromCDS(&timeReturnAsTodFromBuffer, buffer, sizeof(cdsTime));
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
CHECK(timeReturnAsTodFromBuffer.year == time.year);
CHECK(timeReturnAsTodFromBuffer.month == time.month);
CHECK(timeReturnAsTodFromBuffer.day == time.day);
CHECK(timeReturnAsTodFromBuffer.hour == time.hour);
CHECK(timeReturnAsTodFromBuffer.minute == time.minute);
CHECK(timeReturnAsTodFromBuffer.second == time.second);
CHECK(timeReturnAsTodFromBuffer.usecond == 123000);
Clock::TimeOfDay_t todFromCCSDS;
result = CCSDSTime::convertFromCcsds(&todFromCCSDS, buffer, sizeof(cdsTime));
CHECK(result == HasReturnvaluesIF::RETURN_OK);
CHECK(todFromCCSDS.year == time.year);
CHECK(todFromCCSDS.month == time.month);
CHECK(todFromCCSDS.day == time.day);
CHECK(todFromCCSDS.hour == time.hour);
CHECK(todFromCCSDS.minute == time.minute);
CHECK(todFromCCSDS.second == time.second);
CHECK(todFromCCSDS.usecond == 123000);
}
SECTION("CUC") {
timeval to;
// seconds = 0x771E960F, microseconds = 0x237
// microseconds = 567000
// This gives 37158.912 1/65536 seconds -> rounded to 37159 -> 0x9127
// This results in -> 567001 us
std::array<uint8_t, 7> cucBuffer = {
CCSDSTime::P_FIELD_CUC_6B_CCSDS, 0x77, 0x1E, 0x96, 0x0F, 0x91, 0x27};
size_t foundLength = 0;
auto result = CCSDSTime::convertFromCUC(&to, cucBuffer.data(), &foundLength, cucBuffer.size());
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(foundLength == 7);
REQUIRE(to.tv_sec == 1619801999); // TAI (no leap seconds)
REQUIRE(to.tv_usec == 567001);
Clock::TimeOfDay_t tod;
result = CCSDSTime::convertFromCUC(&tod, cucBuffer.data(), cucBuffer.size());
// This test must be changed if this is ever going to be implemented
REQUIRE(result == CCSDSTime::UNSUPPORTED_TIME_FORMAT);
}
SECTION("CCSDS Failures") {
Clock::TimeOfDay_t time;
time.year = 2020;
time.month = 12;
time.day = 32;
time.hour = 13;
time.minute = 24;
time.second = 45;
time.usecond = 123456;
CCSDSTime::Ccs_mseconds to;
auto result = CCSDSTime::convertToCcsds(&to, &time);
REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT);
CCSDSTime::Ccs_seconds to2;
result = CCSDSTime::convertToCcsds(&to2, &time);
REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT);
} }
} }