sequence count init value #81
@ -1,4 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
set(LIB_FSFW_NAME fsfw)
|
||||
project(${LIB_FSFW_NAME})
|
||||
|
||||
set(FSFW_VERSION_IF_GIT_FAILS 4)
|
||||
@ -16,11 +17,12 @@ set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING
|
||||
set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING
|
||||
"ETL library exact version requirement"
|
||||
)
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
|
||||
set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -57,7 +59,7 @@ option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF)
|
||||
# Contrib sources
|
||||
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
|
||||
|
||||
set(LIB_FSFW_NAME fsfw)
|
||||
|
||||
set(FSFW_TEST_TGT fsfw-tests)
|
||||
set(FSFW_DUMMY_TGT fsfw-dummy)
|
||||
|
||||
@ -110,9 +112,7 @@ if(FSFW_BUILD_UNITTESTS)
|
||||
GIT_TAG ${FSFW_CATCH2_LIB_VERSION}
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
#fixes regression -preview4, to be confirmed in later releases
|
||||
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
||||
list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
|
||||
endif()
|
||||
|
||||
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
|
||||
@ -135,23 +135,36 @@ endif()
|
||||
message(STATUS "Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}")
|
||||
|
||||
# Check whether the user has already installed ETL first
|
||||
# find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
|
||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
|
||||
# Not installed, so use FetchContent to download and provide etl
|
||||
# if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||
message(STATUS
|
||||
"No etl installation was found with find_package. Installing and providing "
|
||||
"etl with FetchContent"
|
||||
"No ETL installation was found with find_package. Installing and providing "
|
||||
"etl with FindPackage"
|
||||
)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
${FSFW_ETL_LIB_NAME}
|
||||
GIT_REPOSITORY https://github.com/ETLCPP/etl
|
||||
GIT_TAG ${FSFW_ETL_LIB_VERSION}
|
||||
)
|
||||
list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME})
|
||||
endif()
|
||||
|
||||
FetchContent_MakeAvailable(${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()
|
||||
|
||||
set(FSFW_CORE_INC_PATH "inc")
|
||||
|
||||
@ -414,7 +427,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
||||
)
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||
etl
|
||||
${FSFW_ETL_LINK_TARGET}
|
||||
${FSFW_ADDITIONAL_LINK_LIBS}
|
||||
)
|
||||
|
||||
|
@ -6,3 +6,9 @@ RUN apt-get --yes upgrade
|
||||
#tzdata is a dependency, won't install otherwise
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
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
|
||||
|
2
automation/Jenkinsfile
vendored
2
automation/Jenkinsfile
vendored
@ -3,7 +3,7 @@ pipeline {
|
||||
BUILDDIR = 'build-tests'
|
||||
}
|
||||
agent {
|
||||
docker { image 'fsfw-ci:d1'}
|
||||
docker { image 'fsfw-ci:d2'}
|
||||
}
|
||||
stages {
|
||||
stage('Clean') {
|
||||
|
@ -46,9 +46,9 @@ class GpioIF : public HasReturnvaluesIF {
|
||||
* an ouput or input gpio.
|
||||
*
|
||||
* @param gpioId A unique number which specifies the GPIO to read.
|
||||
* @param gpioState State of GPIO will be written to this pointer.
|
||||
* @param gpioState State of GPIO will be written to this reference
|
||||
*/
|
||||
virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
|
||||
virtual ReturnValue_t readGpio(gpioId_t gpioId, gpio::Levels& gpioState) = 0;
|
||||
};
|
||||
|
||||
#endif /* COMMON_GPIO_GPIOIF_H_ */
|
||||
|
@ -9,7 +9,7 @@ using gpioId_t = uint16_t;
|
||||
|
||||
namespace gpio {
|
||||
|
||||
enum class Levels : int { LOW = 0, HIGH = 1, NONE = 99 };
|
||||
enum class Levels : int { LOW = 0, HIGH = 1, FAILED = -1, NONE = 99 };
|
||||
|
||||
enum class Direction : int { IN = 0, OUT = 1 };
|
||||
|
||||
|
@ -12,9 +12,14 @@ if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
|
||||
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
|
||||
add_subdirectory(gpio)
|
||||
endif()
|
||||
add_subdirectory(spi)
|
||||
add_subdirectory(i2c)
|
||||
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()
|
||||
|
||||
add_subdirectory(uio)
|
||||
|
@ -280,7 +280,7 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regul
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
|
||||
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, gpio::Levels& gpioState) {
|
||||
gpioMapIter = gpioMap.find(gpioId);
|
||||
if (gpioMapIter == gpioMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@ -299,7 +299,10 @@ ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
|
||||
if (regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
*gpioState = gpiod_line_get_value(regularGpio->lineHandle);
|
||||
gpioState = static_cast<gpio::Levels>(gpiod_line_get_value(regularGpio->lineHandle));
|
||||
if (gpioState == gpio::Levels::FAILED) {
|
||||
return GPIO_GET_VALUE_FAILED;
|
||||
}
|
||||
} else {
|
||||
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
||||
if (gpioCallback->callback == nullptr) {
|
||||
|
@ -31,14 +31,16 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
|
||||
static constexpr ReturnValue_t GPIO_INIT_FAILED =
|
||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 6);
|
||||
|
||||
// Will be returned if getting the line value failed. Error type will be set to errno in this case
|
||||
static constexpr ReturnValue_t GPIO_GET_VALUE_FAILED =
|
||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 7);
|
||||
LinuxLibgpioIF(object_id_t objectId);
|
||||
virtual ~LinuxLibgpioIF();
|
||||
|
||||
ReturnValue_t addGpios(GpioCookie* gpioCookie) override;
|
||||
ReturnValue_t pullHigh(gpioId_t gpioId) override;
|
||||
ReturnValue_t pullLow(gpioId_t gpioId) override;
|
||||
ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override;
|
||||
ReturnValue_t readGpio(gpioId_t gpioId, gpio::Levels& gpioState) override;
|
||||
|
||||
private:
|
||||
static const size_t MAX_CHIPNAME_LENGTH = 11;
|
||||
|
@ -170,18 +170,20 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
|
||||
|
||||
int readLen = read(fd, replyBuffer, requestLen);
|
||||
if (readLen != static_cast<int>(requestLen)) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1 and FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "I2cComIF::requestReceiveMessage: Reading from I2C "
|
||||
<< "device failed with error code " << errno << ". Description"
|
||||
<< " of error: " << strerror(errno) << std::endl;
|
||||
sif::error << "I2cComIF::requestReceiveMessage: Read only " << readLen << " from " << requestLen
|
||||
<< " bytes" << std::endl;
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
if (readLen < 0) {
|
||||
sif::warning << "I2cComIF::requestReceiveMessage: Reading from I2C "
|
||||
<< "device failed with error code " << errno << " | " << strerror(errno)
|
||||
<< std::endl;
|
||||
} else {
|
||||
sif::warning << "I2cComIF::requestReceiveMessage: Read only " << readLen << " from "
|
||||
<< requestLen << " bytes" << std::endl;
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
#endif
|
||||
i2cDeviceMapIter->second.replyLen = 0;
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "I2cComIF::requestReceiveMessage: Read " << readLen << " of " << requestLen
|
||||
<< " bytes" << std::endl;
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)
|
||||
|
@ -265,6 +265,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
|
||||
cfsetispeed(options, B230400);
|
||||
cfsetospeed(options, B230400);
|
||||
break;
|
||||
#ifndef __APPLE__
|
||||
case UartBaudRate::RATE_460800:
|
||||
cfsetispeed(options, B460800);
|
||||
cfsetospeed(options, B460800);
|
||||
@ -313,6 +314,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
|
||||
cfsetispeed(options, B4000000);
|
||||
cfsetospeed(options, B4000000);
|
||||
break;
|
||||
#endif // ! __APPLE__
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;
|
||||
|
@ -44,7 +44,7 @@ class HeaderSerializer : public SerializeIF, public PduHeaderIF {
|
||||
cfdp::WidthInBytes getLenEntityIds() const override;
|
||||
cfdp::WidthInBytes getLenSeqNum() const override;
|
||||
cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override;
|
||||
bool hasSegmentMetadataFlag() const;
|
||||
bool hasSegmentMetadataFlag() const override;
|
||||
void setSegmentationControl(cfdp::SegmentationControl);
|
||||
|
||||
void getSourceId(cfdp::EntityId& sourceId) const override;
|
||||
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
template <typename T, size_t MAX_SIZE, typename count_t = uint8_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),
|
||||
"count_t is not large enough to hold MAX_SIZE");
|
||||
#endif
|
||||
|
@ -10,7 +10,7 @@ class HybridIterator : public LinkedElement<T>::Iterator, public ArrayList<T, co
|
||||
HybridIterator() {}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class ControllerBase : public HasModesIF,
|
||||
virtual void performControlOperation() = 0;
|
||||
|
||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) = 0;
|
||||
uint32_t *msToReachTheMode) override = 0;
|
||||
|
||||
const object_id_t parentId;
|
||||
|
||||
@ -80,9 +80,9 @@ class ControllerBase : public HasModesIF,
|
||||
|
||||
/** Mode helpers */
|
||||
virtual void modeChanged(Mode_t mode, Submode_t submode);
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
||||
virtual void setToExternalControl();
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
virtual void setToExternalControl() override;
|
||||
virtual void announceMode(bool recursive);
|
||||
/** HK helpers */
|
||||
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
|
||||
|
@ -109,7 +109,7 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF, public HasRetu
|
||||
*/
|
||||
virtual ReturnValue_t unlockDataPool() override;
|
||||
|
||||
virtual uint16_t getFillCount() const;
|
||||
virtual uint16_t getFillCount() const override;
|
||||
|
||||
/* SerializeIF implementations */
|
||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||
|
@ -94,13 +94,14 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount) / 8.0);
|
||||
uint8_t *validityPtr = nullptr;
|
||||
#ifdef _MSC_VER
|
||||
/* Use a std::vector here because MSVC will (rightly) not create a fixed size array
|
||||
with a non constant size specifier */
|
||||
std::vector<uint8_t> validityMask(validityMaskSize);
|
||||
#if defined(_MSC_VER) || defined(__clang__)
|
||||
// Use a std::vector here because MSVC will (rightly) not create a fixed size array
|
||||
// with a non constant size specifier. The Apple compiler (LLVM) will not accept
|
||||
// the initialization of a variable sized array
|
||||
std::vector<uint8_t> validityMask(validityMaskSize, 0);
|
||||
validityPtr = validityMask.data();
|
||||
#else
|
||||
uint8_t validityMask[validityMaskSize] = {0};
|
||||
uint8_t validityMask[validityMaskSize] = {};
|
||||
validityPtr = validityMask;
|
||||
#endif
|
||||
uint8_t validBufferIndex = 0;
|
||||
|
@ -23,8 +23,8 @@ class LocalPoolObjectBase : public PoolVariableIF, public HasReturnvaluesIF, pub
|
||||
LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr,
|
||||
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
|
||||
|
||||
void setReadWriteMode(pool_rwm_t newReadWriteMode);
|
||||
pool_rwm_t getReadWriteMode() const;
|
||||
void setReadWriteMode(pool_rwm_t newReadWriteMode) override;
|
||||
pool_rwm_t getReadWriteMode() const override;
|
||||
|
||||
bool isValid() const override;
|
||||
void setValid(bool valid) override;
|
||||
|
@ -243,16 +243,27 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::decrementDeviceReplyMap() {
|
||||
bool timedOut = false;
|
||||
for (std::pair<const DeviceCommandId_t, DeviceReplyInfo>& replyPair : deviceReplyMap) {
|
||||
if (replyPair.second.delayCycles != 0) {
|
||||
if (replyPair.second.countdown != nullptr && replyPair.second.active) {
|
||||
if (replyPair.second.countdown->hasTimedOut()) {
|
||||
timedOut = true;
|
||||
}
|
||||
}
|
||||
if (replyPair.second.delayCycles != 0 && replyPair.second.countdown == nullptr) {
|
||||
replyPair.second.delayCycles--;
|
||||
if (replyPair.second.delayCycles == 0) {
|
||||
if (replyPair.second.periodic) {
|
||||
replyPair.second.delayCycles = replyPair.second.maxDelayCycles;
|
||||
}
|
||||
timedOut = true;
|
||||
}
|
||||
}
|
||||
if (timedOut) {
|
||||
replyToReply(replyPair.first, replyPair.second, TIMEOUT);
|
||||
missedReply(replyPair.first);
|
||||
}
|
||||
timedOut = false;
|
||||
replyPair.second.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -416,20 +427,22 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, Submode_t s
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
|
||||
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
|
||||
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) {
|
||||
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId,
|
||||
Countdown* countdown) {
|
||||
// No need to check, as we may try to insert multiple times.
|
||||
insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId);
|
||||
if (hasDifferentReplyId) {
|
||||
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic);
|
||||
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic, countdown);
|
||||
} else {
|
||||
return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic);
|
||||
return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic,
|
||||
countdown);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
||||
uint16_t maxDelayCycles,
|
||||
LocalPoolDataSetBase* dataSet, size_t replyLen,
|
||||
bool periodic) {
|
||||
bool periodic, Countdown* countdown) {
|
||||
DeviceReplyInfo info;
|
||||
info.maxDelayCycles = maxDelayCycles;
|
||||
info.periodic = periodic;
|
||||
@ -437,6 +450,10 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
||||
info.replyLen = replyLen;
|
||||
info.dataSet = dataSet;
|
||||
info.command = deviceCommandMap.end();
|
||||
info.countdown = countdown;
|
||||
if (info.periodic) {
|
||||
info.active = true;
|
||||
}
|
||||
auto resultPair = deviceReplyMap.emplace(replyId, info);
|
||||
if (resultPair.second) {
|
||||
return RETURN_OK;
|
||||
@ -472,7 +489,8 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
|
||||
}
|
||||
DeviceReplyIter iter = deviceReplyMap.find(replyId);
|
||||
if (iter != deviceReplyMap.end()) {
|
||||
if (iter->second.delayCycles != 0) {
|
||||
if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) ||
|
||||
(iter->second.active && iter->second.countdown != nullptr)) {
|
||||
return iter->second.replyLen;
|
||||
}
|
||||
}
|
||||
@ -816,17 +834,18 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
|
||||
|
||||
DeviceReplyInfo* info = &(iter->second);
|
||||
|
||||
if (info->delayCycles != 0) {
|
||||
if ((info->delayCycles != 0 && info->countdown == nullptr) ||
|
||||
(info->active && info->countdown != nullptr)) {
|
||||
result = interpretDeviceReply(foundId, receivedData);
|
||||
|
||||
if (result == IGNORE_REPLY_DATA) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->periodic) {
|
||||
info->delayCycles = info->maxDelayCycles;
|
||||
} else {
|
||||
info->delayCycles = 0;
|
||||
if (info->active && info->countdown != nullptr) {
|
||||
disableTimeoutControlledReply(info);
|
||||
} else if (info->delayCycles != 0) {
|
||||
disableDelayCyclesControlledReply(info);
|
||||
}
|
||||
|
||||
if (result != RETURN_OK) {
|
||||
@ -845,6 +864,24 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::disableTimeoutControlledReply(DeviceReplyInfo* info) {
|
||||
if (info->periodic) {
|
||||
info->countdown->resetTimer();
|
||||
} else {
|
||||
info->active = false;
|
||||
info->countdown->timeOut();
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::disableDelayCyclesControlledReply(DeviceReplyInfo* info) {
|
||||
if (info->periodic) {
|
||||
info->delayCycles = info->maxDelayCycles;
|
||||
} else {
|
||||
info->delayCycles = 0;
|
||||
info->active = false;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data,
|
||||
size_t* len) {
|
||||
size_t lenTmp;
|
||||
@ -970,6 +1007,10 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap(DeviceCommandMap::iterato
|
||||
info->delayCycles = info->maxDelayCycles;
|
||||
info->command = command;
|
||||
command->second.expectedReplies = expectedReplies;
|
||||
if (info->countdown != nullptr) {
|
||||
info->countdown->resetTimer();
|
||||
}
|
||||
info->active = true;
|
||||
return RETURN_OK;
|
||||
} else {
|
||||
return NO_REPLY_EXPECTED;
|
||||
@ -1204,7 +1245,8 @@ void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) {
|
||||
bool DeviceHandlerBase::isAwaitingReply() {
|
||||
std::map<DeviceCommandId_t, DeviceReplyInfo>::iterator iter;
|
||||
for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) {
|
||||
if (iter->second.delayCycles != 0) {
|
||||
if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) ||
|
||||
(iter->second.active && iter->second.countdown != nullptr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1360,6 +1402,9 @@ uint8_t DeviceHandlerBase::getReplyDelayCycles(DeviceCommandId_t deviceCommand)
|
||||
if (iter == deviceReplyMap.end()) {
|
||||
return 0;
|
||||
}
|
||||
else if (iter->second.countdown != nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return iter->second.delayCycles;
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* @param counter Specifies which Action to perform
|
||||
* @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
|
||||
@ -176,7 +176,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* Calls fillCommandAndReplyMap().
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initialize();
|
||||
virtual ReturnValue_t initialize() override;
|
||||
|
||||
/**
|
||||
* @brief Intialization steps performed after all tasks have been created.
|
||||
@ -451,6 +451,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||
* - @c RETURN_FAILED else.
|
||||
*/
|
||||
@ -458,7 +461,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
LocalPoolDataSetBase *replyDataSet = nullptr,
|
||||
size_t replyLen = 0, bool periodic = false,
|
||||
bool hasDifferentReplyId = false,
|
||||
DeviceCommandId_t replyId = 0);
|
||||
DeviceCommandId_t replyId = 0,
|
||||
Countdown *countdown = nullptr);
|
||||
/**
|
||||
* @brief This is a helper method to insert replies in the reply map.
|
||||
* @param deviceCommand Identifier of the reply to add.
|
||||
@ -468,12 +472,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||
* - @c RETURN_FAILED else.
|
||||
*/
|
||||
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
|
||||
LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0,
|
||||
bool periodic = false);
|
||||
bool periodic = false, Countdown *countdown = nullptr);
|
||||
|
||||
/**
|
||||
* @brief A simple command to add a command to the commandList.
|
||||
@ -792,6 +799,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
LocalPoolDataSetBase *dataSet = nullptr;
|
||||
//! The command that expects this reply.
|
||||
DeviceCommandMap::iterator command;
|
||||
//! Instead of using delayCycles to specify the maximum time to wait for the device reply, it
|
||||
//! is also possible specify a countdown
|
||||
Countdown* countdown = nullptr;
|
||||
//! will be set to true when reply is enabled
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
using DeviceReplyMap = std::map<DeviceCommandId_t, DeviceReplyInfo>;
|
||||
@ -1068,11 +1080,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* @param parameter1 Optional parameter 1
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
@ -1253,6 +1266,17 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
void doGetRead(void);
|
||||
|
||||
/**
|
||||
* @brief Handles disabling of replies which use a timeout to detect missed replies.
|
||||
*/
|
||||
void disableTimeoutControlledReply(DeviceReplyInfo* info);
|
||||
|
||||
/**
|
||||
* @brief Handles disabling of replies which use a number of maximum delay cycles to detect
|
||||
* missed replies.
|
||||
*/
|
||||
void disableDelayCyclesControlledReply(DeviceReplyInfo* info);
|
||||
|
||||
/**
|
||||
* Retrive data from the #IPCStore.
|
||||
*
|
||||
|
@ -25,7 +25,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
||||
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
|
||||
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
|
||||
virtual ~MatchTree() {}
|
||||
virtual bool match(T number) { return matchesTree(number); }
|
||||
virtual bool match(T number) override { return matchesTree(number); }
|
||||
bool matchesTree(T number) {
|
||||
iterator iter = this->begin();
|
||||
if (iter == this->end()) {
|
||||
|
@ -15,7 +15,7 @@ class RangeMatcher : public SerializeableMatcherIF<T> {
|
||||
RangeMatcher(T lowerBound, T upperBound, bool inverted = false)
|
||||
: inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {}
|
||||
|
||||
bool match(T input) {
|
||||
bool match(T input) override {
|
||||
if (inverted) {
|
||||
return !doMatch(input);
|
||||
} else {
|
||||
|
@ -34,7 +34,7 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
|
||||
SerializeElement<T> limitValue;
|
||||
SerializeElement<ReturnValue_t> oldState;
|
||||
SerializeElement<ReturnValue_t> newState;
|
||||
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE];
|
||||
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE] = {};
|
||||
SerializeElement<SerialBufferAdapter<uint8_t>> timestampSerializer;
|
||||
TimeStamperIF* timeStamper;
|
||||
MonitoringReportContent()
|
||||
@ -46,7 +46,6 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
|
||||
limitValue(0),
|
||||
oldState(0),
|
||||
newState(0),
|
||||
rawTimestamp({0}),
|
||||
timestampSerializer(rawTimestamp, sizeof(rawTimestamp)),
|
||||
timeStamper(NULL) {
|
||||
setAllNext();
|
||||
|
@ -48,9 +48,10 @@ class SystemObject : public SystemObjectIF {
|
||||
virtual ~SystemObject();
|
||||
object_id_t getObjectId() const 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_ */
|
||||
|
@ -16,11 +16,13 @@
|
||||
//! Debugging preprocessor define.
|
||||
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
|
||||
|
||||
const timeval UdpTcPollingTask::DEFAULT_TIMEOUT = {0, 500000};
|
||||
|
||||
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
|
||||
size_t maxRecvSize, double timeoutSeconds)
|
||||
: SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) {
|
||||
if (frameSize > 0) {
|
||||
this->frameSize = frameSize;
|
||||
if (maxRecvSize > 0) {
|
||||
this->frameSize = maxRecvSize;
|
||||
} else {
|
||||
this->frameSize = DEFAULT_MAX_RECV_SIZE;
|
||||
}
|
||||
@ -31,22 +33,20 @@ UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBrid
|
||||
receptionBuffer.resize(this->frameSize);
|
||||
|
||||
if (timeoutSeconds == -1) {
|
||||
receptionTimeout = DEFAULT_TIMEOUT;
|
||||
receptionTimeout = UdpTcPollingTask::DEFAULT_TIMEOUT;
|
||||
} else {
|
||||
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
UdpTcPollingTask::~UdpTcPollingTask() {}
|
||||
|
||||
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
|
||||
[[noreturn]] ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
|
||||
/* Sender Address is cached here. */
|
||||
struct sockaddr senderAddress;
|
||||
struct sockaddr senderAddress {};
|
||||
socklen_t senderAddressSize = sizeof(senderAddress);
|
||||
|
||||
/* Poll for new UDP datagrams in permanent loop. */
|
||||
while (true) {
|
||||
int bytesReceived =
|
||||
ssize_t bytesReceived =
|
||||
recvfrom(this->serverSocket, reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
|
||||
receptionFlags, &senderAddress, &senderAddressSize);
|
||||
if (bytesReceived == SOCKET_ERROR) {
|
||||
@ -70,7 +70,6 @@ ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
|
||||
}
|
||||
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
||||
@ -155,7 +154,7 @@ void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
|
||||
#endif
|
||||
}
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
timeval tval;
|
||||
timeval tval{};
|
||||
tval = timevalOperations::toTimeval(timeoutSeconds);
|
||||
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout));
|
||||
if (result == -1) {
|
||||
|
@ -21,11 +21,11 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
|
||||
public:
|
||||
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
|
||||
//! 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,
|
||||
double timeoutSeconds = -1);
|
||||
virtual ~UdpTcPollingTask();
|
||||
~UdpTcPollingTask() override = default;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
virtual ReturnValue_t initialize() override;
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
[[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
ReturnValue_t initialize() override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
protected:
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
@ -51,7 +51,7 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
|
||||
std::vector<uint8_t> receptionBuffer;
|
||||
|
||||
size_t frameSize = 0;
|
||||
timeval receptionTimeout;
|
||||
timeval receptionTimeout{};
|
||||
|
||||
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
||||
};
|
||||
|
@ -20,13 +20,13 @@
|
||||
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||
|
||||
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)
|
||||
: TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||
if (udpServerPort == "") {
|
||||
this->udpServerPort = DEFAULT_SERVER_PORT;
|
||||
if (udpServerPort_.empty()) {
|
||||
udpServerPort = DEFAULT_SERVER_PORT;
|
||||
} else {
|
||||
this->udpServerPort = udpServerPort;
|
||||
udpServerPort = udpServerPort_;
|
||||
}
|
||||
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
@ -117,7 +117,7 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||
tcpip::printAddress(&clientAddress);
|
||||
#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);
|
||||
if (bytesSent == SOCKET_ERROR) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@ -150,7 +150,7 @@ void UdpTmTcBridge::checkAndSetClientAddress(sockaddr &newAddress) {
|
||||
clientAddressLen = sizeof(clientAddress);
|
||||
}
|
||||
|
||||
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs) {
|
||||
this->timeoutType = timeoutType;
|
||||
this->mutexTimeoutMs = timeoutMs;
|
||||
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType_, dur_millis_t timeoutMs) {
|
||||
timeoutType = timeoutType_;
|
||||
mutexTimeoutMs = timeoutMs;
|
||||
}
|
||||
|
@ -29,10 +29,10 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
|
||||
/* The ports chosen here should not be used by any other process. */
|
||||
static const std::string DEFAULT_SERVER_PORT;
|
||||
|
||||
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort = "",
|
||||
object_id_t tmStoreId = objects::TM_STORE,
|
||||
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
|
||||
object_id_t tcStoreId = objects::TC_STORE);
|
||||
virtual ~UdpTmTcBridge();
|
||||
~UdpTmTcBridge() override;
|
||||
|
||||
/**
|
||||
* Set properties of internal mutex.
|
||||
@ -46,12 +46,12 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
|
||||
std::string getUdpPort() const;
|
||||
|
||||
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:
|
||||
std::string udpServerPort;
|
||||
|
||||
struct sockaddr clientAddress;
|
||||
struct sockaddr clientAddress = {};
|
||||
socklen_t clientAddressLen = 0;
|
||||
|
||||
//! Access to the client address is mutex protected as it is set by another task.
|
||||
|
@ -46,7 +46,7 @@ void FixedTimeslotTask::missedDeadlineCounter() {
|
||||
FixedTimeslotTask::deadlineMissedCount++;
|
||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
|
||||
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
target_sources(${LIB_FSFW_NAME}
|
||||
PRIVATE
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
Clock.cpp
|
||||
FixedTimeslotTask.cpp
|
||||
MessageQueue.cpp
|
||||
@ -16,9 +15,13 @@ target_sources(${LIB_FSFW_NAME}
|
||||
if(UNIX)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME}
|
||||
PRIVATE
|
||||
rt
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
if(NOT APPLE)
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||
rt
|
||||
)
|
||||
endif()
|
||||
|
||||
endif()
|
@ -18,12 +18,12 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
if(NOT APPLE)
|
||||
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
|
||||
rt
|
||||
)
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME} INTERFACE
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
endif()
|
||||
|
@ -87,7 +87,7 @@ void FixedTimeslotTask::missedDeadlineCounter() {
|
||||
FixedTimeslotTask::deadlineMissedCount++;
|
||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
|
||||
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ void FixedTimeslotTask::missedDeadlineCounter() {
|
||||
FixedTimeslotTask::deadlineMissedCount++;
|
||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
|
||||
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ class Fuse : public SystemObject,
|
||||
|
||||
ReturnValue_t check();
|
||||
uint8_t getFuseId() const;
|
||||
ReturnValue_t initialize();
|
||||
ReturnValue_t initialize() override;
|
||||
DeviceList devices;
|
||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const override;
|
||||
|
@ -43,7 +43,7 @@ class Service3Housekeeping : public CommandingServiceBase, public AcceptsHkPacke
|
||||
CommandMessage* optionalNextCommand, object_id_t objectId,
|
||||
bool* isStep) override;
|
||||
|
||||
virtual MessageQueueId_t getHkQueue() const;
|
||||
virtual MessageQueueId_t getHkQueue() const override;
|
||||
|
||||
private:
|
||||
enum class Subservice {
|
||||
|
@ -155,18 +155,18 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
|
||||
|
||||
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 isTableUsed(Mode_t tableId);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -137,9 +137,9 @@ class SubsystemBase : public SystemObject,
|
||||
|
||||
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();
|
||||
};
|
||||
|
@ -6,10 +6,6 @@
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
|
||||
CCSDSTime::CCSDSTime() {}
|
||||
|
||||
CCSDSTime::~CCSDSTime() {}
|
||||
|
||||
ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) {
|
||||
ReturnValue_t result = checkTimeOfDay(from);
|
||||
if (result != RETURN_OK) {
|
||||
@ -428,7 +424,7 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, const uint8_t* from, size_t
|
||||
from++;
|
||||
ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1);
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
if (foundLength != NULL) {
|
||||
if (foundLength != nullptr) {
|
||||
*foundLength += 1;
|
||||
}
|
||||
}
|
||||
@ -588,18 +584,18 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8
|
||||
uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1;
|
||||
uint8_t nFine = (pField & 0b11);
|
||||
size_t totalLength = nCoarse + nFine;
|
||||
if (foundLength != NULL) {
|
||||
if (foundLength != nullptr) {
|
||||
*foundLength = totalLength;
|
||||
}
|
||||
if (totalLength > maxLength) {
|
||||
return LENGTH_MISMATCH;
|
||||
}
|
||||
for (int count = 0; count < nCoarse; count++) {
|
||||
secs += *from << ((nCoarse * 8 - 8) * (1 + count));
|
||||
for (int count = nCoarse; count > 0; count--) {
|
||||
secs += *from << (count * 8 - 8);
|
||||
from++;
|
||||
}
|
||||
for (int count = 0; count < nFine; count++) {
|
||||
subSeconds += *from << ((nFine * 8 - 8) * (1 + count));
|
||||
for (int count = nFine; count > 0; count--) {
|
||||
subSeconds += *from << (count * 8 - 8);
|
||||
from++;
|
||||
}
|
||||
// Move to POSIX epoch.
|
||||
|
@ -161,18 +161,37 @@ class CCSDSTime : public HasReturnvaluesIF {
|
||||
*/
|
||||
static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength,
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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,
|
||||
size_t maxLength);
|
||||
|
||||
static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from,
|
||||
size_t *foundLength, size_t maxLength);
|
||||
|
||||
static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength,
|
||||
size_t maxLength);
|
||||
|
||||
static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from,
|
||||
size_t *foundLength, size_t maxLength);
|
||||
|
||||
@ -192,8 +211,8 @@ class CCSDSTime : public HasReturnvaluesIF {
|
||||
static uint32_t subsecondsToMicroseconds(uint16_t subseconds);
|
||||
|
||||
private:
|
||||
CCSDSTime();
|
||||
virtual ~CCSDSTime();
|
||||
CCSDSTime(){};
|
||||
virtual ~CCSDSTime(){};
|
||||
/**
|
||||
* checks a ccs time stream for validity
|
||||
*
|
||||
|
@ -1,8 +1,13 @@
|
||||
#include "fsfw/timemanager/Countdown.h"
|
||||
|
||||
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {
|
||||
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
|
||||
if (startImmediately) {
|
||||
setTimeout(initialTimeout);
|
||||
}
|
||||
else {
|
||||
timeout = initialTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
Countdown::~Countdown() {}
|
||||
|
||||
|
@ -26,8 +26,9 @@ class Countdown {
|
||||
* Otherwise a call to hasTimedOut might return True.
|
||||
*
|
||||
* @param initialTimeout Countdown duration in milliseconds
|
||||
* @param startImmediately Set to false if countdown should not be started immediately
|
||||
*/
|
||||
Countdown(uint32_t initialTimeout = 0);
|
||||
Countdown(uint32_t initialTimeout = 0, bool startImmediately = true);
|
||||
~Countdown();
|
||||
/**
|
||||
* Call to set a new countdown duration.
|
||||
|
@ -19,8 +19,8 @@ SpacePacket::SpacePacket(uint16_t packetDataLength, bool isTelecommand, uint16_t
|
||||
SpacePacket::~SpacePacket(void) {}
|
||||
|
||||
bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) {
|
||||
if (packet_size <= sizeof(this->data)) {
|
||||
memcpy(&this->localData.byteStream, p_Data, packet_size);
|
||||
if (packet_size <= sizeof(this->localData)) {
|
||||
memcpy(this->localData.byteStream, p_Data, packet_size);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -95,7 +95,7 @@ class CommandingServiceBase : public SystemObject,
|
||||
*/
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
virtual uint16_t getIdentifier();
|
||||
virtual uint16_t getIdentifier() override;
|
||||
|
||||
/**
|
||||
* Returns the requestQueue MessageQueueId_t
|
||||
@ -104,7 +104,7 @@ class CommandingServiceBase : public SystemObject,
|
||||
*
|
||||
* @return requestQueue messageQueueId_t
|
||||
*/
|
||||
virtual MessageQueueId_t getRequestQueue();
|
||||
virtual MessageQueueId_t getRequestQueue() override;
|
||||
|
||||
/**
|
||||
* Returns the commandQueue MessageQueueId_t
|
||||
|
@ -179,6 +179,27 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user