Merge remote-tracking branch 'upstream/development' into mode_service_fixes
This commit is contained in:
commit
a419806a05
11
CHANGELOG.md
11
CHANGELOG.md
@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
|
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
|
||||||
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
|
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
|
||||||
subservice not working properly.
|
subservice not working properly.
|
||||||
|
- `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
|
||||||
|
- 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
|
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
|
||||||
to false correctly because the `read` and `write` calls were missing.
|
to false correctly because the `read` and `write` calls were missing.
|
||||||
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
|
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
|
||||||
@ -35,6 +41,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## 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.
|
||||||
|
56
automation/Jenkinsfile
vendored
56
automation/Jenkinsfile
vendored
@ -1,48 +1,90 @@
|
|||||||
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('Host') {
|
||||||
|
stages{
|
||||||
stage('Clean') {
|
stage('Clean') {
|
||||||
steps {
|
steps {
|
||||||
sh 'rm -rf $BUILDDIR'
|
sh 'rm -rf $BUILDDIR_HOST'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Configure') {
|
stage('Configure') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_HOST) {
|
||||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Build') {
|
stage('Build') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_HOST) {
|
||||||
sh 'cmake --build . -j4'
|
sh 'cmake --build . -j4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Unittests') {
|
stage('Unittests') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_HOST) {
|
||||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Valgrind') {
|
stage('Valgrind') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_HOST) {
|
||||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Linux') {
|
||||||
|
stages{
|
||||||
|
stage('Clean') {
|
||||||
|
steps {
|
||||||
|
sh 'rm -rf $BUILDDIR_LINUX'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Configure') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'cmake --build . -j4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Documentation') {
|
stage('Documentation') {
|
||||||
when {
|
when {
|
||||||
branch 'development'
|
branch 'development'
|
||||||
|
@ -23,6 +23,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);
|
||||||
}
|
}
|
||||||
@ -61,9 +62,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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -23,7 +23,7 @@ FailureIsolationBase::~FailureIsolationBase() {
|
|||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId);
|
manager->unregisterListener(eventQueue->getId());
|
||||||
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,14 +7,17 @@
|
|||||||
|
|
||||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
||||||
: SystemObject(setObjectId),
|
: SystemObject(setObjectId),
|
||||||
commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,16 +16,17 @@ 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(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
|
message(WARNING "The OS_FSFW 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.")
|
||||||
@ -31,3 +35,5 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(common)
|
add_subdirectory(common)
|
||||||
|
|
||||||
|
configure_file(osal.h.in ${CMAKE_BINARY_DIR}/fsfw/osal/osal.h)
|
||||||
|
@ -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) {
|
||||||
|
@ -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,8 +63,24 @@ 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;
|
||||||
|
|
||||||
@ -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;
|
||||||
|
|
||||||
|
@ -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
36
src/fsfw/osal/osal.h.in
Normal 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
|
||||||
|
}
|
||||||
|
};
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
static constexpr Event CLOCK_SET =
|
|
||||||
MAKE_EVENT(0, severity::INFO); //!< 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_FAILURE =
|
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
|
||||||
MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode.
|
//!< 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.
|
||||||
|
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,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -329,8 +329,8 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
|
|||||||
|
|
||||||
// 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()) {
|
||||||
|
@ -180,10 +180,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;
|
||||||
}
|
}
|
||||||
|
@ -31,4 +31,7 @@ int customSetup() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int customTeardown() { return 0; }
|
int customTeardown() {
|
||||||
|
ObjectManager::clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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]") {
|
||||||
|
// perform set-up here
|
||||||
|
SemaphoreIF* binSemaph = SemaphoreFactory::instance()->createBinarySemaphore();
|
||||||
REQUIRE(binSemaph != nullptr);
|
REQUIRE(binSemaph != nullptr);
|
||||||
SECTION("Simple Test") {
|
SECTION("Simple Test") {
|
||||||
// set-up is run for each section
|
// set-up is run for each section
|
||||||
REQUIRE(binSemaph->getSemaphoreCounter() == 1);
|
REQUIRE(binSemaph->getSemaphoreCounter() == 1);
|
||||||
REQUIRE(binSemaph->release() ==
|
REQUIRE(binSemaph->release() == static_cast<int>(SemaphoreIF::SEMAPHORE_NOT_OWNED));
|
||||||
static_cast<int>(SemaphoreIF::SEMAPHORE_NOT_OWNED));
|
REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == returnvalue::OK);
|
||||||
REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) ==
|
|
||||||
result::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() == result::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
|
Loading…
Reference in New Issue
Block a user