Compare commits
1 Commits
dba08fed7a
...
mueller/sp
Author | SHA1 | Date | |
---|---|---|---|
b9359ab75c |
83
CHANGELOG.md
83
CHANGELOG.md
@ -12,9 +12,6 @@ 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
|
||||||
@ -25,6 +22,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||||
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
||||||
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
||||||
|
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
||||||
- Major update for version handling, using `git describe` to fetch version information with git.
|
- Major update for version handling, using `git describe` to fetch version information with git.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601
|
||||||
- Place `Version` class outside of `fsfw` namespace. It is generic
|
- Place `Version` class outside of `fsfw` namespace. It is generic
|
||||||
@ -43,39 +42,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:
|
||||||
### HAL
|
- `timeval` to `TimeOfDay_t`
|
||||||
|
- Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/)
|
||||||
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
- Moved the statics used by Clock in ClockCommon.cpp to this file
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
- Better check for leap seconds
|
||||||
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
- Added Unittests for Clock (only getter)
|
||||||
and mode
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
|
||||||
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
|
|
||||||
name clashes with Windows defines.
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
|
||||||
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
|
||||||
|
|
||||||
### Time
|
|
||||||
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/584 and
|
|
||||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
|
||||||
|
|
||||||
- `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)
|
|
||||||
|
|
||||||
### Power
|
|
||||||
|
|
||||||
- `PowerSwitchIF`: Remove `const` specifier from `sendSwitchCommand` and `sendFuseOnCommand` and
|
|
||||||
also specify a `ReturnValue_t` return type
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
|
||||||
- Extend `PowerSwitcher` module to optionally check current state when calling `turnOn` or
|
|
||||||
`turnOff`. Tis can be helpful to avoid commanding switches which do not need commanding
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
|
||||||
|
|
||||||
## Removed
|
## Removed
|
||||||
|
|
||||||
@ -85,52 +57,15 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
|||||||
|
|
||||||
## Additions
|
## Additions
|
||||||
|
|
||||||
- LTO support: Allow using LTO/IPO by setting `FSFW_ENABLE_LTO=1`. CMake is able to detect whether
|
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
||||||
the user compiler supports IPO/LPO. LTO is on by default now. Most modern compilers support it,
|
|
||||||
can make good use of it and it usually makes the code faster and/or smaller.
|
|
||||||
After some more research:
|
|
||||||
Enabling LTO will actually cause the compiler to only produce thin LTO by adding
|
|
||||||
`-flto -fno-fat-lto-objects` to the compiler options. I am not sure this is an ideal choice
|
|
||||||
because if an application linking against the FSFW does not use LTO, there can be compile
|
|
||||||
issues (e.g. observed when compiling the FSFW tests without LTO). This is a known issue as
|
|
||||||
can be seen in the multiple CMake issues for it:
|
|
||||||
- https://gitlab.kitware.com/cmake/cmake/-/issues/22913,
|
|
||||||
- https://gitlab.kitware.com/cmake/cmake/-/issues/16808,
|
|
||||||
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
|
|
||||||
Easiest solution for now: Keep this option OFF by default.
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
|
|
||||||
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
||||||
inside `fsfw/version.h`
|
inside `fsfw/version.h`
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
||||||
- Added ETL dependency and improved library dependency management
|
- Added ETL dependency and improved library dependency management
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
||||||
- Add a `DummyPowerSwitcher` module which can be useful for test setups when no PCDU is available
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
|
||||||
- New typedef for switcher type
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
|
||||||
- `Subsystem`: New API to add table and sequence entries
|
|
||||||
|
|
||||||
## HAL
|
|
||||||
|
|
||||||
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
|
|
||||||
lot more sense because each ComIF should be responsible for one SPI bus.
|
|
||||||
- SPI: Move the empty transfer to update the line polarity to separate function. This means
|
|
||||||
it is not automatically called when calling the setter function for SPI speed and mode.
|
|
||||||
The user should call this function after locking the CS mutex if multiple SPI devices with
|
|
||||||
differing speeds and modes are attached to one bus.
|
|
||||||
- SPI: Getter functions for SPI speed and mode.
|
|
||||||
- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
|
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
- TCP TMTC Server: `MutexGuard` was not created properly in
|
|
||||||
`TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)` call.
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/618
|
|
||||||
- Fix infinite recursion in `prepareHealthSetReply` of PUS Health Service 201.
|
|
||||||
Is not currently used right now but might be used in the future
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/617
|
|
||||||
- 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
|
- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO
|
||||||
|
@ -2,13 +2,6 @@ cmake_minimum_required(VERSION 3.13)
|
|||||||
set(LIB_FSFW_NAME fsfw)
|
set(LIB_FSFW_NAME fsfw)
|
||||||
project(${LIB_FSFW_NAME})
|
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_IF_GIT_FAILS 4)
|
set(FSFW_VERSION_IF_GIT_FAILS 4)
|
||||||
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
||||||
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||||
@ -18,12 +11,11 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" )
|
|||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules")
|
||||||
set(MSG_PREFIX "fsfw |")
|
set(MSG_PREFIX "fsfw |")
|
||||||
|
|
||||||
set(FSFW_ETL_LIB_NAME etl)
|
|
||||||
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.3 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_ETL_LINK_TARGET etl::etl)
|
||||||
|
|
||||||
@ -34,28 +26,19 @@ set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5 CACHE
|
|||||||
"Catch2 library exact version requirement"
|
"Catch2 library exact version requirement"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Keep this off by default for now. See PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
|
set(FSFW_ETL_LIB_NAME etl)
|
||||||
# for information which keeping this on by default is problematic
|
|
||||||
option(FSFW_ENABLE_IPO "Enable interprocedural optimization or link-time optimization if available" OFF)
|
|
||||||
if(FSFW_ENABLE_IPO)
|
|
||||||
include(CheckIPOSupported)
|
|
||||||
check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_ERROR)
|
|
||||||
if(NOT IPO_SUPPORTED)
|
|
||||||
message(STATUS "FSFW | IPO/LTO not supported: ${IPO_ERROR}")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
option(FSFW_GENERATE_SECTIONS
|
option(FSFW_GENERATE_SECTIONS
|
||||||
"Generate function and data sections. Required to remove unused code" ON
|
"Generate function and data sections. Required to remove unused code" ON
|
||||||
)
|
)
|
||||||
if(FSFW_GENERATE_SECTIONS)
|
if(FSFW_GENERATE_SECTIONS)
|
||||||
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(FSFW_BUILD_UNITTESTS "Build unittest binary in addition to static library" OFF)
|
option(FSFW_BUILD_UNITTESTS "Build unittest binary in addition to static library" OFF)
|
||||||
option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
|
option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
|
||||||
if(FSFW_BUILD_UNITTESTS)
|
if(FSFW_BUILD_UNITTESTS)
|
||||||
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
|
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
||||||
@ -82,10 +65,6 @@ set(FSFW_DUMMY_TGT fsfw-dummy)
|
|||||||
|
|
||||||
add_library(${LIB_FSFW_NAME})
|
add_library(${LIB_FSFW_NAME})
|
||||||
|
|
||||||
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
|
||||||
set_property(TARGET ${LIB_FSFW_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
# Version handling
|
# Version handling
|
||||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
|
||||||
@ -142,9 +121,6 @@ if(FSFW_BUILD_UNITTESTS)
|
|||||||
|
|
||||||
project(${FSFW_TEST_TGT} CXX C)
|
project(${FSFW_TEST_TGT} CXX C)
|
||||||
add_executable(${FSFW_TEST_TGT})
|
add_executable(${FSFW_TEST_TGT})
|
||||||
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
|
||||||
set_property(TARGET ${FSFW_TEST_TGT} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(FSFW_TESTS_GEN_COV)
|
if(FSFW_TESTS_GEN_COV)
|
||||||
message(STATUS "${MSG_PREFIX} Generating coverage data for the library")
|
message(STATUS "${MSG_PREFIX} Generating coverage data for the library")
|
||||||
@ -202,6 +178,13 @@ 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 "${MSG_PREFIX} 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)
|
||||||
message(WARNING "${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
|
message(WARNING "${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
|
||||||
|
@ -32,8 +32,6 @@ ReturnValue_t CommandExecutor::execute() {
|
|||||||
} else if (state == States::PENDING) {
|
} else if (state == States::PENDING) {
|
||||||
return COMMAND_PENDING;
|
return COMMAND_PENDING;
|
||||||
}
|
}
|
||||||
// Reset data in read vector
|
|
||||||
std::memset(readVec.data(), 0, readVec.size());
|
|
||||||
currentCmdFile = popen(currentCmd.c_str(), "r");
|
currentCmdFile = popen(currentCmd.c_str(), "r");
|
||||||
if (currentCmdFile == nullptr) {
|
if (currentCmdFile == nullptr) {
|
||||||
lastError = errno;
|
lastError = errno;
|
||||||
@ -207,5 +205,3 @@ ReturnValue_t CommandExecutor::executeBlocking() {
|
|||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<char>& CommandExecutor::getReadVector() const { return readVec; }
|
|
||||||
|
@ -109,8 +109,6 @@ class CommandExecutor {
|
|||||||
*/
|
*/
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
const std::vector<char>& getReadVector() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string currentCmd;
|
std::string currentCmd;
|
||||||
bool blocking = true;
|
bool blocking = true;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include "fsfw/FSFW.h"
|
#include "fsfw/FSFW.h"
|
||||||
#include "fsfw/serviceinterface.h"
|
#include "fsfw/serviceinterface.h"
|
||||||
|
|
||||||
UnixFileGuard::UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
|
UnixFileGuard::UnixFileGuard(std::string device, int* fileDescriptor, int flags,
|
||||||
std::string diagnosticPrefix)
|
std::string diagnosticPrefix)
|
||||||
: fileDescriptor(fileDescriptor) {
|
: fileDescriptor(fileDescriptor) {
|
||||||
if (fileDescriptor == nullptr) {
|
if (fileDescriptor == nullptr) {
|
||||||
|
@ -15,7 +15,7 @@ class UnixFileGuard {
|
|||||||
|
|
||||||
static constexpr ReturnValue_t OPEN_FILE_FAILED = 1;
|
static constexpr ReturnValue_t OPEN_FILE_FAILED = 1;
|
||||||
|
|
||||||
UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
|
UnixFileGuard(std::string device, int* fileDescriptor, int flags,
|
||||||
std::string diagnosticPrefix = "");
|
std::string diagnosticPrefix = "");
|
||||||
|
|
||||||
virtual ~UnixFileGuard();
|
virtual ~UnixFileGuard();
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
#include "fsfw_hal/linux/spi/SpiCookie.h"
|
#include "fsfw_hal/linux/spi/SpiCookie.h"
|
||||||
#include "fsfw_hal/linux/utility.h"
|
#include "fsfw_hal/linux/utility.h"
|
||||||
|
|
||||||
SpiComIF::SpiComIF(object_id_t objectId, std::string devname, GpioIF* gpioComIF)
|
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF)
|
||||||
: SystemObject(objectId), gpioComIF(gpioComIF), dev(std::move(devname)) {
|
: SystemObject(objectId), gpioComIF(gpioComIF) {
|
||||||
if (gpioComIF == nullptr) {
|
if (gpioComIF == nullptr) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -27,7 +27,7 @@ SpiComIF::SpiComIF(object_id_t objectId, std::string devname, GpioIF* gpioComIF)
|
|||||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
csMutex = MutexFactory::instance()->createMutex();
|
spiMutex = MutexFactory::instance()->createMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
||||||
@ -85,7 +85,8 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
|||||||
spiCookie->getSpiParameters(spiMode, spiSpeed, ¶ms);
|
spiCookie->getSpiParameters(spiMode, spiSpeed, ¶ms);
|
||||||
|
|
||||||
int fileDescriptor = 0;
|
int fileDescriptor = 0;
|
||||||
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::initializeInterface");
|
UnixFileGuard fileHelper(spiCookie->getSpiDevice(), &fileDescriptor, O_RDWR,
|
||||||
|
"SpiComIF::initializeInterface");
|
||||||
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return fileHelper.getOpenResult();
|
return fileHelper.getOpenResult();
|
||||||
}
|
}
|
||||||
@ -173,6 +174,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
|||||||
size_t sendLen) {
|
size_t sendLen) {
|
||||||
address_t spiAddress = spiCookie->getSpiAddress();
|
address_t spiAddress = spiCookie->getSpiAddress();
|
||||||
auto iter = spiDeviceMap.find(spiAddress);
|
auto iter = spiDeviceMap.find(spiAddress);
|
||||||
|
std::memset(iter->second.replyBuffer.data(), 0, sendLen);
|
||||||
if (iter != spiDeviceMap.end()) {
|
if (iter != spiDeviceMap.end()) {
|
||||||
spiCookie->assignReadBuffer(iter->second.replyBuffer.data());
|
spiCookie->assignReadBuffer(iter->second.replyBuffer.data());
|
||||||
}
|
}
|
||||||
@ -181,7 +183,8 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
|||||||
int retval = 0;
|
int retval = 0;
|
||||||
/* Prepare transfer */
|
/* Prepare transfer */
|
||||||
int fileDescriptor = 0;
|
int fileDescriptor = 0;
|
||||||
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
|
std::string device = spiCookie->getSpiDevice();
|
||||||
|
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
|
||||||
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return OPENING_FILE_FAILED;
|
return OPENING_FILE_FAILED;
|
||||||
}
|
}
|
||||||
@ -197,7 +200,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
|||||||
|
|
||||||
/* Pull SPI CS low. For now, no support for active high given */
|
/* Pull SPI CS low. For now, no support for active high given */
|
||||||
if (gpioId != gpio::NO_GPIO) {
|
if (gpioId != gpio::NO_GPIO) {
|
||||||
result = csMutex->lockMutex(timeoutType, timeoutMs);
|
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -208,7 +211,6 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
|||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
updateLinePolarity(fileDescriptor);
|
|
||||||
ReturnValue_t result = gpioComIF->pullLow(gpioId);
|
ReturnValue_t result = gpioComIF->pullLow(gpioId);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
@ -220,8 +222,6 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
|||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
updateLinePolarity(fileDescriptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Execute transfer */
|
/* Execute transfer */
|
||||||
@ -251,7 +251,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
|||||||
|
|
||||||
if (gpioId != gpio::NO_GPIO) {
|
if (gpioId != gpio::NO_GPIO) {
|
||||||
gpioComIF->pullHigh(gpioId);
|
gpioComIF->pullHigh(gpioId);
|
||||||
result = csMutex->unlockMutex();
|
result = spiMutex->unlockMutex();
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl;
|
sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl;
|
||||||
@ -279,8 +279,9 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
|
|||||||
|
|
||||||
ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||||
|
std::string device = spiCookie->getSpiDevice();
|
||||||
int fileDescriptor = 0;
|
int fileDescriptor = 0;
|
||||||
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
|
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
|
||||||
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return OPENING_FILE_FAILED;
|
return OPENING_FILE_FAILED;
|
||||||
}
|
}
|
||||||
@ -294,7 +295,7 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
|||||||
|
|
||||||
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
||||||
if (gpioId != gpio::NO_GPIO) {
|
if (gpioId != gpio::NO_GPIO) {
|
||||||
result = csMutex->lockMutex(timeoutType, timeoutMs);
|
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl;
|
sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl;
|
||||||
@ -317,7 +318,7 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
|||||||
|
|
||||||
if (gpioId != gpio::NO_GPIO) {
|
if (gpioId != gpio::NO_GPIO) {
|
||||||
gpioComIF->pullHigh(gpioId);
|
gpioComIF->pullHigh(gpioId);
|
||||||
result = csMutex->unlockMutex();
|
result = spiMutex->unlockMutex();
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "SpiComIF::getSendSuccess: Failed to unlock mutex" << std::endl;
|
sif::error << "SpiComIF::getSendSuccess: Failed to unlock mutex" << std::endl;
|
||||||
@ -353,7 +354,7 @@ MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeout
|
|||||||
if (timeoutMs != nullptr) {
|
if (timeoutMs != nullptr) {
|
||||||
*timeoutMs = this->timeoutMs;
|
*timeoutMs = this->timeoutMs;
|
||||||
}
|
}
|
||||||
return csMutex;
|
return spiMutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
|
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
|
||||||
@ -401,33 +402,12 @@ void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed)
|
|||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
|
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
|
||||||
}
|
}
|
||||||
}
|
// This updates the SPI clock default polarity. Only setting the mode does not update
|
||||||
|
// the line state, which can be an issue on mode switches because the clock line will
|
||||||
void SpiComIF::getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const {
|
// switch the state after the chip select is pulled low
|
||||||
uint8_t tmpMode = 0;
|
|
||||||
int retval = ioctl(spiFd, SPI_IOC_RD_MODE, &tmpMode);
|
|
||||||
if (retval != 0) {
|
|
||||||
utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Reading SPI mode failed");
|
|
||||||
}
|
|
||||||
mode = static_cast<spi::SpiModes>(tmpMode);
|
|
||||||
|
|
||||||
retval = ioctl(spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
|
|
||||||
if (retval != 0) {
|
|
||||||
utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Getting SPI speed failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& SpiComIF::getSpiDev() const { return dev; }
|
|
||||||
|
|
||||||
void SpiComIF::updateLinePolarity(int spiFd) {
|
|
||||||
clockUpdateTransfer.len = 0;
|
clockUpdateTransfer.len = 0;
|
||||||
int retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
|
retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Updating SPI default clock failed");
|
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Updating SPI default clock failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiComIF::setMutexParams(MutexIF::TimeoutType timeoutType_, uint32_t timeoutMs_) {
|
|
||||||
timeoutType = timeoutType_;
|
|
||||||
timeoutMs = timeoutMs_;
|
|
||||||
}
|
|
||||||
|
@ -22,19 +22,17 @@ class SpiCookie;
|
|||||||
*/
|
*/
|
||||||
class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||||
public:
|
public:
|
||||||
static constexpr dur_millis_t DEFAULT_MUTEX_TIMEOUT = 20;
|
static constexpr uint8_t spiRetvalId = CLASS_ID::HAL_SPI;
|
||||||
|
|
||||||
static constexpr uint8_t CLASS_ID = CLASS_ID::HAL_SPI;
|
|
||||||
static constexpr ReturnValue_t OPENING_FILE_FAILED =
|
static constexpr ReturnValue_t OPENING_FILE_FAILED =
|
||||||
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 0);
|
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 0);
|
||||||
/* Full duplex (ioctl) transfer failure */
|
/* Full duplex (ioctl) transfer failure */
|
||||||
static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED =
|
static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED =
|
||||||
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1);
|
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 1);
|
||||||
/* Half duplex (read/write) transfer failure */
|
/* Half duplex (read/write) transfer failure */
|
||||||
static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED =
|
static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED =
|
||||||
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2);
|
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 2);
|
||||||
|
|
||||||
SpiComIF(object_id_t objectId, std::string devname, GpioIF* gpioComIF);
|
SpiComIF(object_id_t objectId, GpioIF* gpioComIF);
|
||||||
|
|
||||||
ReturnValue_t initializeInterface(CookieIF* cookie) override;
|
ReturnValue_t initializeInterface(CookieIF* cookie) override;
|
||||||
ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override;
|
ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override;
|
||||||
@ -47,7 +45,6 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
|||||||
* the chip select must be driven from outside of the com if.
|
* the chip select must be driven from outside of the com if.
|
||||||
*/
|
*/
|
||||||
MutexIF* getMutex(MutexIF::TimeoutType* timeoutType = nullptr, uint32_t* timeoutMs = nullptr);
|
MutexIF* getMutex(MutexIF::TimeoutType* timeoutType = nullptr, uint32_t* timeoutMs = nullptr);
|
||||||
void setMutexParams(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a regular send operation using Linux iotcl. This is public so it can be used
|
* Perform a regular send operation using Linux iotcl. This is public so it can be used
|
||||||
@ -62,20 +59,6 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
|||||||
|
|
||||||
GpioIF* getGpioInterface();
|
GpioIF* getGpioInterface();
|
||||||
void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);
|
void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);
|
||||||
void getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This updates the SPI clock default polarity. Only setting the mode does not update
|
|
||||||
* the line state, which can be an issue on mode switches because the clock line will
|
|
||||||
* switch the state after the chip select is pulled low.
|
|
||||||
*
|
|
||||||
* It is recommended to call this function after #setSpiSpeedAndMode and after locking the
|
|
||||||
* CS mutex if the SPI bus has multiple SPI devices with different speed and SPI modes attached.
|
|
||||||
* @param spiFd
|
|
||||||
*/
|
|
||||||
void updateLinePolarity(int spiFd);
|
|
||||||
|
|
||||||
const std::string& getSpiDev() const;
|
|
||||||
void performSpiWiretapping(SpiCookie* spiCookie);
|
void performSpiWiretapping(SpiCookie* spiCookie);
|
||||||
|
|
||||||
ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer);
|
ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer);
|
||||||
@ -87,14 +70,10 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
|||||||
};
|
};
|
||||||
|
|
||||||
GpioIF* gpioComIF = nullptr;
|
GpioIF* gpioComIF = nullptr;
|
||||||
std::string dev = "";
|
|
||||||
/**
|
MutexIF* spiMutex = nullptr;
|
||||||
* Protects the chip select operations. Lock when GPIO is pulled low, unlock after it was
|
|
||||||
* pulled high
|
|
||||||
*/
|
|
||||||
MutexIF* csMutex = nullptr;
|
|
||||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||||
uint32_t timeoutMs = DEFAULT_MUTEX_TIMEOUT;
|
uint32_t timeoutMs = 20;
|
||||||
spi_ioc_transfer clockUpdateTransfer = {};
|
spi_ioc_transfer clockUpdateTransfer = {};
|
||||||
|
|
||||||
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;
|
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;
|
||||||
|
@ -1,25 +1,26 @@
|
|||||||
#include "SpiCookie.h"
|
#include "SpiCookie.h"
|
||||||
|
|
||||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize,
|
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||||
|
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)
|
||||||
|
: SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, spiDev, maxSize, spiMode,
|
||||||
|
spiSpeed, nullptr, nullptr) {}
|
||||||
|
|
||||||
|
SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize,
|
||||||
spi::SpiModes spiMode, uint32_t spiSpeed)
|
spi::SpiModes spiMode, uint32_t spiSpeed)
|
||||||
: SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
|
: SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) {}
|
||||||
nullptr, nullptr) {}
|
|
||||||
|
|
||||||
SpiCookie::SpiCookie(address_t spiAddress, const size_t maxSize, spi::SpiModes spiMode,
|
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||||
uint32_t spiSpeed)
|
|
||||||
: SpiCookie(spiAddress, gpio::NO_GPIO, maxSize, spiMode, spiSpeed) {}
|
|
||||||
|
|
||||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize,
|
|
||||||
spi::SpiModes spiMode, uint32_t spiSpeed,
|
|
||||||
spi::send_callback_function_t callback, void* args)
|
|
||||||
: SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
|
|
||||||
callback, args) {}
|
|
||||||
|
|
||||||
SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
|
||||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||||
spi::send_callback_function_t callback, void* args)
|
spi::send_callback_function_t callback, void* args)
|
||||||
|
: SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize, spiMode,
|
||||||
|
spiSpeed, callback, args) {}
|
||||||
|
|
||||||
|
SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
||||||
|
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode,
|
||||||
|
uint32_t spiSpeed, spi::send_callback_function_t callback, void* args)
|
||||||
: spiAddress(spiAddress),
|
: spiAddress(spiAddress),
|
||||||
chipSelectPin(chipSelect),
|
chipSelectPin(chipSelect),
|
||||||
|
spiDevice(spiDev),
|
||||||
comIfMode(comIfMode),
|
comIfMode(comIfMode),
|
||||||
maxSize(maxSize),
|
maxSize(maxSize),
|
||||||
spiMode(spiMode),
|
spiMode(spiMode),
|
||||||
@ -49,6 +50,8 @@ size_t SpiCookie::getMaxBufferSize() const { return maxSize; }
|
|||||||
|
|
||||||
address_t SpiCookie::getSpiAddress() const { return spiAddress; }
|
address_t SpiCookie::getSpiAddress() const { return spiAddress; }
|
||||||
|
|
||||||
|
std::string SpiCookie::getSpiDevice() const { return spiDevice; }
|
||||||
|
|
||||||
void SpiCookie::setThreeWireSpi(bool enable) { uncommonParameters.threeWireSpi = enable; }
|
void SpiCookie::setThreeWireSpi(bool enable) { uncommonParameters.threeWireSpi = enable; }
|
||||||
|
|
||||||
void SpiCookie::setLsbFirst(bool enable) { uncommonParameters.lsbFirst = enable; }
|
void SpiCookie::setLsbFirst(bool enable) { uncommonParameters.lsbFirst = enable; }
|
||||||
|
@ -29,22 +29,23 @@ class SpiCookie : public CookieIF {
|
|||||||
* @param spiDev
|
* @param spiDev
|
||||||
* @param maxSize
|
* @param maxSize
|
||||||
*/
|
*/
|
||||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
|
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
|
||||||
uint32_t spiSpeed);
|
spi::SpiModes spiMode, uint32_t spiSpeed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like constructor above, but without a dedicated GPIO CS. Can be used for hardware
|
* Like constructor above, but without a dedicated GPIO CS. Can be used for hardware
|
||||||
* slave select or if CS logic is performed with decoders.
|
* slave select or if CS logic is performed with decoders.
|
||||||
*/
|
*/
|
||||||
SpiCookie(address_t spiAddress, const size_t maxReplySize, spi::SpiModes spiMode,
|
SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxReplySize,
|
||||||
uint32_t spiSpeed);
|
spi::SpiModes spiMode, uint32_t spiSpeed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the callback mode of the SPI communication interface. The user can pass the callback
|
* Use the callback mode of the SPI communication interface. The user can pass the callback
|
||||||
* function here or by using the setter function #setCallbackMode
|
* function here or by using the setter function #setCallbackMode
|
||||||
*/
|
*/
|
||||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
|
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
|
||||||
uint32_t spiSpeed, spi::send_callback_function_t callback, void* args);
|
spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback,
|
||||||
|
void* args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the callback function
|
* Get the callback function
|
||||||
@ -54,6 +55,7 @@ class SpiCookie : public CookieIF {
|
|||||||
void getCallback(spi::send_callback_function_t* callback, void** args);
|
void getCallback(spi::send_callback_function_t* callback, void** args);
|
||||||
|
|
||||||
address_t getSpiAddress() const;
|
address_t getSpiAddress() const;
|
||||||
|
std::string getSpiDevice() const;
|
||||||
gpioId_t getChipSelectPin() const;
|
gpioId_t getChipSelectPin() const;
|
||||||
size_t getMaxBufferSize() const;
|
size_t getMaxBufferSize() const;
|
||||||
|
|
||||||
@ -152,11 +154,12 @@ class SpiCookie : public CookieIF {
|
|||||||
* @param args
|
* @param args
|
||||||
*/
|
*/
|
||||||
SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
||||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||||
spi::send_callback_function_t callback, void* args);
|
spi::send_callback_function_t callback, void* args);
|
||||||
|
|
||||||
address_t spiAddress;
|
address_t spiAddress;
|
||||||
gpioId_t chipSelectPin;
|
gpioId_t chipSelectPin;
|
||||||
|
std::string spiDevice;
|
||||||
|
|
||||||
spi::SpiComIfModes comIfMode;
|
spi::SpiComIfModes comIfMode;
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#define FIXEDARRAYLIST_H_
|
#define FIXEDARRAYLIST_H_
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include "ArrayList.h"
|
#include "ArrayList.h"
|
||||||
/**
|
/**
|
||||||
@ -10,9 +9,10 @@
|
|||||||
*/
|
*/
|
||||||
template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
||||||
class FixedArrayList : public ArrayList<T, count_t> {
|
class FixedArrayList : public ArrayList<T, count_t> {
|
||||||
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
#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");
|
"count_t is not large enough to hold MAX_SIZE");
|
||||||
|
#endif
|
||||||
private:
|
private:
|
||||||
T data[MAX_SIZE];
|
T data[MAX_SIZE];
|
||||||
|
|
||||||
|
@ -1401,7 +1401,8 @@ uint8_t DeviceHandlerBase::getReplyDelayCycles(DeviceCommandId_t deviceCommand)
|
|||||||
DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand);
|
DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand);
|
||||||
if (iter == deviceReplyMap.end()) {
|
if (iter == deviceReplyMap.end()) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (iter->second.countdown != nullptr) {
|
}
|
||||||
|
else if (iter->second.countdown != nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return iter->second.delayCycles;
|
return iter->second.delayCycles;
|
||||||
|
@ -467,14 +467,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* @brief This is a helper method to insert replies in the reply map.
|
* @brief This is a helper method to insert replies in the reply map.
|
||||||
* @param deviceCommand Identifier of the reply to add.
|
* @param deviceCommand Identifier of the reply to add.
|
||||||
* @param maxDelayCycles The maximum number of delay cycles the reply waits
|
* @param maxDelayCycles The maximum number of delay cycles the reply waits
|
||||||
* until it times out.
|
* until it times out.
|
||||||
* @param periodic Indicates if the command is periodic (i.e. it is sent
|
* @param periodic Indicates if the command is periodic (i.e. it is sent
|
||||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
* 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
|
* Please note that periodic replies are disabled by default. You can enable them with
|
||||||
* #updatePeriodicReply
|
* #updatePeriodicReply
|
||||||
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
* @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
|
* to provide a pointer to a Countdown object which will signal the timeout
|
||||||
* when expired
|
* when expired
|
||||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||||
* - @c RETURN_FAILED else.
|
* - @c RETURN_FAILED else.
|
||||||
*/
|
*/
|
||||||
@ -783,18 +783,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* This is used to keep track of pending replies.
|
* This is used to keep track of pending replies.
|
||||||
*/
|
*/
|
||||||
struct DeviceReplyInfo {
|
struct DeviceReplyInfo {
|
||||||
//! For Command-Reply combinations:
|
|
||||||
//! The maximum number of cycles the handler should wait for a reply
|
//! The maximum number of cycles the handler should wait for a reply
|
||||||
//! to this command.
|
//! to this command.
|
||||||
//!
|
|
||||||
//! Reply Only:
|
|
||||||
//! For periodic replies, this variable will be the number of delay cycles between the replies.
|
|
||||||
//! For the non-periodic variant, this variable is not used as there is no meaningful
|
|
||||||
//! definition for delay
|
|
||||||
uint16_t maxDelayCycles;
|
uint16_t maxDelayCycles;
|
||||||
//! This variable will be set to #maxDelayCycles if a reply is expected.
|
//! The currently remaining cycles the handler should wait for a reply,
|
||||||
//! For non-periodic replies without a command, this variable is unused.
|
//! 0 means there is no reply expected
|
||||||
//! A runtime value of 0 means there is no reply is currently expected.
|
|
||||||
uint16_t delayCycles;
|
uint16_t delayCycles;
|
||||||
size_t replyLen = 0; //!< Expected size of the reply.
|
size_t replyLen = 0; //!< Expected size of the reply.
|
||||||
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
||||||
@ -808,7 +801,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
DeviceCommandMap::iterator command;
|
DeviceCommandMap::iterator command;
|
||||||
//! Instead of using delayCycles to specify the maximum time to wait for the device reply, it
|
//! Instead of using delayCycles to specify the maximum time to wait for the device reply, it
|
||||||
//! is also possible specify a countdown
|
//! is also possible specify a countdown
|
||||||
Countdown *countdown = nullptr;
|
Countdown* countdown = nullptr;
|
||||||
//! will be set to true when reply is enabled
|
//! will be set to true when reply is enabled
|
||||||
bool active = false;
|
bool active = false;
|
||||||
};
|
};
|
||||||
@ -1276,13 +1269,13 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
/**
|
/**
|
||||||
* @brief Handles disabling of replies which use a timeout to detect missed replies.
|
* @brief Handles disabling of replies which use a timeout to detect missed replies.
|
||||||
*/
|
*/
|
||||||
void disableTimeoutControlledReply(DeviceReplyInfo *info);
|
void disableTimeoutControlledReply(DeviceReplyInfo* info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handles disabling of replies which use a number of maximum delay cycles to detect
|
* @brief Handles disabling of replies which use a number of maximum delay cycles to detect
|
||||||
* missed replies.
|
* missed replies.
|
||||||
*/
|
*/
|
||||||
void disableDelayCyclesControlledReply(DeviceReplyInfo *info);
|
void disableDelayCyclesControlledReply(DeviceReplyInfo* info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrive data from the #IPCStore.
|
* Retrive data from the #IPCStore.
|
||||||
|
@ -16,15 +16,10 @@ class HasHealthIF {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
||||||
static constexpr ReturnValue_t OBJECT_NOT_HEALTHY =
|
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
|
||||||
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1);
|
static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2);
|
||||||
static constexpr ReturnValue_t INVALID_HEALTH_STATE =
|
|
||||||
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 2);
|
|
||||||
static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED =
|
|
||||||
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 3);
|
|
||||||
|
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
|
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
|
||||||
//! P1: New Health, P2: Old Health
|
|
||||||
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
|
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
|
||||||
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
|
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
|
||||||
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
|
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
|
||||||
|
@ -19,8 +19,6 @@
|
|||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||||
@ -31,7 +29,7 @@ TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
|||||||
: SystemObject(objectId),
|
: SystemObject(objectId),
|
||||||
tmtcBridgeId(tmtcTcpBridge),
|
tmtcBridgeId(tmtcTcpBridge),
|
||||||
receptionMode(receptionMode),
|
receptionMode(receptionMode),
|
||||||
tcpConfig(std::move(customTcpServerPort)),
|
tcpConfig(customTcpServerPort),
|
||||||
receptionBuffer(receptionBufferSize),
|
receptionBuffer(receptionBufferSize),
|
||||||
ringBuffer(ringBufferSize, true) {}
|
ringBuffer(ringBufferSize, true) {}
|
||||||
|
|
||||||
@ -105,7 +103,7 @@ ReturnValue_t TcpTmTcServer::initialize() {
|
|||||||
|
|
||||||
TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
||||||
|
|
||||||
[[noreturn]] ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
||||||
using namespace tcpip;
|
using namespace tcpip;
|
||||||
// If a connection is accepted, the corresponding socket will be assigned to the new socket
|
// If a connection is accepted, the corresponding socket will be assigned to the new socket
|
||||||
socket_t connSocket = 0;
|
socket_t connSocket = 0;
|
||||||
@ -140,6 +138,7 @@ TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
|||||||
closeSocket(connSocket);
|
closeSocket(connSocket);
|
||||||
connSocket = 0;
|
connSocket = 0;
|
||||||
}
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
|
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
|
||||||
@ -160,8 +159,8 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ssize_t retval = recv(connSocket, reinterpret_cast<char*>(receptionBuffer.data()),
|
int retval = recv(connSocket, reinterpret_cast<char*>(receptionBuffer.data()),
|
||||||
receptionBuffer.capacity(), tcpConfig.tcpFlags);
|
receptionBuffer.capacity(), tcpConfig.tcpFlags);
|
||||||
if (retval == 0) {
|
if (retval == 0) {
|
||||||
size_t availableReadData = ringBuffer.getAvailableReadData();
|
size_t availableReadData = ringBuffer.getAvailableReadData();
|
||||||
if (availableReadData > lastRingBufferSize) {
|
if (availableReadData > lastRingBufferSize) {
|
||||||
@ -253,17 +252,17 @@ ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t pack
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; }
|
std::string TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; }
|
||||||
|
|
||||||
void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds_) {
|
void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds) {
|
||||||
this->validPacketIds = std::move(validPacketIds_);
|
this->validPacketIds = validPacketIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; }
|
TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; }
|
||||||
|
|
||||||
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) {
|
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) {
|
||||||
// Access to the FIFO is mutex protected because it is filled by the bridge
|
// Access to the FIFO is mutex protected because it is filled by the bridge
|
||||||
MutexGuard mg(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
|
MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
while ((not tmtcBridge->tmFifo->empty()) and
|
while ((not tmtcBridge->tmFifo->empty()) and
|
||||||
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
|
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
|
||||||
@ -284,8 +283,8 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)
|
|||||||
#endif
|
#endif
|
||||||
arrayprinter::print(storeAccessor.data(), storeAccessor.size());
|
arrayprinter::print(storeAccessor.data(), storeAccessor.size());
|
||||||
}
|
}
|
||||||
ssize_t retval = send(connSocket, reinterpret_cast<const char*>(storeAccessor.data()),
|
int retval = send(connSocket, reinterpret_cast<const char*>(storeAccessor.data()),
|
||||||
storeAccessor.size(), tcpConfig.tcpTmFlags);
|
storeAccessor.size(), tcpConfig.tcpTmFlags);
|
||||||
if (retval == static_cast<int>(storeAccessor.size())) {
|
if (retval == static_cast<int>(storeAccessor.size())) {
|
||||||
// Packet sent, clear FIFO entry
|
// Packet sent, clear FIFO entry
|
||||||
tmtcBridge->tmFifo->pop();
|
tmtcBridge->tmFifo->pop();
|
||||||
@ -340,9 +339,6 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) {
|
|||||||
size_t foundSize = 0;
|
size_t foundSize = 0;
|
||||||
size_t readLen = 0;
|
size_t readLen = 0;
|
||||||
while (readLen < readAmount) {
|
while (readLen < readAmount) {
|
||||||
if (spacePacketParser == nullptr) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
result =
|
result =
|
||||||
spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen);
|
spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class TcpTmTcBridge;
|
class TcpTmTcBridge;
|
||||||
@ -45,7 +44,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
|
|
||||||
struct TcpConfig {
|
struct TcpConfig {
|
||||||
public:
|
public:
|
||||||
explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
|
TcpConfig(std::string tcpPort) : tcpPort(tcpPort) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passed to the recv call
|
* Passed to the recv call
|
||||||
@ -85,7 +84,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
size_t ringBufferSize = RING_BUFFER_SIZE,
|
size_t ringBufferSize = RING_BUFFER_SIZE,
|
||||||
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
||||||
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
||||||
~TcpTmTcServer() override;
|
virtual ~TcpTmTcServer();
|
||||||
|
|
||||||
void enableWiretapping(bool enable);
|
void enableWiretapping(bool enable);
|
||||||
|
|
||||||
@ -98,10 +97,10 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
void setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds);
|
void setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds);
|
||||||
|
|
||||||
ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
[[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
ReturnValue_t initializeAfterTaskCreation() override;
|
ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
|
|
||||||
[[nodiscard]] const std::string& getTcpPort() const;
|
std::string getTcpPort() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StorageManagerIF* tcStore = nullptr;
|
StorageManagerIF* tcStore = nullptr;
|
||||||
@ -116,7 +115,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
|
|
||||||
ReceptionModes receptionMode;
|
ReceptionModes receptionMode;
|
||||||
TcpConfig tcpConfig;
|
TcpConfig tcpConfig;
|
||||||
struct sockaddr tcpAddress = {};
|
struct sockaddr tcpAddress;
|
||||||
socket_t listenerTcpSocket = 0;
|
socket_t listenerTcpSocket = 0;
|
||||||
|
|
||||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||||
|
@ -47,7 +47,7 @@ void FixedTimeslotTask::missedDeadlineCounter() {
|
|||||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,6 @@ FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, size_t st
|
|||||||
|
|
||||||
FixedTimeslotTask::~FixedTimeslotTask() {}
|
FixedTimeslotTask::~FixedTimeslotTask() {}
|
||||||
|
|
||||||
bool FixedTimeslotTask::isEmpty() const { return pst.isEmpty(); }
|
|
||||||
|
|
||||||
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
||||||
// The argument is re-interpreted as PollingTask.
|
// The argument is re-interpreted as PollingTask.
|
||||||
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
|
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
|
||||||
@ -52,7 +50,7 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotT
|
|||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::checkSequence() { return pst.checkSequence(); }
|
ReturnValue_t FixedTimeslotTask::checkSequence() const { return pst.checkSequence(); }
|
||||||
|
|
||||||
void FixedTimeslotTask::taskFunctionality() {
|
void FixedTimeslotTask::taskFunctionality() {
|
||||||
// Like FreeRTOS pthreads are running as soon as they are created
|
// Like FreeRTOS pthreads are running as soon as they are created
|
||||||
@ -90,7 +88,7 @@ void FixedTimeslotTask::missedDeadlineCounter() {
|
|||||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,18 +24,15 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
|
|||||||
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_);
|
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_);
|
||||||
virtual ~FixedTimeslotTask();
|
virtual ~FixedTimeslotTask();
|
||||||
|
|
||||||
ReturnValue_t startTask() override;
|
virtual ReturnValue_t startTask();
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
virtual ReturnValue_t sleepFor(uint32_t ms);
|
||||||
|
|
||||||
uint32_t getPeriodMs() const override;
|
virtual uint32_t getPeriodMs() const;
|
||||||
|
|
||||||
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
|
||||||
int8_t executionStep) override;
|
|
||||||
|
|
||||||
ReturnValue_t checkSequence() override;
|
virtual ReturnValue_t checkSequence() const;
|
||||||
|
|
||||||
bool isEmpty() const override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This static function can be used as #deadlineMissedFunc.
|
* This static function can be used as #deadlineMissedFunc.
|
||||||
|
@ -26,12 +26,12 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object, uint8_t opCode) {
|
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||||
return addComponent(newObject, opCode);
|
return addComponent(newObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::addComponent(ExecutableObjectIF* object, uint8_t opCode) {
|
ReturnValue_t PeriodicPosixTask::addComponent(ExecutableObjectIF* object) {
|
||||||
if (object == nullptr) {
|
if (object == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
||||||
@ -43,7 +43,7 @@ ReturnValue_t PeriodicPosixTask::addComponent(ExecutableObjectIF* object, uint8_
|
|||||||
#endif
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
objectList.emplace(object, opCode);
|
objectList.push_back(object);
|
||||||
object->setTaskIF(this);
|
object->setTaskIF(this);
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
@ -54,9 +54,6 @@ ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::startTask(void) {
|
ReturnValue_t PeriodicPosixTask::startTask(void) {
|
||||||
if (isEmpty()) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
started = true;
|
started = true;
|
||||||
PosixThread::createTask(&taskEntryPoint, this);
|
PosixThread::createTask(&taskEntryPoint, this);
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
@ -67,13 +64,15 @@ void PeriodicPosixTask::taskFunctionality(void) {
|
|||||||
suspend();
|
suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
initObjsAfterTaskCreation();
|
for (auto const& object : objectList) {
|
||||||
|
object->initializeAfterTaskCreation();
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
|
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
|
||||||
// The task's "infinite" inner loop is entered.
|
// The task's "infinite" inner loop is entered.
|
||||||
while (1) {
|
while (1) {
|
||||||
for (auto const& objOpCodePair : objectList) {
|
for (auto const& object : objectList) {
|
||||||
objOpCodePair.first->performOperation(objOpCodePair.second);
|
object->performOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) {
|
if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) {
|
||||||
@ -85,25 +84,3 @@ void PeriodicPosixTask::taskFunctionality(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PeriodicPosixTask::getPeriodMs() const { return periodMs; }
|
uint32_t PeriodicPosixTask::getPeriodMs() const { return periodMs; }
|
||||||
|
|
||||||
bool PeriodicPosixTask::isEmpty() const { return objectList.empty(); }
|
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::initObjsAfterTaskCreation() {
|
|
||||||
std::multiset<ExecutableObjectIF*> uniqueObjects;
|
|
||||||
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
|
|
||||||
uint32_t count = 0;
|
|
||||||
for (const auto& obj : objectList) {
|
|
||||||
// Ensure that each unique object is initialized once.
|
|
||||||
if (uniqueObjects.find(obj.first) == uniqueObjects.end()) {
|
|
||||||
ReturnValue_t result = obj.first->initializeAfterTaskCreation();
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
count++;
|
|
||||||
status = result;
|
|
||||||
}
|
|
||||||
uniqueObjects.emplace(obj.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count > 0) {
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
|
#ifndef FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
|
||||||
#define FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
|
#define FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
|
||||||
|
|
||||||
#include <set>
|
#include <vector>
|
||||||
|
|
||||||
#include "../../objectmanager/ObjectManagerIF.h"
|
#include "../../objectmanager/ObjectManagerIF.h"
|
||||||
#include "../../tasks/ExecutableObjectIF.h"
|
#include "../../tasks/ExecutableObjectIF.h"
|
||||||
@ -40,7 +40,7 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* @param object Id of the object to add.
|
* @param object Id of 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(object_id_t object, uint8_t opCode) 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.
|
||||||
@ -48,20 +48,14 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* @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, uint8_t opCode) override;
|
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
|
||||||
|
|
||||||
uint32_t getPeriodMs() const override;
|
uint32_t getPeriodMs() const override;
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
|
||||||
ReturnValue_t initObjsAfterTaskCreation();
|
|
||||||
|
|
||||||
bool isEmpty() const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Typedef for the List of objects. Will contain the objects to execute and their respective
|
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.
|
||||||
//! op codes
|
|
||||||
using ObjectList = std::multiset<std::pair<ExecutableObjectIF*, uint8_t>>;
|
|
||||||
/**
|
/**
|
||||||
* @brief This attribute holds a list of objects to be executed.
|
* @brief This attribute holds a list of objects to be executed.
|
||||||
*/
|
*/
|
||||||
|
@ -51,7 +51,7 @@ void FixedTimeslotTask::missedDeadlineCounter() {
|
|||||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
#include "DummyPowerSwitcher.h"
|
#include "DummyPowerSwitcher.h"
|
||||||
|
|
||||||
DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches,
|
DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches,
|
||||||
size_t numberOfFuses, bool registerGlobally,
|
size_t numberOfFuses, uint32_t switchDelayMs)
|
||||||
uint32_t switchDelayMs)
|
: SystemObject(objectId),
|
||||||
: SystemObject(objectId, registerGlobally),
|
|
||||||
switcherList(numberOfSwitches),
|
switcherList(numberOfSwitches),
|
||||||
fuseList(numberOfFuses),
|
fuseList(numberOfFuses),
|
||||||
switchDelayMs(switchDelayMs) {}
|
switchDelayMs(switchDelayMs) {}
|
||||||
|
@ -8,17 +8,10 @@
|
|||||||
#include "definitions.h"
|
#include "definitions.h"
|
||||||
#include "fsfw/objectmanager/SystemObject.h"
|
#include "fsfw/objectmanager/SystemObject.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This component can be used to simulate a power switcher like a
|
|
||||||
* Power Control Distribution Unit (PCDU)
|
|
||||||
* @details
|
|
||||||
* The dummy switcher will simply cache the commanded fuse and switch states and return them
|
|
||||||
* in the according switch getter functions. In that sense, it simulates an ideal PCDU.
|
|
||||||
*/
|
|
||||||
class DummyPowerSwitcher : public SystemObject, public PowerSwitchIF {
|
class DummyPowerSwitcher : public SystemObject, public PowerSwitchIF {
|
||||||
public:
|
public:
|
||||||
DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, size_t numberOfFuses,
|
DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, size_t numberOfFuses,
|
||||||
bool registerGlobally = true, uint32_t switchDelayMs = 5000);
|
uint32_t switchDelayMs = 5000);
|
||||||
|
|
||||||
void setInitialSwitcherList(std::vector<ReturnValue_t> switcherList);
|
void setInitialSwitcherList(std::vector<ReturnValue_t> switcherList);
|
||||||
void setInitialFusesList(std::vector<ReturnValue_t> switcherList);
|
void setInitialFusesList(std::vector<ReturnValue_t> switcherList);
|
||||||
|
@ -18,8 +18,7 @@ class PowerSwitcher : public HasReturnvaluesIF {
|
|||||||
static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER;
|
static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER;
|
||||||
static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1);
|
static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1);
|
||||||
static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2);
|
static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2);
|
||||||
PowerSwitcher(PowerSwitchIF* switcher, power::Switch_t setSwitch1,
|
PowerSwitcher(PowerSwitchIF* switcher, uint8_t setSwitch1, uint8_t setSwitch2 = power::NO_SWITCH,
|
||||||
power::Switch_t setSwitch2 = power::NO_SWITCH,
|
|
||||||
State_t setStartState = SWITCH_IS_OFF);
|
State_t setStartState = SWITCH_IS_OFF);
|
||||||
void turnOn(bool checkCurrentState = true);
|
void turnOn(bool checkCurrentState = true);
|
||||||
void turnOff(bool checkCurrentState = true);
|
void turnOff(bool checkCurrentState = true);
|
||||||
|
@ -13,6 +13,8 @@ CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, u
|
|||||||
: CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) {
|
: CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CService201HealthCommanding::~CService201HealthCommanding() {}
|
||||||
|
|
||||||
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
|
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
|
||||||
switch (subservice) {
|
switch (subservice) {
|
||||||
case (Subservice::COMMAND_SET_HEALTH):
|
case (Subservice::COMMAND_SET_HEALTH):
|
||||||
@ -41,8 +43,8 @@ ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subs
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
||||||
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
|
MessageQueueId_t *messageQueueToSet, object_id_t *objectId) {
|
||||||
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
HasHealthIF *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
||||||
if (destination == nullptr) {
|
if (destination == nullptr) {
|
||||||
return CommandingServiceBase::INVALID_OBJECT;
|
return CommandingServiceBase::INVALID_OBJECT;
|
||||||
}
|
}
|
||||||
@ -75,10 +77,6 @@ ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *messag
|
|||||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
|
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
|
||||||
// Should never happen, subservice was already checked
|
|
||||||
result = RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -97,10 +95,10 @@ ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *rep
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Not used for now, health state already reported by event
|
// Not used for now, health state already reported by event
|
||||||
[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(
|
ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(const CommandMessage *reply) {
|
||||||
const CommandMessage *reply) {
|
prepareHealthSetReply(reply);
|
||||||
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
uint8_t health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
||||||
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
uint8_t oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
||||||
HealthSetReply healthSetReply(health, oldHealth);
|
HealthSetReply healthSetReply(health, oldHealth);
|
||||||
return sendTmPacket(Subservice::REPLY_HEALTH_SET, &healthSetReply);
|
return sendTmPacket(Subservice::REPLY_HEALTH_SET, &healthSetReply);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||||
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||||
|
|
||||||
#include "fsfw/tmtcservices/CommandingServiceBase.h"
|
#include "../tmtcservices/CommandingServiceBase.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Custom PUS service to set health of all objects
|
* @brief Custom PUS service to set health of all objects
|
||||||
@ -21,7 +21,7 @@ class CService201HealthCommanding : public CommandingServiceBase {
|
|||||||
public:
|
public:
|
||||||
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
||||||
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
|
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
|
||||||
~CService201HealthCommanding() override = default;
|
virtual ~CService201HealthCommanding();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* CSB abstract function implementations */
|
/* CSB abstract function implementations */
|
||||||
@ -38,10 +38,12 @@ class CService201HealthCommanding : public CommandingServiceBase {
|
|||||||
bool *isStep) override;
|
bool *isStep) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
|
ReturnValue_t checkAndAcquireTargetID(object_id_t *objectIdToSet, const uint8_t *tcData,
|
||||||
const object_id_t *objectId);
|
size_t tcDataLen);
|
||||||
|
ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
|
||||||
|
object_id_t *objectId);
|
||||||
|
|
||||||
[[maybe_unused]] ReturnValue_t prepareHealthSetReply(const CommandMessage *reply);
|
ReturnValue_t prepareHealthSetReply(const CommandMessage *reply);
|
||||||
|
|
||||||
enum Subservice {
|
enum Subservice {
|
||||||
//! [EXPORT] : [TC] Set health of target object
|
//! [EXPORT] : [TC] Set health of target object
|
||||||
|
@ -164,5 +164,3 @@ ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const {
|
|||||||
void FixedSlotSequence::addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList&)) {
|
void FixedSlotSequence::addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList&)) {
|
||||||
this->customCheckFunction = customCheckFunction;
|
this->customCheckFunction = customCheckFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FixedSlotSequence::isEmpty() const { return slotList.empty(); }
|
|
||||||
|
@ -159,8 +159,6 @@ class FixedSlotSequence {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t intializeSequenceAfterTaskCreation() const;
|
ReturnValue_t intializeSequenceAfterTaskCreation() const;
|
||||||
|
|
||||||
bool isEmpty() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief This list contains all PollingSlot objects, defining order and
|
* @brief This list contains all PollingSlot objects, defining order and
|
||||||
|
@ -30,7 +30,7 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF {
|
|||||||
* Check whether the sequence is valid and perform all other required
|
* Check whether the sequence is valid and perform all other required
|
||||||
* initialization steps which are needed after task creation
|
* initialization steps which are needed after task creation
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t checkSequence() = 0;
|
virtual ReturnValue_t checkSequence() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */
|
#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */
|
||||||
|
@ -31,7 +31,7 @@ class PeriodicTaskIF {
|
|||||||
* Add an object to the task. The object needs to implement ExecutableObjectIF
|
* Add an object to the task. The object needs to implement ExecutableObjectIF
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode = 0) {
|
virtual ReturnValue_t addComponent(object_id_t object) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,15 +41,13 @@ class PeriodicTaskIF {
|
|||||||
* Add an object to the task.
|
* Add an object to the task.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode = 0) {
|
virtual ReturnValue_t addComponent(ExecutableObjectIF* object) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ReturnValue_t sleepFor(uint32_t ms) = 0;
|
virtual ReturnValue_t sleepFor(uint32_t ms) = 0;
|
||||||
|
|
||||||
virtual uint32_t getPeriodMs() const = 0;
|
virtual uint32_t getPeriodMs() const = 0;
|
||||||
|
|
||||||
virtual bool isEmpty() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* PERIODICTASKIF_H_ */
|
#endif /* PERIODICTASKIF_H_ */
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
|
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
|
||||||
if (startImmediately) {
|
if (startImmediately) {
|
||||||
setTimeout(initialTimeout);
|
setTimeout(initialTimeout);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
timeout = initialTimeout;
|
timeout = initialTimeout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ class CommandingServiceBase : public SystemObject,
|
|||||||
* @param objectId Target object ID
|
* @param objectId Target object ID
|
||||||
* @return
|
* @return
|
||||||
* - @c RETURN_OK to generate a verification start message
|
* - @c RETURN_OK to generate a verification start message
|
||||||
* - @c EXECUTION_COMPLETE Fire-and-forget command. Generate a completion
|
* - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion
|
||||||
* verification message.
|
* verification message.
|
||||||
* - @c Anything else rejects the packets and generates a start failure
|
* - @c Anything else rejects the packets and generates a start failure
|
||||||
* verification.
|
* verification.
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
class SourceSequenceCounter {
|
class SourceSequenceCounter {
|
||||||
private:
|
private:
|
||||||
uint16_t sequenceCount = 0;
|
uint16_t sequenceCount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SourceSequenceCounter(uint16_t initialSequenceCount = 0) : sequenceCount(initialSequenceCount) {}
|
SourceSequenceCounter() : sequenceCount(0) {}
|
||||||
void increment() {
|
void increment() {
|
||||||
sequenceCount = (sequenceCount + 1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT);
|
sequenceCount = (sequenceCount + 1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT);
|
||||||
}
|
}
|
||||||
@ -31,7 +31,6 @@ class SourceSequenceCounter {
|
|||||||
sequenceCount = newCount;
|
sequenceCount = newCount;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator uint16_t() { return this->get(); }
|
operator uint16_t() { return this->get(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,10 +11,7 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(testcfg)
|
add_subdirectory(testcfg)
|
||||||
add_subdirectory(mocks)
|
|
||||||
|
|
||||||
add_subdirectory(action)
|
add_subdirectory(action)
|
||||||
add_subdirectory(power)
|
|
||||||
add_subdirectory(container)
|
add_subdirectory(container)
|
||||||
add_subdirectory(osal)
|
add_subdirectory(osal)
|
||||||
add_subdirectory(serialize)
|
add_subdirectory(serialize)
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
target_sources(${FSFW_TEST_TGT} PRIVATE
|
|
||||||
PowerSwitcherMock.cpp
|
|
||||||
)
|
|
@ -1,77 +0,0 @@
|
|||||||
#include "PowerSwitcherMock.h"
|
|
||||||
|
|
||||||
static uint32_t SWITCH_REQUEST_UPDATE_VALUE = 0;
|
|
||||||
|
|
||||||
PowerSwitcherMock::PowerSwitcherMock() {}
|
|
||||||
|
|
||||||
ReturnValue_t PowerSwitcherMock::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {
|
|
||||||
if (switchMap.count(switchNr) == 0) {
|
|
||||||
switchMap.emplace(switchNr, SwitchInfo(switchNr, onOff));
|
|
||||||
} else {
|
|
||||||
SwitchInfo& info = switchMap.at(switchNr);
|
|
||||||
info.currentState = onOff;
|
|
||||||
if (onOff == PowerSwitchIF::SWITCH_ON) {
|
|
||||||
info.timesCalledOn++;
|
|
||||||
} else {
|
|
||||||
info.timesCalledOff++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PowerSwitcherMock::sendFuseOnCommand(uint8_t fuseNr) {
|
|
||||||
if (fuseMap.count(fuseNr) == 0) {
|
|
||||||
fuseMap.emplace(fuseNr, FuseInfo(fuseNr));
|
|
||||||
} else {
|
|
||||||
FuseInfo& info = fuseMap.at(fuseNr);
|
|
||||||
info.timesCalled++;
|
|
||||||
}
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PowerSwitcherMock::getSwitchState(power::Switch_t switchNr) const {
|
|
||||||
if (switchMap.count(switchNr) == 1) {
|
|
||||||
auto& info = switchMap.at(switchNr);
|
|
||||||
SWITCH_REQUEST_UPDATE_VALUE++;
|
|
||||||
return info.currentState;
|
|
||||||
}
|
|
||||||
return RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PowerSwitcherMock::getFuseState(uint8_t fuseNr) const {
|
|
||||||
if (fuseMap.count(fuseNr) == 1) {
|
|
||||||
return FUSE_ON;
|
|
||||||
} else {
|
|
||||||
return FUSE_OFF;
|
|
||||||
}
|
|
||||||
return RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PowerSwitcherMock::getSwitchDelayMs(void) const { return 5000; }
|
|
||||||
|
|
||||||
SwitchInfo::SwitchInfo() : switcher(0) {}
|
|
||||||
|
|
||||||
SwitchInfo::SwitchInfo(power::Switch_t switcher, ReturnValue_t initState)
|
|
||||||
: switcher(switcher), currentState(initState) {}
|
|
||||||
|
|
||||||
FuseInfo::FuseInfo(uint8_t fuse) : fuse(fuse) {}
|
|
||||||
|
|
||||||
void PowerSwitcherMock::getSwitchInfo(power::Switch_t switcher, SwitchInfo& info) {
|
|
||||||
if (switchMap.count(switcher) == 1) {
|
|
||||||
info = switchMap.at(switcher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PowerSwitcherMock::getFuseInfo(uint8_t fuse, FuseInfo& info) {
|
|
||||||
if (fuseMap.count(fuse) == 1) {
|
|
||||||
info = fuseMap.at(fuse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PowerSwitcherMock::getAmountSwitchStatWasRequested() {
|
|
||||||
return SWITCH_REQUEST_UPDATE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PowerSwitcherMock::initSwitch(power::Switch_t switchNr) {
|
|
||||||
switchMap.emplace(switchNr, SwitchInfo(switchNr, PowerSwitchIF::SWITCH_OFF));
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
#ifndef FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_
|
|
||||||
#define FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_
|
|
||||||
|
|
||||||
#include <fsfw/power/PowerSwitchIF.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
struct SwitchInfo {
|
|
||||||
public:
|
|
||||||
SwitchInfo();
|
|
||||||
SwitchInfo(power::Switch_t switcher, ReturnValue_t initState);
|
|
||||||
|
|
||||||
power::Switch_t switcher;
|
|
||||||
ReturnValue_t currentState = PowerSwitchIF::SWITCH_OFF;
|
|
||||||
uint32_t timesCalledOn = 0;
|
|
||||||
uint32_t timesCalledOff = 0;
|
|
||||||
uint32_t timesStatusRequested = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FuseInfo {
|
|
||||||
public:
|
|
||||||
FuseInfo(uint8_t fuse);
|
|
||||||
uint8_t fuse;
|
|
||||||
uint32_t timesCalled = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PowerSwitcherMock : public PowerSwitchIF {
|
|
||||||
public:
|
|
||||||
PowerSwitcherMock();
|
|
||||||
|
|
||||||
ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) override;
|
|
||||||
ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) override;
|
|
||||||
ReturnValue_t getSwitchState(power::Switch_t switchNr) const override;
|
|
||||||
ReturnValue_t getFuseState(uint8_t fuseNr) const override;
|
|
||||||
uint32_t getSwitchDelayMs(void) const override;
|
|
||||||
|
|
||||||
void getSwitchInfo(power::Switch_t switcher, SwitchInfo& info);
|
|
||||||
void getFuseInfo(uint8_t fuse, FuseInfo& info);
|
|
||||||
|
|
||||||
uint32_t getAmountSwitchStatWasRequested();
|
|
||||||
|
|
||||||
void initSwitch(power::Switch_t switchNr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
using SwitchOnOffPair = std::pair<power::Switch_t, ReturnValue_t>;
|
|
||||||
using FuseOnOffPair = std::pair<uint8_t, ReturnValue_t>;
|
|
||||||
std::map<power::Switch_t, SwitchInfo> switchMap;
|
|
||||||
std::map<uint8_t, FuseInfo> fuseMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_ */
|
|
@ -1,3 +0,0 @@
|
|||||||
target_sources(${FSFW_TEST_TGT} PRIVATE
|
|
||||||
testPowerSwitcher.cpp
|
|
||||||
)
|
|
@ -1,71 +0,0 @@
|
|||||||
#include <fsfw/power/DummyPowerSwitcher.h>
|
|
||||||
#include <fsfw/power/PowerSwitcher.h>
|
|
||||||
#include <fsfw_tests/unit/mocks/PowerSwitcherMock.h>
|
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
|
|
||||||
#include "objects/systemObjectList.h"
|
|
||||||
|
|
||||||
TEST_CASE("Power Switcher", "[power-switcher]") {
|
|
||||||
PowerSwitcherMock mock;
|
|
||||||
PowerSwitcher switcher(&mock, 1);
|
|
||||||
DummyPowerSwitcher dummySwitcher(objects::DUMMY_POWER_SWITCHER, 5, 5, false);
|
|
||||||
PowerSwitcher switcherUsingDummy(&dummySwitcher, 1);
|
|
||||||
SwitchInfo switchInfo;
|
|
||||||
mock.initSwitch(1);
|
|
||||||
|
|
||||||
SECTION("Basic Tests") {
|
|
||||||
REQUIRE(switcher.getFirstSwitch() == 1);
|
|
||||||
REQUIRE(switcher.getSecondSwitch() == power::NO_SWITCH);
|
|
||||||
// Default start state
|
|
||||||
REQUIRE(switcher.getState() == PowerSwitcher::SWITCH_IS_OFF);
|
|
||||||
switcher.turnOn(true);
|
|
||||||
REQUIRE(mock.getAmountSwitchStatWasRequested() == 1);
|
|
||||||
REQUIRE(switcher.getState() == PowerSwitcher::WAIT_ON);
|
|
||||||
REQUIRE(switcher.checkSwitchState() == PowerSwitcher::IN_POWER_TRANSITION);
|
|
||||||
REQUIRE(switcher.active());
|
|
||||||
switcher.doStateMachine();
|
|
||||||
REQUIRE(switcher.getState() == PowerSwitcher::SWITCH_IS_ON);
|
|
||||||
mock.getSwitchInfo(1, switchInfo);
|
|
||||||
REQUIRE(switchInfo.timesCalledOn == 1);
|
|
||||||
REQUIRE(not switcher.active());
|
|
||||||
REQUIRE(mock.getAmountSwitchStatWasRequested() == 2);
|
|
||||||
REQUIRE(switcher.checkSwitchState() == HasReturnvaluesIF::RETURN_OK);
|
|
||||||
REQUIRE(mock.getAmountSwitchStatWasRequested() == 3);
|
|
||||||
switcher.turnOff(false);
|
|
||||||
REQUIRE(mock.getAmountSwitchStatWasRequested() == 3);
|
|
||||||
REQUIRE(switcher.getState() == PowerSwitcher::WAIT_OFF);
|
|
||||||
REQUIRE(switcher.active());
|
|
||||||
REQUIRE(switcher.getState() == PowerSwitcher::WAIT_OFF);
|
|
||||||
switcher.doStateMachine();
|
|
||||||
mock.getSwitchInfo(1, switchInfo);
|
|
||||||
REQUIRE(switcher.getState() == PowerSwitcher::SWITCH_IS_OFF);
|
|
||||||
REQUIRE(switchInfo.timesCalledOn == 1);
|
|
||||||
REQUIRE(switchInfo.timesCalledOff == 1);
|
|
||||||
REQUIRE(not switcher.active());
|
|
||||||
REQUIRE(mock.getAmountSwitchStatWasRequested() == 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Dummy Test") {
|
|
||||||
// Same tests, but we can't really check the dummy
|
|
||||||
REQUIRE(switcherUsingDummy.getFirstSwitch() == 1);
|
|
||||||
REQUIRE(switcherUsingDummy.getSecondSwitch() == power::NO_SWITCH);
|
|
||||||
REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::SWITCH_IS_OFF);
|
|
||||||
switcherUsingDummy.turnOn(true);
|
|
||||||
REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::WAIT_ON);
|
|
||||||
REQUIRE(switcherUsingDummy.active());
|
|
||||||
switcherUsingDummy.doStateMachine();
|
|
||||||
REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::SWITCH_IS_ON);
|
|
||||||
REQUIRE(not switcherUsingDummy.active());
|
|
||||||
|
|
||||||
switcherUsingDummy.turnOff(false);
|
|
||||||
REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::WAIT_OFF);
|
|
||||||
REQUIRE(switcherUsingDummy.active());
|
|
||||||
REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::WAIT_OFF);
|
|
||||||
switcherUsingDummy.doStateMachine();
|
|
||||||
REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::SWITCH_IS_OFF);
|
|
||||||
REQUIRE(not switcherUsingDummy.active());
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("More Dummy Tests") {}
|
|
||||||
}
|
|
@ -21,9 +21,8 @@ enum sourceObjects : uint32_t {
|
|||||||
HK_RECEIVER_MOCK = 22,
|
HK_RECEIVER_MOCK = 22,
|
||||||
TEST_LOCAL_POOL_OWNER_BASE = 25,
|
TEST_LOCAL_POOL_OWNER_BASE = 25,
|
||||||
|
|
||||||
SHARED_SET_ID = 26,
|
SHARED_SET_ID = 26
|
||||||
|
|
||||||
DUMMY_POWER_SWITCHER = 27
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user