Merge pull request 'SPI refactoring' (#80) from mueller/spi-cache-spi-dev-in-com-if into develop

Reviewed-on: #80
This commit is contained in:
Jakob Meier 2022-05-11 16:28:08 +02:00
commit c0ff84bb9d
21 changed files with 158 additions and 103 deletions

View File

@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Changes ## Changes
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
compiler supports it
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed - HAL Linux SPI: Set the Clock Default State when setting new SPI speed
and mode and mode
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
@ -57,15 +60,34 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Additions ## Additions
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
- 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
- `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

View File

@ -2,6 +2,13 @@ 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)
@ -178,13 +185,6 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
) )
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
elseif(${CMAKE_CXX_STANDARD} LESS 11)
message(FATAL_ERROR "${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")

View File

@ -6,7 +6,7 @@
#include "fsfw/FSFW.h" #include "fsfw/FSFW.h"
#include "fsfw/serviceinterface.h" #include "fsfw/serviceinterface.h"
UnixFileGuard::UnixFileGuard(std::string device, int* fileDescriptor, int flags, UnixFileGuard::UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
std::string diagnosticPrefix) std::string diagnosticPrefix)
: fileDescriptor(fileDescriptor) { : fileDescriptor(fileDescriptor) {
if (fileDescriptor == nullptr) { if (fileDescriptor == nullptr) {

View File

@ -15,7 +15,7 @@ class UnixFileGuard {
static constexpr ReturnValue_t OPEN_FILE_FAILED = 1; static constexpr ReturnValue_t OPEN_FILE_FAILED = 1;
UnixFileGuard(std::string device, int* fileDescriptor, int flags, UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
std::string diagnosticPrefix = ""); std::string diagnosticPrefix = "");
virtual ~UnixFileGuard(); virtual ~UnixFileGuard();

View File

@ -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, GpioIF* gpioComIF) SpiComIF::SpiComIF(object_id_t objectId, std::string devname, GpioIF* gpioComIF)
: SystemObject(objectId), gpioComIF(gpioComIF) { : SystemObject(objectId), gpioComIF(gpioComIF), dev(std::move(devname)) {
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, GpioIF* gpioComIF)
#endif /* FSFW_VERBOSE_LEVEL >= 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */
} }
spiMutex = MutexFactory::instance()->createMutex(); csMutex = MutexFactory::instance()->createMutex();
} }
ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) { ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
@ -85,8 +85,7 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
spiCookie->getSpiParameters(spiMode, spiSpeed, &params); spiCookie->getSpiParameters(spiMode, spiSpeed, &params);
int fileDescriptor = 0; int fileDescriptor = 0;
UnixFileGuard fileHelper(spiCookie->getSpiDevice(), &fileDescriptor, O_RDWR, UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::initializeInterface");
"SpiComIF::initializeInterface");
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return fileHelper.getOpenResult(); return fileHelper.getOpenResult();
} }
@ -182,8 +181,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
int retval = 0; int retval = 0;
/* Prepare transfer */ /* Prepare transfer */
int fileDescriptor = 0; int fileDescriptor = 0;
std::string device = spiCookie->getSpiDevice(); UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
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;
} }
@ -199,7 +197,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 = spiMutex->lockMutex(timeoutType, timeoutMs); result = csMutex->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
@ -210,6 +208,7 @@ 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
@ -221,6 +220,8 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
#endif #endif
return result; return result;
} }
} else {
updateLinePolarity(fileDescriptor);
} }
/* Execute transfer */ /* Execute transfer */
@ -250,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 = spiMutex->unlockMutex(); result = csMutex->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;
@ -278,9 +279,8 @@ 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(device, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage"); UnixFileGuard fileHelper(dev, &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 +294,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 = spiMutex->lockMutex(timeoutType, timeoutMs); result = csMutex->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 +317,7 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
if (gpioId != gpio::NO_GPIO) { if (gpioId != gpio::NO_GPIO) {
gpioComIF->pullHigh(gpioId); gpioComIF->pullHigh(gpioId);
result = spiMutex->unlockMutex(); result = csMutex->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 +353,7 @@ MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeout
if (timeoutMs != nullptr) { if (timeoutMs != nullptr) {
*timeoutMs = this->timeoutMs; *timeoutMs = this->timeoutMs;
} }
return spiMutex; return csMutex;
} }
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) { void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
@ -401,11 +401,29 @@ 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
// switch the state after the chip select is pulled low void SpiComIF::getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const {
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;
retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer); int 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");
} }

View File

@ -32,7 +32,7 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED = static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED =
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 2); HasReturnvaluesIF::makeReturnCode(spiRetvalId, 2);
SpiComIF(object_id_t objectId, GpioIF* gpioComIF); SpiComIF(object_id_t objectId, std::string devname, 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;
@ -59,6 +59,20 @@ 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);
/**
* 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);
void getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const;
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);
@ -70,8 +84,12 @@ 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 = 20; uint32_t timeoutMs = 20;
spi_ioc_transfer clockUpdateTransfer = {}; spi_ioc_transfer clockUpdateTransfer = {};

View File

@ -1,26 +1,25 @@
#include "SpiCookie.h" #include "SpiCookie.h"
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize,
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(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) {} : SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
nullptr, nullptr) {}
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, SpiCookie::SpiCookie(address_t spiAddress, const size_t maxSize, spi::SpiModes spiMode,
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed, 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) spi::send_callback_function_t callback, void* args)
: SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize, spiMode, : SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
spiSpeed, callback, args) {} callback, args) {}
SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect, SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
uint32_t spiSpeed, spi::send_callback_function_t callback, void* args) 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),
@ -50,8 +49,6 @@ 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; }

View File

@ -29,23 +29,22 @@ class SpiCookie : public CookieIF {
* @param spiDev * @param spiDev
* @param maxSize * @param maxSize
*/ */
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize, SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
spi::SpiModes spiMode, uint32_t spiSpeed); 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, std::string spiDev, const size_t maxReplySize, SpiCookie(address_t spiAddress, const size_t maxReplySize, spi::SpiModes spiMode,
spi::SpiModes spiMode, uint32_t spiSpeed); 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, std::string spiDev, const size_t maxSize, SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback, uint32_t spiSpeed, spi::send_callback_function_t callback, void* args);
void* args);
/** /**
* Get the callback function * Get the callback function
@ -55,7 +54,6 @@ 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;
@ -154,12 +152,11 @@ 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,
std::string spiDev, 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);
address_t spiAddress; address_t spiAddress;
gpioId_t chipSelectPin; gpioId_t chipSelectPin;
std::string spiDevice;
spi::SpiComIfModes comIfMode; spi::SpiComIfModes comIfMode;

View File

@ -2,6 +2,7 @@
#define FIXEDARRAYLIST_H_ #define FIXEDARRAYLIST_H_
#include <cmath> #include <cmath>
#include <limits>
#include "ArrayList.h" #include "ArrayList.h"
/** /**
@ -9,10 +10,9 @@
*/ */
template <typename T, size_t MAX_SIZE, typename count_t = uint8_t> template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
class FixedArrayList : public ArrayList<T, count_t> { class FixedArrayList : public ArrayList<T, count_t> {
#if !defined(_MSC_VER) && !defined(__clang__) static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
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];

View File

@ -1401,8 +1401,7 @@ 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;

View File

@ -801,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;
}; };
@ -1269,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.

View File

@ -19,6 +19,8 @@
#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;
@ -29,7 +31,7 @@ TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
: SystemObject(objectId), : SystemObject(objectId),
tmtcBridgeId(tmtcTcpBridge), tmtcBridgeId(tmtcTcpBridge),
receptionMode(receptionMode), receptionMode(receptionMode),
tcpConfig(customTcpServerPort), tcpConfig(std::move(customTcpServerPort)),
receptionBuffer(receptionBufferSize), receptionBuffer(receptionBufferSize),
ringBuffer(ringBufferSize, true) {} ringBuffer(ringBufferSize, true) {}
@ -103,7 +105,7 @@ ReturnValue_t TcpTmTcServer::initialize() {
TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); } TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { [[noreturn]] 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;
@ -138,7 +140,6 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
closeSocket(connSocket); closeSocket(connSocket);
connSocket = 0; connSocket = 0;
} }
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
@ -159,8 +160,8 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) {
#endif #endif
while (true) { while (true) {
int retval = recv(connSocket, reinterpret_cast<char*>(receptionBuffer.data()), ssize_t 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) {
@ -252,17 +253,17 @@ ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t pack
return result; return result;
} }
std::string TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; } const 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 = validPacketIds; this->validPacketIds = std::move(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(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs); MutexGuard mg(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)) {
@ -283,8 +284,8 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)
#endif #endif
arrayprinter::print(storeAccessor.data(), storeAccessor.size()); arrayprinter::print(storeAccessor.data(), storeAccessor.size());
} }
int retval = send(connSocket, reinterpret_cast<const char*>(storeAccessor.data()), ssize_t 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();
@ -339,6 +340,9 @@ 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) {

View File

@ -17,6 +17,7 @@
#endif #endif
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
class TcpTmTcBridge; class TcpTmTcBridge;
@ -44,7 +45,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
struct TcpConfig { struct TcpConfig {
public: public:
TcpConfig(std::string tcpPort) : tcpPort(tcpPort) {} explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
/** /**
* Passed to the recv call * Passed to the recv call
@ -84,7 +85,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);
virtual ~TcpTmTcServer(); ~TcpTmTcServer() override;
void enableWiretapping(bool enable); void enableWiretapping(bool enable);
@ -97,10 +98,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;
ReturnValue_t performOperation(uint8_t opCode) override; [[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initializeAfterTaskCreation() override; ReturnValue_t initializeAfterTaskCreation() override;
std::string getTcpPort() const; [[nodiscard]] const std::string& getTcpPort() const;
protected: protected:
StorageManagerIF* tcStore = nullptr; StorageManagerIF* tcStore = nullptr;
@ -115,7 +116,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;

View File

@ -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
} }
} }

View File

@ -88,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
} }
} }

View File

@ -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
} }
} }

View File

@ -13,8 +13,6 @@ 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):
@ -43,8 +41,8 @@ ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subs
} }
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue( ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
MessageQueueId_t *messageQueueToSet, object_id_t *objectId) { MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
HasHealthIF *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId); auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
if (destination == nullptr) { if (destination == nullptr) {
return CommandingServiceBase::INVALID_OBJECT; return CommandingServiceBase::INVALID_OBJECT;
} }
@ -77,6 +75,10 @@ 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;
} }
@ -95,10 +97,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
ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(const CommandMessage *reply) { [[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(
prepareHealthSetReply(reply); const CommandMessage *reply) {
uint8_t health = static_cast<uint8_t>(HealthMessage::getHealth(reply)); auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
uint8_t oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply)); auto 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);
} }

View File

@ -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 "../tmtcservices/CommandingServiceBase.h" #include "fsfw/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);
virtual ~CService201HealthCommanding(); ~CService201HealthCommanding() override = default;
protected: protected:
/* CSB abstract function implementations */ /* CSB abstract function implementations */
@ -38,12 +38,10 @@ class CService201HealthCommanding : public CommandingServiceBase {
bool *isStep) override; bool *isStep) override;
private: private:
ReturnValue_t checkAndAcquireTargetID(object_id_t *objectIdToSet, const uint8_t *tcData, static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
size_t tcDataLen); const object_id_t *objectId);
ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
object_id_t *objectId);
ReturnValue_t prepareHealthSetReply(const CommandMessage *reply); [[maybe_unused]] ReturnValue_t prepareHealthSetReply(const CommandMessage *reply);
enum Subservice { enum Subservice {
//! [EXPORT] : [TC] Set health of target object //! [EXPORT] : [TC] Set health of target object

View File

@ -3,8 +3,7 @@
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;
} }
} }

View File

@ -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_COMPELTE Fire-and-forget command. Generate a completion * - @c EXECUTION_COMPLETE 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.

View File

@ -5,7 +5,7 @@
class SourceSequenceCounter { class SourceSequenceCounter {
private: private:
uint16_t sequenceCount; uint16_t sequenceCount = 0;
public: public:
SourceSequenceCounter(uint16_t initialSequenceCount = 0) : sequenceCount(initialSequenceCount) {} SourceSequenceCounter(uint16_t initialSequenceCount = 0) : sequenceCount(initialSequenceCount) {}