Merge branch 'develop' into develop_update

This commit is contained in:
Robin Müller 2023-02-07 12:24:27 +01:00
commit e9d629b9b3
44 changed files with 548 additions and 234 deletions

View File

@ -12,6 +12,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Fixes ## Fixes
- HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously,
only the X scaling factor was used.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
to false correctly because the `read` and `write` calls were missing.
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
of the correct unsegmented flags (0b11) as specified in the standard.
- `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval
seconds instead of uptime.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/726
- TC Scheduler Service 11: Add size and CRC check for contained TC.
- Only delete health table entry in `HealthHelper` destructor if - Only delete health table entry in `HealthHelper` destructor if
health table was set. health table was set.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710/files PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710/files
@ -24,9 +35,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `TcpTmTcServer.cpp`: The server was actually not able to handle - `TcpTmTcServer.cpp`: The server was actually not able to handle
CCSDS packets which were clumped together. This has been fixed now. CCSDS packets which were clumped together. This has been fixed now.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
- `CServiceHealthCommanding`: Add announce all health info implementation
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
## Added ## Added
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT`
option on the TCP server. CTOR prototype has changed and expects an explicit
TCP configuration struct to be passed.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/722
- `DleParser` helper class to parse DLE encoded packets from a byte stream. - `DleParser` helper class to parse DLE encoded packets from a byte stream.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
- `UioMapper` is able to resolve symlinks now. - `UioMapper` is able to resolve symlinks now.
@ -36,6 +54,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Changes ## Changes
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
`HealthServiceCfg` now
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now - `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
- Moved some container returnvalues to dedicated header and namespace - Moved some container returnvalues to dedicated header and namespace

View File

@ -1,45 +1,87 @@
pipeline { pipeline {
environment { environment {
BUILDDIR = 'cmake-build-tests' BUILDDIR_HOST = 'cmake-build-tests-host'
BUILDDIR_LINUX = 'cmake-build-tests-linux'
DOCDDIR = 'cmake-build-documentation' DOCDDIR = 'cmake-build-documentation'
} }
agent { agent {
docker { docker {
image 'fsfw-ci:d6' image 'fsfw-ci:d6'
args '--network host' args '--network host --sysctl fs.mqueue.msg_max=100'
} }
} }
stages { stages {
stage('Clean') { stage('Host') {
steps { stages{
sh 'rm -rf $BUILDDIR' stage('Clean') {
} steps {
} sh 'rm -rf $BUILDDIR_HOST'
stage('Configure') { }
steps { }
dir(BUILDDIR) { stage('Configure') {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..' steps {
dir(BUILDDIR_HOST) {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
}
}
}
stage('Build') {
steps {
dir(BUILDDIR_HOST) {
sh 'cmake --build . -j4'
}
}
}
stage('Unittests') {
steps {
dir(BUILDDIR_HOST) {
sh 'cmake --build . -- fsfw-tests_coverage -j4'
}
}
}
stage('Valgrind') {
steps {
dir(BUILDDIR_HOST) {
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
}
}
} }
} }
} }
stage('Build') { stage('Linux') {
steps { stages{
dir(BUILDDIR) { stage('Clean') {
sh 'cmake --build . -j4' steps {
sh 'rm -rf $BUILDDIR_LINUX'
}
} }
} stage('Configure') {
} steps {
stage('Unittests') { dir(BUILDDIR_LINUX) {
steps { sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
dir(BUILDDIR) { }
sh 'cmake --build . -- fsfw-tests_coverage -j4' }
} }
} stage('Build') {
} steps {
stage('Valgrind') { dir(BUILDDIR_LINUX) {
steps { sh 'cmake --build . -j4'
dir(BUILDDIR) { }
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests' }
}
stage('Unittests') {
steps {
dir(BUILDDIR_LINUX) {
sh 'cmake --build . -- fsfw-tests_coverage -j4'
}
}
}
stage('Valgrind') {
steps {
dir(BUILDDIR_LINUX) {
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
}
}
} }
} }
} }

View File

@ -51,7 +51,10 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
html_theme = "alabaster" html_theme = "alabaster"
html_theme_options = { html_theme_options = {
"extra_nav_links": {"Impressum" : "https://www.uni-stuttgart.de/impressum", "Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html"} "extra_nav_links": {
"Impressum": "https://www.uni-stuttgart.de/impressum",
"Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html",
}
} }

View File

@ -12,6 +12,7 @@ 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(), static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
"count_t is not large enough to hold MAX_SIZE"); "count_t is not large enough to hold MAX_SIZE");
static_assert(MAX_SIZE > 0, "MAX_SIZE is 0");
private: private:
T data[MAX_SIZE]; T data[MAX_SIZE];

View File

@ -109,5 +109,5 @@ const HasModesIF& ControllerBase::getModeIF() const { return *this; }
ModeTreeChildIF& ControllerBase::getModeTreeChildIF() { return *this; } ModeTreeChildIF& ControllerBase::getModeTreeChildIF() { return *this; }
ReturnValue_t ControllerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) { ReturnValue_t ControllerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
return modetree::connectModeTreeParent(parent, *this, healthHelper, modeHelper); return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
} }

View File

@ -1,5 +1,6 @@
#include "DeviceHandlerBase.h" #include "DeviceHandlerBase.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include "fsfw/datapoollocal/LocalPoolVariable.h" #include "fsfw/datapoollocal/LocalPoolVariable.h"
#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h" #include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h"
#include "fsfw/devicehandlers/DeviceTmReportingWrapper.h" #include "fsfw/devicehandlers/DeviceTmReportingWrapper.h"
@ -1524,7 +1525,10 @@ DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const {
void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() { void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() {
for (const auto& reply : deviceReplyMap) { for (const auto& reply : deviceReplyMap) {
if (reply.second.dataSet != nullptr) { if (reply.second.dataSet != nullptr) {
reply.second.dataSet->setValidity(false, true); PoolReadGuard pg(reply.second.dataSet);
if (pg.getReadResult() == returnvalue::OK) {
reply.second.dataSet->setValidity(false, true);
}
} }
} }
} }
@ -1608,7 +1612,7 @@ void DeviceHandlerBase::disableCommandsAndReplies() {
} }
ReturnValue_t DeviceHandlerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) { ReturnValue_t DeviceHandlerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
return modetree::connectModeTreeParent(parent, *this, healthHelper, modeHelper); return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
} }
const HasHealthIF* DeviceHandlerBase::getOptHealthIF() const { return this; } const HasHealthIF* DeviceHandlerBase::getOptHealthIF() const { return this; }

View File

@ -24,6 +24,7 @@ EventManager::EventManager(object_id_t setObjectId)
} }
EventManager::~EventManager() { EventManager::~EventManager() {
listenerList.clear();
QueueFactory::instance()->deleteMessageQueue(eventReportQueue); QueueFactory::instance()->deleteMessageQueue(eventReportQueue);
MutexFactory::instance()->deleteMutex(mutex); MutexFactory::instance()->deleteMutex(mutex);
} }
@ -73,9 +74,14 @@ ReturnValue_t EventManager::registerListener(MessageQueueId_t listener,
if (!result.second) { if (!result.second) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t EventManager::unregisterListener(MessageQueueId_t listener) {
return listenerList.erase(listener) == 1 ? returnvalue::OK : returnvalue::FAILED;
}
ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) { ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) {
return subscribeToEventRange(listener, event); return subscribeToEventRange(listener, event);
} }

View File

@ -31,6 +31,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
MessageQueueId_t getEventReportQueue(); MessageQueueId_t getEventReportQueue();
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false); ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
ReturnValue_t unregisterListener(MessageQueueId_t listener) override;
ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event); ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event);
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object); ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object);
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0, ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,

View File

@ -18,6 +18,7 @@ class EventManagerIF {
virtual ReturnValue_t registerListener(MessageQueueId_t listener, virtual ReturnValue_t registerListener(MessageQueueId_t listener,
bool forwardAllButSelected = false) = 0; bool forwardAllButSelected = false) = 0;
virtual ReturnValue_t unregisterListener(MessageQueueId_t listener) = 0;
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0; virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0; virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0; virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;

View File

@ -24,7 +24,7 @@ FailureIsolationBase::~FailureIsolationBase() {
#endif #endif
return; return;
} }
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId); manager->unregisterListener(eventQueue->getId());
QueueFactory::instance()->deleteMessageQueue(eventQueue); QueueFactory::instance()->deleteMessageQueue(eventQueue);
} }

View File

@ -24,7 +24,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
MatchTree(iterator root, uint8_t maxDepth = -1) MatchTree(iterator root, uint8_t maxDepth = -1)
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {} : BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {} MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
virtual ~MatchTree() {} virtual ~MatchTree() { clear(); }
virtual bool match(T number) override { return matchesTree(number); } virtual bool match(T number) override { return matchesTree(number); }
bool matchesTree(T number) { bool matchesTree(T number) {
iterator iter = this->begin(); iterator iter = this->begin();
@ -176,6 +176,45 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
return cleanUpElement(position); return cleanUpElement(position);
} }
void clear() {
Node* localRoot = BinaryTree<SerializeableMatcherIF<T>>::rootNode;
if (localRoot == nullptr) {
return;
}
Node* node = localRoot->left;
while (true) {
if (node->left != nullptr) {
node = node->left;
continue;
}
if (node->right != nullptr) {
node = node->right;
continue;
}
if (node->parent == nullptr) {
// this is the root node with no children
if (node->value != nullptr) {
cleanUpElement(iterator(node));
}
return;
}
// leaf
{
Node* parent = node->parent;
if (parent->left == node) {
parent->left = nullptr;
} else {
parent->right = nullptr;
}
cleanUpElement(iterator(node));
node = parent;
}
}
}
virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; } virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; }
bool matchSubtree(iterator iter, T number) { bool matchSubtree(iterator iter, T number) {

View File

@ -6,8 +6,6 @@
HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) { HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) {
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
;
mapIterator = healthMap.begin(); mapIterator = healthMap.begin();
} }

View File

@ -8,6 +8,8 @@
#include "HealthTableIF.h" #include "HealthTableIF.h"
class HealthTable : public HealthTableIF, public SystemObject { class HealthTable : public HealthTableIF, public SystemObject {
friend class CServiceHealthCommanding;
public: public:
explicit HealthTable(object_id_t objectid); explicit HealthTable(object_id_t objectid);
~HealthTable() override; ~HealthTable() override;

View File

@ -10,13 +10,17 @@ InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t m
poolManager(this, commandQueue), poolManager(this, commandQueue),
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
internalErrorDataset(this) { internalErrorDataset(this) {
commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this)); auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
commandQueue = QueueFactory::instance()->createMessageQueue( commandQueue = QueueFactory::instance()->createMessageQueue(
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
} }
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); } InternalErrorReporter::~InternalErrorReporter() {
MutexFactory::instance()->deleteMutex(mutex);
QueueFactory::instance()->deleteMessageQueue(commandQueue);
}
void InternalErrorReporter::setDiagnosticPrintout(bool enable) { void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
this->diagnosticPrintout = enable; this->diagnosticPrintout = enable;

View File

@ -34,3 +34,7 @@ void ModeMessage::setModeAnnounceMessage(CommandMessage& message, bool recursive
} }
message.setCommand(cmd); message.setCommand(cmd);
} }
void ModeMessage::setCmdModeModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode) {
setModeMessage(&message, CMD_MODE_COMMAND, mode, submode);
}

View File

@ -38,12 +38,13 @@ class ModeMessage {
ModeMessage() = delete; ModeMessage() = delete;
static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode,
Submode_t submode);
static Mode_t getMode(const CommandMessage* message); static Mode_t getMode(const CommandMessage* message);
static Submode_t getSubmode(const CommandMessage* message); static Submode_t getSubmode(const CommandMessage* message);
static ReturnValue_t getCantReachModeReason(const CommandMessage* message); static ReturnValue_t getCantReachModeReason(const CommandMessage* message);
static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode, static void setCmdModeModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode);
Submode_t submode);
static void setModeAnnounceMessage(CommandMessage& message, bool recursive); static void setModeAnnounceMessage(CommandMessage& message, bool recursive);
static void setCantReachMode(CommandMessage* message, ReturnValue_t reason); static void setCantReachMode(CommandMessage* message, ReturnValue_t reason);
static void clear(CommandMessage* message); static void clear(CommandMessage* message);

View File

@ -23,9 +23,17 @@ void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc,
ObjectManager::ObjectManager() = default; ObjectManager::ObjectManager() = default;
void ObjectManager::clear() {
if (objManagerInstance != nullptr) {
delete objManagerInstance;
objManagerInstance = nullptr;
}
}
ObjectManager::~ObjectManager() { ObjectManager::~ObjectManager() {
for (auto const& iter : objectList) { teardown = true;
delete iter.second; for (auto iter = objectList.begin(); iter != objectList.end(); iter = objectList.erase(iter)) {
delete iter->second;
} }
} }
@ -53,6 +61,12 @@ ReturnValue_t ObjectManager::insert(object_id_t id, SystemObjectIF* object) {
} }
ReturnValue_t ObjectManager::remove(object_id_t id) { ReturnValue_t ObjectManager::remove(object_id_t id) {
// this function is called during destruction of System Objects
// disabeld for teardown to avoid iterator invalidation and
// double free
if (teardown) {
return returnvalue::OK;
}
if (this->getSystemObject(id) != nullptr) { if (this->getSystemObject(id) != nullptr) {
this->objectList.erase(id); this->objectList.erase(id);
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1

View File

@ -24,12 +24,17 @@ class ObjectManager : public ObjectManagerIF {
using produce_function_t = void (*)(void* args); using produce_function_t = void (*)(void* args);
/** /**
* Returns the single instance of TaskFactory. * Returns the single instance of ObjectManager.
* The implementation of #instance is found in its subclasses. * The implementation of #instance is found in its subclasses.
* Thus, we choose link-time variability of the instance. * Thus, we choose link-time variability of the instance.
*/ */
static ObjectManager* instance(); static ObjectManager* instance();
/**
* Deletes the single instance of ObjectManager
*/
static void clear();
void setObjectFactoryFunction(produce_function_t prodFunc, void* args); void setObjectFactoryFunction(produce_function_t prodFunc, void* args);
template <typename T> template <typename T>
@ -66,6 +71,9 @@ class ObjectManager : public ObjectManagerIF {
*/ */
std::map<object_id_t, SystemObjectIF*> objectList; std::map<object_id_t, SystemObjectIF*> objectList;
static ObjectManager* objManagerInstance; static ObjectManager* objManagerInstance;
// used when the OM itself is deleted to modify behaviour of remove()
// to avoid iterator invalidation and double free
bool teardown = false;
}; };
// Documentation can be found in the class method declaration above // Documentation can be found in the class method declaration above

View File

@ -1,10 +1,13 @@
# Check the OS_FSFW variable # Check the OS_FSFW variable
if(FSFW_OSAL MATCHES "freertos") if(FSFW_OSAL MATCHES "freertos")
add_subdirectory(freertos) add_subdirectory(freertos)
set(FSFW_OSAL_FREERTOS 1)
elseif(FSFW_OSAL MATCHES "rtems") elseif(FSFW_OSAL MATCHES "rtems")
add_subdirectory(rtems) add_subdirectory(rtems)
set(FSFW_OSAL_RTEMS 1)
elseif(FSFW_OSAL MATCHES "linux") elseif(FSFW_OSAL MATCHES "linux")
add_subdirectory(linux) add_subdirectory(linux)
set(FSFW_OSAL_LINUX 1)
elseif(FSFW_OSAL MATCHES "host") elseif(FSFW_OSAL MATCHES "host")
add_subdirectory(host) add_subdirectory(host)
if(WIN32) if(WIN32)
@ -13,18 +16,20 @@ elseif(FSFW_OSAL MATCHES "host")
# We still need to pull in some Linux specific sources # We still need to pull in some Linux specific sources
target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp) target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp)
endif() endif()
set(FSFW_OSAL_HOST 1)
else() else()
message( message(
WARNING WARNING
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..") "${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
# Not set. Assumuing this is a host build, try to determine host OS # Not set. Assumuing this is a host build, try to determine host OS
if(WIN32) if(WIN32)
add_subdirectory(host) add_subdirectory(host)
add_subdirectory(windows) add_subdirectory(windows)
set(FSFW_OSAL_HOST 1)
elseif(UNIX) elseif(UNIX)
add_subdirectory(linux) add_subdirectory(linux)
set(FSFW_OSAL_LINUX 1)
else() else()
# MacOS or other OSes have not been tested yet / are not supported. # MacOS or other OSes have not been tested yet / are not supported.
message(FATAL_ERROR "The host OS could not be determined! Aborting.") message(FATAL_ERROR "The host OS could not be determined! Aborting.")
@ -33,3 +38,5 @@ else()
endif() endif()
add_subdirectory(common) add_subdirectory(common)
configure_file(osal.h.in ${CMAKE_BINARY_DIR}/fsfw/osal/osal.h)

View File

@ -26,12 +26,12 @@
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
size_t receptionBufferSize, size_t ringBufferSize, TcpTmTcServer::TcpConfig cfg, size_t receptionBufferSize,
std::string customTcpServerPort, ReceptionModes receptionMode) size_t ringBufferSize, ReceptionModes receptionMode)
: SystemObject(objectId), : SystemObject(objectId),
tmtcBridgeId(tmtcTcpBridge), tmtcBridgeId(tmtcTcpBridge),
receptionMode(receptionMode), receptionMode(receptionMode),
tcpConfig(std::move(customTcpServerPort)), tcpConfig(cfg),
receptionBuffer(receptionBufferSize), receptionBuffer(receptionBufferSize),
ringBuffer(ringBufferSize, true) {} ringBuffer(ringBufferSize, true) {}
@ -91,6 +91,15 @@ ReturnValue_t TcpTmTcServer::initialize() {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
if (tcpConfig.reuseAddr) {
unsigned int enable = 1;
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
}
if (tcpConfig.reusePort) {
unsigned int enable = 1;
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
}
// Bind to the address found by getaddrinfo // Bind to the address found by getaddrinfo
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen)); retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
if (retval == SOCKET_ERROR) { if (retval == SOCKET_ERROR) {

View File

@ -41,11 +41,11 @@ class SpacePacketParser;
*/ */
class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableObjectIF { class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableObjectIF {
public: public:
enum class ReceptionModes { SPACE_PACKETS };
struct TcpConfig { struct TcpConfig {
public: public:
explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {} TcpConfig(bool reuseAddr, bool reusePort) : reuseAddr(reuseAddr), reusePort(reusePort) {}
TcpConfig(std::string tcpPort, bool reuseAddr, bool reusePort)
: tcpPort(std::move(tcpPort)), reuseAddr(reuseAddr), reusePort(reusePort) {}
/** /**
* Passed to the recv call * Passed to the recv call
@ -63,9 +63,25 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
*/ */
int tcpTmFlags = 0; int tcpTmFlags = 0;
const std::string tcpPort; std::string tcpPort = DEFAULT_SERVER_PORT;
/**
* Sets the SO_REUSEADDR option on the socket. See
* https://man7.org/linux/man-pages/man7/socket.7.html for more details. This option is
* especially useful in a debugging and development environment where an OBSW image might be
* re-flashed oftentimes and where all incoming telecommands are received on a dedicated TCP
* port.
*/
bool reuseAddr = false;
/**
* Sets the SO_REUSEPORT option on the socket. See
* https://man7.org/linux/man-pages/man7/socket.7.html for more details.
*/
bool reusePort = false;
}; };
enum class ReceptionModes { SPACE_PACKETS };
static const std::string DEFAULT_SERVER_PORT; static const std::string DEFAULT_SERVER_PORT;
static constexpr size_t ETHERNET_MTU_SIZE = 1500; static constexpr size_t ETHERNET_MTU_SIZE = 1500;
@ -80,10 +96,9 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
* size will be the Ethernet MTU size * size will be the Ethernet MTU size
* @param customTcpServerPort The user can specify another port than the default (7301) here. * @param customTcpServerPort The user can specify another port than the default (7301) here.
*/ */
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer::TcpConfig cfg,
size_t receptionBufferSize = RING_BUFFER_SIZE, size_t receptionBufferSize = RING_BUFFER_SIZE,
size_t ringBufferSize = RING_BUFFER_SIZE, size_t ringBufferSize = RING_BUFFER_SIZE,
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS); ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
~TcpTmTcServer() override; ~TcpTmTcServer() override;

View File

@ -21,7 +21,7 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs*
attributes.mq_msgsize = maxMessageSize; attributes.mq_msgsize = maxMessageSize;
attributes.mq_flags = 0; // Flags are ignored on Linux during mq_open attributes.mq_flags = 0; // Flags are ignored on Linux during mq_open
// Set the name of the queue. The slash is mandatory! // Set the name of the queue. The slash is mandatory!
sprintf(name, "/FSFW_MQ%u\n", queueCounter++); sprintf(name, "/FSFW_MQ%u", queueCounter++);
// Create a nonblocking queue if the name is available (the queue is read // Create a nonblocking queue if the name is available (the queue is read
// and writable for the owner as well as the group) // and writable for the owner as well as the group)

36
src/fsfw/osal/osal.h.in Normal file
View File

@ -0,0 +1,36 @@
#pragma once
namespace osal {
enum osalTarget{
HOST,
LINUX,
WINDOWS,
FREERTOS,
RTEMS,
};
#cmakedefine FSFW_OSAL_HOST
#cmakedefine FSFW_OSAL_LINUX
#cmakedefine FSFW_OSAL_WINDOWS
#cmakedefine FSFW_OSAL_FREERTOS
#cmakedefine FSFW_OSAL_RTEMS
constexpr osalTarget getTarget() {
#ifdef FSFW_OSAL_HOST
return HOST;
#endif
#ifdef FSFW_OSAL_LINUX
return LINUX;
#endif
#ifdef FSFW_OSAL_WINDOWS
return WINDOWS;
#endif
#ifdef FSFW_OSAL_FREERTOS
return FREERTOS;
#endif
#ifdef FSFW_OSAL_RTEMS
return RTEMS;
#endif
}
};

View File

@ -9,4 +9,4 @@ target_sources(
Service17Test.cpp Service17Test.cpp
Service20ParameterManagement.cpp Service20ParameterManagement.cpp
CService200ModeCommanding.cpp CService200ModeCommanding.cpp
CService201HealthCommanding.cpp) CServiceHealthCommanding.cpp)

View File

@ -1,106 +0,0 @@
#include "fsfw/pus/CService201HealthCommanding.h"
#include "fsfw/health/HasHealthIF.h"
#include "fsfw/health/HealthMessage.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/pus/servicepackets/Service201Packets.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, uint16_t apid,
uint8_t serviceId,
uint8_t numParallelCommands,
uint16_t commandTimeoutSeconds)
: CommandingServiceBase(objectId, apid, "PUS 201 Health MGMT", serviceId, numParallelCommands,
commandTimeoutSeconds) {}
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
return returnvalue::OK;
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Invalid Subservice" << std::endl;
#endif
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
}
}
ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subservice,
const uint8_t *tcData,
size_t tcDataLen,
MessageQueueId_t *id,
object_id_t *objectId) {
if (tcDataLen < sizeof(object_id_t)) {
return CommandingServiceBase::INVALID_TC;
}
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
return checkInterfaceAndAcquireMessageQueue(id, objectId);
}
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
if (destination == nullptr) {
return CommandingServiceBase::INVALID_OBJECT;
}
*messageQueueToSet = destination->getCommandQueue();
return returnvalue::OK;
}
ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *message,
uint8_t subservice, const uint8_t *tcData,
size_t tcDataLen, uint32_t *state,
object_id_t objectId) {
ReturnValue_t result = returnvalue::OK;
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH): {
HealthSetCommand healthCommand;
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
if (result != returnvalue::OK) {
break;
}
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
healthCommand.getHealth());
break;
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
break;
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
break;
}
default: {
// Should never happen, subservice was already checked
result = returnvalue::FAILED;
}
}
return result;
}
ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *reply,
Command_t previousCommand, uint32_t *state,
CommandMessage *optionalNextCommand,
object_id_t objectId, bool *isStep) {
Command_t replyId = reply->getCommand();
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
return EXECUTION_COMPLETE;
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
return reply->getReplyRejectedReason();
}
return CommandingServiceBase::INVALID_REPLY;
}
// Not used for now, health state already reported by event
[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(
const CommandMessage *reply) {
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
HealthSetReply healthSetReply(health, oldHealth);
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
}

View File

@ -0,0 +1,152 @@
#include <fsfw/events/EventManagerIF.h>
#include <fsfw/pus/CServiceHealthCommanding.h>
#include "fsfw/health/HasHealthIF.h"
#include "fsfw/health/HealthMessage.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/pus/servicepackets/Service201Packets.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args)
: CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service,
args.numParallelCommands, args.commandTimeoutSeconds),
healthTable(args.table),
maxNumHealthInfoPerCycle(args.maxNumHealthInfoPerCycle) {}
ReturnValue_t CServiceHealthCommanding::isValidSubservice(uint8_t subservice) {
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
return returnvalue::OK;
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Invalid Subservice" << std::endl;
#endif
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
}
}
ReturnValue_t CServiceHealthCommanding::getMessageQueueAndObject(uint8_t subservice,
const uint8_t *tcData,
size_t tcDataLen,
MessageQueueId_t *id,
object_id_t *objectId) {
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
if (tcDataLen < sizeof(object_id_t)) {
return CommandingServiceBase::INVALID_TC;
}
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
return checkInterfaceAndAcquireMessageQueue(id, objectId);
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
return returnvalue::OK;
}
default: {
return returnvalue::FAILED;
}
}
}
ReturnValue_t CServiceHealthCommanding::checkInterfaceAndAcquireMessageQueue(
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
if (destination == nullptr) {
return CommandingServiceBase::INVALID_OBJECT;
}
*messageQueueToSet = destination->getCommandQueue();
return returnvalue::OK;
}
ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
const uint8_t *tcData, size_t tcDataLen,
uint32_t *state, object_id_t objectId) {
ReturnValue_t result = returnvalue::OK;
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH): {
HealthSetCommand healthCommand;
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
if (result != returnvalue::OK) {
break;
}
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
healthCommand.getHealth());
break;
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
break;
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
ReturnValue_t result = iterateHealthTable(true);
if (result == returnvalue::OK) {
reportAllHealth = true;
return EXECUTION_COMPLETE;
}
return result;
while (true) {
ReturnValue_t result = iterateHealthTable(false);
if (result != returnvalue::OK) {
break;
}
}
return returnvalue::OK;
}
default: {
// Should never happen, subservice was already checked
result = returnvalue::FAILED;
}
}
return result;
}
ReturnValue_t CServiceHealthCommanding::handleReply(const CommandMessage *reply,
Command_t previousCommand, uint32_t *state,
CommandMessage *optionalNextCommand,
object_id_t objectId, bool *isStep) {
Command_t replyId = reply->getCommand();
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
return EXECUTION_COMPLETE;
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
return reply->getReplyRejectedReason();
}
return CommandingServiceBase::INVALID_REPLY;
}
void CServiceHealthCommanding::doPeriodicOperation() {
if (reportAllHealth) {
for (uint8_t i = 0; i < maxNumHealthInfoPerCycle; i++) {
ReturnValue_t result = iterateHealthTable(false);
if (result != returnvalue::OK) {
reportAllHealth = false;
break;
}
}
}
}
// Not used for now, health state already reported by event
[[maybe_unused]] ReturnValue_t CServiceHealthCommanding::prepareHealthSetReply(
const CommandMessage *reply) {
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
HealthSetReply healthSetReply(health, oldHealth);
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
}
ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) {
std::pair<object_id_t, HasHealthIF::HealthState> pair;
ReturnValue_t result = healthTable.iterate(&pair, reset);
if (result != returnvalue::OK) {
return result;
} else {
EventManagerIF::triggerEvent(pair.first, HasHealthIF::HEALTH_INFO, pair.second, pair.second);
return returnvalue::OK;
}
}

View File

@ -1,8 +1,26 @@
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ #ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ #define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
#include <fsfw/health/HealthTable.h>
#include "fsfw/tmtcservices/CommandingServiceBase.h" #include "fsfw/tmtcservices/CommandingServiceBase.h"
struct HealthServiceCfg {
HealthServiceCfg(object_id_t objectId, uint16_t apid, HealthTable &healthTable,
uint16_t maxNumHealthInfoPerCycle)
: objectId(objectId),
apid(apid),
table(healthTable),
maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {}
object_id_t objectId;
uint16_t apid;
HealthTable &table;
uint16_t maxNumHealthInfoPerCycle;
uint8_t service = 201;
uint8_t numParallelCommands = 4;
uint16_t commandTimeoutSeconds = 60;
};
/** /**
* @brief Custom PUS service to set health of all objects * @brief Custom PUS service to set health of all objects
* implementing hasHealthIF. * implementing hasHealthIF.
@ -17,11 +35,10 @@
* child class like this service * child class like this service
* *
*/ */
class CService201HealthCommanding : public CommandingServiceBase { class CServiceHealthCommanding : public CommandingServiceBase {
public: public:
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId, CServiceHealthCommanding(HealthServiceCfg args);
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60); ~CServiceHealthCommanding() override = default;
~CService201HealthCommanding() override = default;
protected: protected:
/* CSB abstract function implementations */ /* CSB abstract function implementations */
@ -37,7 +54,13 @@ class CService201HealthCommanding : public CommandingServiceBase {
CommandMessage *optionalNextCommand, object_id_t objectId, CommandMessage *optionalNextCommand, object_id_t objectId,
bool *isStep) override; bool *isStep) override;
void doPeriodicOperation() override;
private: private:
HealthTable &healthTable;
uint16_t maxNumHealthInfoPerCycle = 0;
bool reportAllHealth = false;
ReturnValue_t iterateHealthTable(bool reset);
static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet, static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
const object_id_t *objectId); const object_id_t *objectId);

View File

@ -41,6 +41,8 @@ class Service11TelecommandScheduling final : public PusServiceBase {
static constexpr ReturnValue_t INVALID_TIME_WINDOW = returnvalue::makeCode(CLASS_ID, 2); static constexpr ReturnValue_t INVALID_TIME_WINDOW = returnvalue::makeCode(CLASS_ID, 2);
static constexpr ReturnValue_t TIMESHIFTING_NOT_POSSIBLE = returnvalue::makeCode(CLASS_ID, 3); static constexpr ReturnValue_t TIMESHIFTING_NOT_POSSIBLE = returnvalue::makeCode(CLASS_ID, 3);
static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4); static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4);
static constexpr ReturnValue_t CONTAINED_TC_TOO_SMALL = returnvalue::makeCode(CLASS_ID, 5);
static constexpr ReturnValue_t CONTAINED_TC_CRC_MISSMATCH = returnvalue::makeCode(CLASS_ID, 6);
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11;

View File

@ -2,9 +2,11 @@
#include <cstddef> #include <cstddef>
#include "fsfw/globalfunctions/CRC.h"
#include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serialize/SerializeAdapter.h" #include "fsfw/serialize/SerializeAdapter.h"
#include "fsfw/serviceinterface.h" #include "fsfw/serviceinterface.h"
#include "fsfw/tmtcpacket/pus/tc/PusTcIF.h"
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" #include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
static constexpr auto DEF_END = SerializeIF::Endianness::BIG; static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
@ -171,6 +173,14 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivi
return returnvalue::FAILED; return returnvalue::FAILED;
} }
if (size < PusTcIF::MIN_SIZE) {
return CONTAINED_TC_TOO_SMALL;
}
if (CRC::crc16ccitt(data, size) != 0) {
return CONTAINED_TC_CRC_MISSMATCH;
}
// store currentPacket and receive the store address // store currentPacket and receive the store address
store_address_t addr{}; store_address_t addr{};
if (tcStore->addData(&addr, data, size) != returnvalue::OK || if (tcStore->addData(&addr, data, size) != returnvalue::OK ||

View File

@ -69,14 +69,14 @@ ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire" sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire"
<< "MessageQueue: Can't access object" << std::endl; << "MessageQueue: Can't access object" << std::endl;
sif::error << "Object ID: " << std::hex << objectId << std::dec << std::endl; sif::error << "Object ID: 0x" << std::hex << *objectId << std::dec << std::endl;
sif::error << "Make sure it implements ReceivesParameterMessagesIF!" << std::endl; sif::error << "Make sure it implements ReceivesParameterMessagesIF" << std::endl;
#else #else
sif::printError( sif::printError(
"Service20ParameterManagement::checkInterfaceAndAcquire" "Service20ParameterManagement::checkInterfaceAndAcquire"
"MessageQueue: Can't access object\n"); "MessageQueue: Can't access object\n");
sif::printError("Object ID: 0x%08x\n", *objectId); sif::printError("Object ID: 0x%08x\n", *objectId);
sif::printError("Make sure it implements ReceivesParameterMessagesIF!\n"); sif::printError("Make sure it implements ReceivesParameterMessagesIF\n");
#endif #endif
return CommandingServiceBase::INVALID_OBJECT; return CommandingServiceBase::INVALID_OBJECT;

View File

@ -1,5 +1,7 @@
#include "fsfw/pus/Service9TimeManagement.h" #include "fsfw/pus/Service9TimeManagement.h"
#include <cmath>
#include "fsfw/events/EventManagerIF.h" #include "fsfw/events/EventManagerIF.h"
#include "fsfw/pus/servicepackets/Service9Packets.h" #include "fsfw/pus/servicepackets/Service9Packets.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
@ -15,9 +17,17 @@ ReturnValue_t Service9TimeManagement::performService() { return returnvalue::OK;
ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) { ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) {
switch (subservice) { switch (subservice) {
case SUBSERVICE::SET_TIME: { case Subservice::SET_TIME: {
return setTime(); return setTime();
} }
case Subservice::DUMP_TIME: {
timeval newTime;
Clock::getClock_timeval(&newTime);
uint32_t subsecondMs =
static_cast<uint32_t>(std::floor(static_cast<double>(newTime.tv_usec) / 1000.0));
triggerEvent(CLOCK_DUMP, newTime.tv_sec, subsecondMs);
return returnvalue::OK;
}
default: default:
return AcceptsTelecommandsIF::INVALID_SUBSERVICE; return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
} }
@ -33,14 +43,14 @@ ReturnValue_t Service9TimeManagement::setTime() {
return result; return result;
} }
uint32_t formerUptime; timeval time;
Clock::getUptime(&formerUptime); Clock::getClock_timeval(&time);
result = Clock::setClock(&timeToSet); result = Clock::setClock(&timeToSet);
if (result == returnvalue::OK) { if (result == returnvalue::OK) {
uint32_t newUptime; timeval newTime;
Clock::getUptime(&newUptime); Clock::getClock_timeval(&newTime);
triggerEvent(CLOCK_SET, newUptime, formerUptime); triggerEvent(CLOCK_SET, time.tv_sec, newTime.tv_sec);
return returnvalue::OK; return returnvalue::OK;
} else { } else {
triggerEvent(CLOCK_SET_FAILURE, result, 0); triggerEvent(CLOCK_SET_FAILURE, result, 0);

View File

@ -6,10 +6,13 @@
class Service9TimeManagement : public PusServiceBase { class Service9TimeManagement : public PusServiceBase {
public: public:
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
//!< Clock has been set. P1: New Uptime. P2: Old Uptime
//!< Clock has been set. P1: old timeval seconds. P2: new timeval seconds.
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO); static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
//!< Clock dump event. P1: timeval seconds P2: timeval milliseconds.
static constexpr Event CLOCK_DUMP = MAKE_EVENT(1, severity::INFO);
//!< Clock could not be set. P1: Returncode. //!< Clock could not be set. P1: Returncode.
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, severity::LOW); static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(2, severity::LOW);
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9; static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
@ -30,8 +33,9 @@ class Service9TimeManagement : public PusServiceBase {
virtual ReturnValue_t setTime(); virtual ReturnValue_t setTime();
private: private:
enum SUBSERVICE { enum Subservice {
SET_TIME = 128 //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format SET_TIME = 128, //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format
DUMP_TIME = 129,
}; };
}; };

View File

@ -195,7 +195,7 @@ ReturnValue_t SubsystemBase::checkTable(HybridIterator<ModeListEntry> tableIter)
if (childrenMap.find(tableIter.value->getObject()) == childrenMap.end()) { if (childrenMap.find(tableIter.value->getObject()) == childrenMap.end()) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
using namespace std; using namespace std;
sif::warning << "SubsystemBase::checkTable: Could not find Object " << setfill('0') << hex sif::warning << "SubsystemBase::checkTable: Could not find object " << setfill('0') << hex
<< "0x" << setw(8) << tableIter.value->getObject() << " in object " << setw(8) << "0x" << setw(8) << tableIter.value->getObject() << " in object " << setw(8)
<< setw(0) << "0x" << setw(8) << SystemObject::getObjectId() << dec << std::endl; << setw(0) << "0x" << setw(8) << SystemObject::getObjectId() << dec << std::endl;
#endif #endif
@ -284,7 +284,7 @@ ReturnValue_t SubsystemBase::setHealth(HealthState health) {
HasHealthIF::HealthState SubsystemBase::getHealth() { return healthHelper.getHealth(); } HasHealthIF::HealthState SubsystemBase::getHealth() { return healthHelper.getHealth(); }
ReturnValue_t SubsystemBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) { ReturnValue_t SubsystemBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
return modetree::connectModeTreeParent(parent, *this, healthHelper, modeHelper); return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
} }
object_id_t SubsystemBase::getObjectId() const { return SystemObject::getObjectId(); } object_id_t SubsystemBase::getObjectId() const { return SystemObject::getObjectId(); }

View File

@ -2,12 +2,14 @@
ReturnValue_t modetree::connectModeTreeParent(HasModeTreeChildrenIF& parent, ReturnValue_t modetree::connectModeTreeParent(HasModeTreeChildrenIF& parent,
const ModeTreeChildIF& child, const ModeTreeChildIF& child,
HealthHelper& healthHelper, ModeHelper& modeHelper) { HealthHelper* healthHelper, ModeHelper& modeHelper) {
ReturnValue_t result = parent.registerChild(child); ReturnValue_t result = parent.registerChild(child);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
healthHelper.setParentQueue(parent.getCommandQueue()); if (healthHelper != nullptr) {
healthHelper->setParentQueue(parent.getCommandQueue());
}
modeHelper.setParentQueue(parent.getCommandQueue()); modeHelper.setParentQueue(parent.getCommandQueue());
return returnvalue::OK; return returnvalue::OK;
} }

View File

@ -7,7 +7,7 @@
namespace modetree { namespace modetree {
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent, const ModeTreeChildIF& child, ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent, const ModeTreeChildIF& child,
HealthHelper& healthHelper, ModeHelper& modeHelper); HealthHelper* healthHelper, ModeHelper& modeHelper);
} }

View File

@ -100,5 +100,6 @@ ReturnValue_t PusTcCreator::setSerializableUserData(const SerializeIF &serializa
void PusTcCreator::setup() { void PusTcCreator::setup() {
spCreator.setPacketType(ccsds::PacketType::TC); spCreator.setPacketType(ccsds::PacketType::TC);
spCreator.setSecHeaderFlag(); spCreator.setSecHeaderFlag();
spCreator.setSeqFlags(ccsds::SequenceFlags::UNSEGMENTED);
updateSpLengthField(); updateSpLengthField();
} }

View File

@ -119,6 +119,7 @@ void PusTmCreator::setup() {
updateSpLengthField(); updateSpLengthField();
spCreator.setPacketType(ccsds::PacketType::TM); spCreator.setPacketType(ccsds::PacketType::TM);
spCreator.setSecHeaderFlag(); spCreator.setSecHeaderFlag();
spCreator.setSeqFlags(ccsds::SequenceFlags::UNSEGMENTED);
} }
void PusTmCreator::setMessageTypeCounter(uint16_t messageTypeCounter) { void PusTmCreator::setMessageTypeCounter(uint16_t messageTypeCounter) {

View File

@ -325,12 +325,12 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
// trickery here to calculate the raw values first // trickery here to calculate the raw values first
int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8; int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8;
int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8; int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8;
int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[3] << 8)) >> 8; int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[9] << 8)) >> 8;
// Now scale to physical value in microtesla // Now scale to physical value in microtesla
float fieldStrengthX = fieldStrengthRawX * scaleFactorX; float fieldStrengthX = fieldStrengthRawX * scaleFactorX;
float fieldStrengthY = fieldStrengthRawY * scaleFactorX; float fieldStrengthY = fieldStrengthRawY * scaleFactorY;
float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX; float fieldStrengthZ = fieldStrengthRawZ * scaleFactorZ;
if (periodicPrintout) { if (periodicPrintout) {
if (debugDivider.checkAndIncrement()) { if (debugDivider.checkAndIncrement()) {

View File

@ -109,14 +109,17 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s
} }
if (write(fd, sendData, sendLen) != static_cast<int>(sendLen)) { if (write(fd, sendData, sendLen) != static_cast<int>(sendLen)) {
i2cCookie->errorCounter++;
if (i2cCookie->errorCounter < 3) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "I2cComIF::sendMessage: Failed to send data to I2C " sif::error << "I2cComIF::sendMessage: Failed to send data to I2C "
"device with error code " "device with error code "
<< errno << ". Error description: " << strerror(errno) << std::endl; << errno << ". Error description: " << strerror(errno) << std::endl;
#endif #endif
}
return returnvalue::FAILED; return returnvalue::FAILED;
} }
i2cCookie->errorCounter = 0;
#if FSFW_HAL_I2C_WIRETAPPING == 1 #if FSFW_HAL_I2C_WIRETAPPING == 1
sif::info << "Sent I2C data to bus " << deviceFile << ":" << std::endl; sif::info << "Sent I2C data to bus " << deviceFile << ":" << std::endl;
arrayprinter::print(sendData, sendLen); arrayprinter::print(sendData, sendLen);
@ -180,10 +183,6 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
} }
#else #else
#endif #endif
#endif
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "I2cComIF::requestReceiveMessage: Read " << readLen << " of " << requestLen
<< " bytes" << std::endl;
#endif #endif
return returnvalue::FAILED; return returnvalue::FAILED;
} }

View File

@ -27,6 +27,8 @@ class I2cCookie : public CookieIF {
size_t getMaxReplyLen() const; size_t getMaxReplyLen() const;
std::string getDeviceFile() const; std::string getDeviceFile() const;
uint8_t errorCounter = 0;
private: private:
address_t i2cAddress = 0; address_t i2cAddress = 0;
size_t maxReplyLen = 0; size_t maxReplyLen = 0;

View File

@ -31,4 +31,7 @@ int customSetup() {
return 0; return 0;
} }
int customTeardown() { return 0; } int customTeardown() {
ObjectManager::clear();
return 0;
}

View File

@ -9,7 +9,9 @@ DeviceHandlerCommander::DeviceHandlerCommander(object_id_t objectId)
QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
} }
DeviceHandlerCommander::~DeviceHandlerCommander() {} DeviceHandlerCommander::~DeviceHandlerCommander() {
QueueFactory::instance()->deleteMessageQueue(commandQueue);
}
ReturnValue_t DeviceHandlerCommander::performOperation(uint8_t operationCode) { ReturnValue_t DeviceHandlerCommander::performOperation(uint8_t operationCode) {
readCommandQueue(); readCommandQueue();

View File

@ -1,46 +1,38 @@
#include <fsfw/osal/osal.h>
#ifdef LINUX
/*
#include <fsfw/tasks/SemaphoreFactory.h> #include <fsfw/tasks/SemaphoreFactory.h>
#include <fsfw/timemanager/Stopwatch.h> #include <fsfw/timemanager/Stopwatch.h>
#include "catch.hpp" #include <catch2/catch_test_macros.hpp>
#include "core/CatchDefinitions.h"
TEST_CASE("Binary Semaphore Test" , "[BinSemaphore]") { // binary semaphores currently only supported on linux
//perform set-up here #ifdef FSFW_OSAL_LINUX
SemaphoreIF* binSemaph = SemaphoreFactory::instance()->
createBinarySemaphore(); TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") {
REQUIRE(binSemaph != nullptr); // perform set-up here
SECTION("Simple Test") { SemaphoreIF* binSemaph = SemaphoreFactory::instance()->createBinarySemaphore();
// set-up is run for each section REQUIRE(binSemaph != nullptr);
REQUIRE(binSemaph->getSemaphoreCounter() == 1); SECTION("Simple Test") {
REQUIRE(binSemaph->release() == // set-up is run for each section
static_cast<int>(SemaphoreIF::SEMAPHORE_NOT_OWNED)); REQUIRE(binSemaph->getSemaphoreCounter() == 1);
REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == REQUIRE(binSemaph->release() == static_cast<int>(SemaphoreIF::SEMAPHORE_NOT_OWNED));
returnvalue::OK); REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == returnvalue::OK);
{ {
// not precise enough on linux.. should use clock instead.. // not precise enough on linux.. should use clock instead..
//Stopwatch stopwatch(false); // Stopwatch stopwatch(false);
//REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) == // REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) ==
// SemaphoreIF::SEMAPHORE_TIMEOUT); // SemaphoreIF::SEMAPHORE_TIMEOUT);
//dur_millis_t time = stopwatch.stop(); // dur_millis_t time = stopwatch.stop();
//CHECK(time == 5); // CHECK(time == 5);
} }
REQUIRE(binSemaph->getSemaphoreCounter() == 0); REQUIRE(binSemaph->getSemaphoreCounter() == 0);
REQUIRE(binSemaph->release() == returnvalue::OK); REQUIRE(binSemaph->release() == returnvalue::OK);
} }
SemaphoreFactory::instance()->deleteSemaphore(binSemaph); SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
// perform tear-down here // perform tear-down here
} }
TEST_CASE("Counting Semaphore Test", "[CountingSemaph]") {
TEST_CASE("Counting Semaphore Test" , "[CountingSemaph]") { SECTION("Simple Test") {}
SECTION("Simple Test") {
}
} }
*/
#endif #endif

View File

@ -7,7 +7,7 @@
namespace addresses { namespace addresses {
/* Logical addresses have uint32_t datatype */ /* Logical addresses have uint32_t datatype */
enum logicalAddresses : address_t {}; enum LogicAddress : address_t {};
} // namespace addresses } // namespace addresses
#endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */ #endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */