Compare commits

...

80 Commits

Author SHA1 Message Date
b8d2fa530b release check helper 2023-02-09 17:00:44 +01:00
0a9c563bbc format 2023-02-09 15:58:48 +01:00
fa7675897d Merge pull request 'Mode Service Bugfixes' (#736) from eive/fsfw:mode_service_fixes into development
Reviewed-on: fsfw/fsfw#736
2023-02-09 15:56:26 +01:00
3a2393885f more style 2023-02-09 15:44:39 +01:00
c752b6d143 Merge pull request 'Generic TMTC Bridge Update' (#734) from eive/fsfw:tmtcbridge_tweaks into development
Reviewed-on: fsfw/fsfw#734
2023-02-09 15:37:35 +01:00
b676040c7c Merge pull request 'CMakeLists file updates' (#731) from eive/fsfw:cmakelists_update into development
Reviewed-on: fsfw/fsfw#731
2023-02-09 15:29:46 +01:00
010509efb4 removed unneeded find_package parameter for etl 2023-02-09 13:50:16 +01:00
dfb1633f00 Merge branch 'development' into mode_service_fixes 2023-02-09 13:46:19 +01:00
5f7172e130 Merge pull request 'TCP/IP TMTC bridge memory leak fixes' (#737) from eive/fsfw:possible_tcpip_bridge_fixes into development
Reviewed-on: fsfw/fsfw#737
2023-02-09 12:15:45 +01:00
0c6465cd95 Merge pull request 'time stamper empty ctor' (#730) from eive/fsfw:empty_cds_short_ctor into development
Reviewed-on: fsfw/fsfw#730
2023-02-09 11:45:49 +01:00
f94987c46d Merge pull request 'RM3100 important bugfix' (#733) from eive/fsfw:rm3100_fixes into development
Reviewed-on: fsfw/fsfw#733
2023-02-09 11:41:53 +01:00
1809ce359b Merge pull request 'comment tweak to event parser can read everything' (#732) from eive/fsfw:health_if_update into development
Reviewed-on: fsfw/fsfw#732
2023-02-09 11:39:53 +01:00
8c712441ab Making fetch Catch2 quiet as well. 2023-02-09 11:34:58 +01:00
f1b0ca7cff add PR link 2023-02-08 21:26:37 +01:00
000df85556 bump changelog 2023-02-08 21:24:00 +01:00
1fffcc2229 possiible leak fixes 2023-02-08 21:23:21 +01:00
a419806a05 Merge remote-tracking branch 'upstream/development' into mode_service_fixes 2023-02-08 09:33:13 +01:00
6445debfa1 bump changelog 2023-02-08 09:24:55 +01:00
8014e4adf9 mode service fixes 2023-02-08 09:23:48 +01:00
134d908f26 that stuff is not in upstream yet.. 2023-02-07 12:52:18 +01:00
40a9e12416 1000 is a bit much 2023-02-07 12:47:40 +01:00
f39054edd4 introduce warning switch 2023-02-07 12:45:29 +01:00
5adf89b911 changelog update 2023-02-07 12:41:42 +01:00
c2e6a22dec important bugfix for RM3100 2023-02-07 12:39:43 +01:00
c8e065a713 comment tweak to event parser can read everything 2023-02-07 12:36:42 +01:00
3ed49dbae3 Merge remote-tracking branch 'upstream/development' into empty_cds_short_ctor 2023-02-07 12:24:02 +01:00
4cf52d5dfe Merge pull request 'Time Service 9 update' (#726) from eive/fsfw:updates_fixes_pus_time_service into development
Reviewed-on: fsfw/fsfw#726
2023-02-07 12:19:45 +01:00
539d7aac9e suppress error if ETL is not found 2023-02-07 12:17:03 +01:00
0a23f2c85a correction for printout, add prefix 2023-02-07 12:15:44 +01:00
46230e6c6d Merge remote-tracking branch 'upstream/development' into updates_fixes_pus_time_service 2023-02-07 12:11:29 +01:00
b22d439300 bump changelog 2023-02-07 12:10:11 +01:00
7e7b3bbbc9 time stamper empty ctor 2023-02-07 12:07:41 +01:00
e2b66df72e Merge pull request 'various fixes related to linux Unittests and memory leaks' (#715) from eive/fsfw:unittest_fix_semaphore into development
Reviewed-on: fsfw/fsfw#715
2023-02-06 16:30:37 +01:00
7b828f233a Merge pull request 'I2C Linux: remove duplicate printout' (#718) from eive/fsfw:i2c_remove_duplicate_printout into development
Reviewed-on: fsfw/fsfw#718
2023-02-06 14:54:58 +01:00
c3d1000cd5 Merge branch 'development' into unittest_fix_semaphore 2023-02-06 14:46:45 +01:00
8e0e57714d Merge pull request 'allow using SO_REUSEADDR and SO_REUSEPORT on TCP server' (#722) from eive/fsfw:tcp_server_reuseaddr_reusesocket into development
Reviewed-on: fsfw/fsfw#722
2023-02-06 14:45:40 +01:00
cc9e54ea6b Merge pull request 'improve srv20 error messages' (#723) from eive/fsfw:srv20_error_msgs into development
Reviewed-on: fsfw/fsfw#723
2023-02-06 14:37:26 +01:00
31465a4e0f Merge pull request 'MGM: small tweak, gain factor was always them same' (#724) from eive/fsfw:mgm_handler_small_fix into development
Reviewed-on: fsfw/fsfw#724
2023-02-06 14:36:34 +01:00
c0e5d1eb99 Merge branch 'development' into tcp_server_reuseaddr_reusesocket 2023-02-06 14:34:52 +01:00
3bc5d4a2e0 Merge remote-tracking branch 'upstream/development' into mgm_handler_small_fix 2023-02-06 14:25:33 +01:00
b1e9dd9e4a Merge remote-tracking branch 'upstream/development' into updates_fixes_pus_time_service 2023-02-06 14:24:38 +01:00
ab86599db3 Merge pull request 'Bugfix DHB setNormalDatapoolEntriesInvalid' (#728) from eive/fsfw:bugfix_dhb_set_datapool_entries_invalid into development
Reviewed-on: fsfw/fsfw#728
2023-02-06 14:20:34 +01:00
034eb34c2e small tweak 2023-02-03 16:05:50 +01:00
4374c7c4f4 changelog 2023-02-03 16:01:56 +01:00
5343844be5 bugfix in setNormalDataPoolEntriesInvalid
Do not forget to call read and write to actually update the
validity state
2023-02-03 16:00:55 +01:00
e300490b93 Merge pull request 'Bugfix PUS packet creators Sequence flags' (#727) from eive/fsfw:bugfix_pus_packets_seq_flags into development
Reviewed-on: fsfw/fsfw#727
2023-02-02 17:22:29 +01:00
0f811777a7 changelog update 2023-02-01 20:49:53 +01:00
e93137939e set sequence flags for PUS TMTC to unsegmented 2023-02-01 20:48:26 +01:00
1f88c006d9 update changelog 2023-02-01 18:42:09 +01:00
7e94baceef service 9 update
- fix time info event
- add time dump subservice
2023-02-01 18:39:23 +01:00
9b05e8f274 re-order fields in TcpConfig 2023-01-30 14:24:48 +01:00
eb223dae88 bump changelog 2023-01-30 14:20:28 +01:00
3656662d88 small tweak, gain factory was always them same 2023-01-30 14:18:03 +01:00
fe71978467 improve srv20 error messages 2023-01-30 14:15:37 +01:00
b646717a76 bump changelog 2023-01-30 14:11:00 +01:00
99d8c845f2 allow using SO_REUSEADDR and SO_REUSEPORT on TCP server 2023-01-30 14:07:41 +01:00
0e7c6b117f Merge pull request 'Service 11 TC Scheduler Robustness Improvements' (#720) from service_11_bugfixes into development
Reviewed-on: fsfw/fsfw#720
2023-01-13 13:33:19 +01:00
d16c5024dc small include improvement 2023-01-13 11:15:36 +01:00
a4531e4ced typo 2023-01-13 10:59:39 +01:00
97c629ad84 update changelog 2023-01-13 10:53:36 +01:00
bf12f284fa add size and crc check for contained TC 2023-01-13 10:53:04 +01:00
ba62c28b64 adding linux ci and fixing problems 2023-01-12 15:40:52 +01:00
7adb47aecb remove duplicate printout 2023-01-11 08:45:37 +01:00
8589f4d63a Merge pull request 'updates for source sequence counter' (#714) from eive/fsfw:source_seq_counter_update into development
Reviewed-on: fsfw/fsfw#714
2022-12-19 15:00:28 +01:00
ca80589233 make get const 2022-12-19 14:58:08 +01:00
f2ebaed092 Merge pull request 'vec getter, reset for content' (#716) from eive/fsfw:get_cmd_exec_read_buf into development
Reviewed-on: fsfw/fsfw#716
2022-12-19 14:56:11 +01:00
f0b89e98df Merge pull request 'printout handling improvements' (#717) from eive/fsfw:i2c_printout_improvements into development
Reviewed-on: fsfw/fsfw#717
2022-12-19 14:45:04 +01:00
5557d95994 Merge branch 'development' into i2c_printout_improvements 2022-12-05 14:20:58 +01:00
fc24c9b5d8 Merge branch 'development' into get_cmd_exec_read_buf 2022-12-05 14:20:52 +01:00
7ef69c839c Merge pull request 'small fix to allow teardown handling' (#713) from eive/fsfw:mueller/shutdown_for_failed_to_on_transition into development
Reviewed-on: fsfw/fsfw#713
2022-11-28 14:30:15 +01:00
9b798d798e Merge pull request 'DLE parser' (#711) from eive/fsfw:mueller/dle_parser into development
Reviewed-on: fsfw/fsfw#711
2022-11-28 14:13:18 +01:00
b13453f46b vec getter, reset for content 2022-11-28 08:43:54 +01:00
d0e322d7e2 printout handling improvements 2022-11-28 08:42:08 +01:00
ecde164f68 updates for source sequence counter 2022-11-28 08:30:45 +01:00
50930b41ba Merge remote-tracking branch 'upstream/development' into mueller/dle_parser 2022-11-28 08:27:24 +01:00
bf4ca56658 Merge branch 'development' into mueller/shutdown_for_failed_to_on_transition 2022-11-21 15:29:11 +01:00
16ffa00155 Merge branch 'development' into mueller/dle_parser 2022-11-21 15:28:34 +01:00
f05295bada small fix to allow teardown handling 2022-11-17 15:16:29 +01:00
8199b8f359 bump changelog 2022-11-15 11:45:39 +01:00
9483c2809d DLE parser 2022-11-15 11:26:53 +01:00
49 changed files with 840 additions and 188 deletions

View File

@ -8,13 +8,36 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased] # [unreleased]
# [v6.0.0] # [v6.0.0] 2023-02-10
## Fixes ## Fixes
- `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
subservice not working properly.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/736
- Memory leak fixes for the TCP/IP TMTC bridge.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737
- `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
- HAL MGM3100 Handler: Z value was previously calculated with bytes of the X value.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/733
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
to false correctly because the `read` and `write` calls were missing.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/728
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
of the correct unsegmented flags (0b11) as specified in the standard.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/727
- TC Scheduler Service 11: Add size and CRC check for contained TC.
Bug: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/719
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/720
- 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
- I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator. - I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator.
Also properly reset the reply size for successfull transfers and erroneous transfers. Also properly reset the reply size for successfull transfers and erroneous transfers.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
@ -27,6 +50,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Added ## Added
- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730
- `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.
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.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
- Add new `UnsignedByteField` class - Add new `UnsignedByteField` class
@ -37,7 +69,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `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
to they can be used without template specification. so they can be used without template specification.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707
- Remove default secondary header argument for - Remove default secondary header argument for
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and `uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
@ -98,7 +130,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
implementation without an extra component implementation without an extra component
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
# [v5.0.0] 25.07.2022 # [v5.0.0] 2022-07-25
## Changes ## Changes

View File

@ -153,12 +153,12 @@ if(FSFW_BUILD_TESTS)
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library" "${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
) )
# Check whether the user has already installed Catch2 first # Check whether the user has already installed Catch2 first
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} QUIET)
# Not installed, so use FetchContent to download and provide Catch2 # Not installed, so use FetchContent to download and provide Catch2
if(NOT Catch2_FOUND) if(NOT Catch2_FOUND)
message( message(
STATUS STATUS
"${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent" "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent."
) )
include(FetchContent) include(FetchContent)
@ -201,8 +201,8 @@ find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
message( message(
STATUS STATUS
"${MSG_PREFIX} No ETL installation was found with find_package. Installing and providing " "${MSG_PREFIX} ETL installation not found. Downloading ETL with FetchContent."
"etl with FindPackage") )
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(

View File

@ -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 {
stage('Host') {
stages{ 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'

43
scripts/check_release.py Normal file
View File

@ -0,0 +1,43 @@
import argparse
import json
import urllib.request
import re
def main() -> None:
parser = argparse.ArgumentParser(
description="List undocumented PRs"
)
parser.add_argument("-m", "--milestone", type=int, required=True)
args = parser.parse_args()
milestone = args.milestone
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/milestones/" + str(milestone)) as milestone_json:
milestone_title = json.load(milestone_json)['title']
match = re.search("(v[0-9]+\.[0-9]+\.[0-9]+)", milestone_title)
if not match:
print("invalid Milestone name")
exit(1)
version = match.group(0)
print("detected Version " + version)
milestone_prs = []
page = 1
last_count = 1;
while last_count != 0:
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/pulls?state=closed&milestone=" + str(milestone) + "&limit=100&page=" + str(page)) as pull_requests_json:
pull_requests = json.load(pull_requests_json)
for pr in pull_requests:
milestone_prs.append(pr['number'])
page += 1
last_count = len(pull_requests)
print("Found " + str(len(milestone_prs)) + " closed PRs in Milestone")
main()

View File

@ -1,5 +1,6 @@
#include "fsfw/devicehandlers/DeviceHandlerBase.h" #include "fsfw/devicehandlers/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"
@ -359,6 +360,8 @@ void DeviceHandlerBase::doStateMachine() {
if ((switchState == PowerSwitchIF::SWITCH_ON) || (switchState == NO_SWITCH)) { if ((switchState == PowerSwitchIF::SWITCH_ON) || (switchState == NO_SWITCH)) {
// NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition // NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition
childTransitionFailure = CHILD_TIMEOUT; childTransitionFailure = CHILD_TIMEOUT;
transitionSourceMode = _MODE_SHUT_DOWN;
transitionSourceSubMode = SUBMODE_NONE;
setMode(_MODE_START_UP); setMode(_MODE_START_UP);
callChildStatemachine(); callChildStatemachine();
} }
@ -1506,10 +1509,13 @@ 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) {
PoolReadGuard pg(reply.second.dataSet);
if (pg.getReadResult() == returnvalue::OK) {
reply.second.dataSet->setValidity(false, true); reply.second.dataSet->setValidity(false, true);
} }
} }
} }
}
void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, const char* functionName, void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, const char* functionName,
ReturnValue_t errorCode, const char* errorPrint) { ReturnValue_t errorCode, const char* errorPrint) {

View File

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

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

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

View File

@ -4,6 +4,7 @@ target_sources(
AsciiConverter.cpp AsciiConverter.cpp
CRC.cpp CRC.cpp
DleEncoder.cpp DleEncoder.cpp
DleParser.cpp
PeriodicOperationDivider.cpp PeriodicOperationDivider.cpp
timevalOperations.cpp timevalOperations.cpp
Type.cpp Type.cpp

View File

@ -0,0 +1,173 @@
#include "DleParser.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <cstdio>
#include <fstream>
#include <iostream>
DleParser::DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
BufPair decodedBuf)
: decodeRingBuf(decodeRingBuf),
decoder(decoder),
encodedBuf(encodedBuf),
decodedBuf(decodedBuf) {}
ReturnValue_t DleParser::passData(const uint8_t* data, size_t len) {
if (data == nullptr or len == 0) {
return returnvalue::FAILED;
}
return decodeRingBuf.writeData(data, len);
}
ReturnValue_t DleParser::parseRingBuf(size_t& readSize) {
ctx.setType(DleParser::ContextType::NONE);
size_t availableData = decodeRingBuf.getAvailableReadData();
if (availableData == 0) {
return NO_PACKET_FOUND;
}
if (availableData > encodedBuf.second) {
ErrorInfo info;
info.len = decodeRingBuf.getAvailableReadData();
setErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
return returnvalue::FAILED;
}
ReturnValue_t result = decodeRingBuf.readData(encodedBuf.first, availableData);
if (result != returnvalue::OK) {
ErrorInfo info;
info.res = result;
setErrorContext(ErrorTypes::RING_BUF_ERROR, info);
return result;
}
bool stxFound = false;
size_t stxIdx = 0;
for (size_t vectorIdx = 0; vectorIdx < availableData; vectorIdx++) {
// handle STX char
if (encodedBuf.first[vectorIdx] == DleEncoder::STX_CHAR) {
if (not stxFound) {
stxFound = true;
stxIdx = vectorIdx;
} else {
// might be lost packet, so we should advance the read pointer
// without skipping the STX
readSize = vectorIdx;
ErrorInfo info;
setErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
return POSSIBLE_PACKET_LOSS;
}
}
// handle ETX char
if (encodedBuf.first[vectorIdx] == DleEncoder::ETX_CHAR) {
if (stxFound) {
// This is propably a packet, so we decode it.
size_t decodedLen = 0;
size_t dummy = 0;
ReturnValue_t result =
decoder.decode(&encodedBuf.first[stxIdx], availableData - stxIdx, &dummy,
decodedBuf.first, decodedBuf.second, &decodedLen);
if (result == returnvalue::OK) {
ctx.setType(ContextType::PACKET_FOUND);
ctx.decodedPacket.first = decodedBuf.first;
ctx.decodedPacket.second = decodedLen;
readSize = ++vectorIdx;
return returnvalue::OK;
} else {
// invalid packet, skip.
readSize = ++vectorIdx;
ErrorInfo info;
info.res = result;
setErrorContext(ErrorTypes::DECODE_ERROR, info);
return POSSIBLE_PACKET_LOSS;
}
} else {
// might be lost packet, so we should advance the read pointer
readSize = ++vectorIdx;
ErrorInfo info;
info.len = 0;
setErrorContext(ErrorTypes::CONSECUTIVE_ETX_CHARS, info);
return POSSIBLE_PACKET_LOSS;
}
}
}
return NO_PACKET_FOUND;
}
void DleParser::defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "DleParserBase::handleFoundPacket: Detected DLE packet with " << len << " bytes"
<< std::endl;
#else
sif::printInfo("DleParserBase::handleFoundPacket: Detected DLE packet with %d bytes\n", len);
#endif
#endif
}
void DleParser::defaultErrorHandler() {
if (ctx.getType() != DleParser::ContextType::ERROR) {
errorPrinter("No error");
return;
}
switch (ctx.error.first) {
case (ErrorTypes::NONE): {
errorPrinter("No error");
break;
}
case (ErrorTypes::DECODE_ERROR): {
errorPrinter("Decode Error");
break;
}
case (ErrorTypes::RING_BUF_ERROR): {
errorPrinter("Ring Buffer Error");
break;
}
case (ErrorTypes::ENCODED_BUF_TOO_SMALL):
case (ErrorTypes::DECODING_BUF_TOO_SMALL): {
char opt[64];
snprintf(opt, sizeof(opt), ": Too small for packet with length %zu",
ctx.decodedPacket.second);
if (ctx.error.first == ErrorTypes::ENCODED_BUF_TOO_SMALL) {
errorPrinter("Encoded buf too small", opt);
} else {
errorPrinter("Decoding buf too small", opt);
}
break;
}
case (ErrorTypes::CONSECUTIVE_STX_CHARS): {
errorPrinter("Consecutive STX chars detected");
break;
}
case (ErrorTypes::CONSECUTIVE_ETX_CHARS): {
errorPrinter("Consecutive ETX chars detected");
break;
}
}
}
void DleParser::errorPrinter(const char* str, const char* opt) {
if (opt == nullptr) {
opt = "";
}
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "DleParserBase::handleParseError: " << str << opt << std::endl;
#else
sif::printInfo("DleParserBase::handleParseError: %s%s\n", str, opt);
#endif
#endif
}
void DleParser::setErrorContext(ErrorTypes err, ErrorInfo info) {
ctx.setType(ContextType::ERROR);
ctx.error.first = err;
ctx.error.second = info;
}
ReturnValue_t DleParser::confirmBytesRead(size_t bytesRead) {
return decodeRingBuf.deleteData(bytesRead);
}
const DleParser::Context& DleParser::getContext() { return ctx; }
void DleParser::reset() { decodeRingBuf.clear(); }

View File

@ -0,0 +1,127 @@
#pragma once
#include <fsfw/container/SimpleRingBuffer.h>
#include <fsfw/globalfunctions/DleEncoder.h>
#include <fsfw/returnvalues/returnvalue.h>
#include <cstddef>
#include <utility>
/**
* @brief This base helper class can be used to extract DLE encoded packets from a data stream
* @details
* The core API of the parser takes received packets which can contains DLE packets. The parser
* can deal with DLE packets split across multiple packets. It does so by using a dedicated
* decoding ring buffer. The user can process received packets and detect errors by
* overriding two provided virtual methods. This also allows detecting multiple DLE packets
* inside one passed packet.
*/
class DleParser {
public:
static constexpr ReturnValue_t NO_PACKET_FOUND = returnvalue::makeCode(1, 1);
static constexpr ReturnValue_t POSSIBLE_PACKET_LOSS = returnvalue::makeCode(1, 2);
using BufPair = std::pair<uint8_t*, size_t>;
enum class ContextType { NONE, PACKET_FOUND, ERROR };
enum class ErrorTypes {
NONE,
ENCODED_BUF_TOO_SMALL,
DECODING_BUF_TOO_SMALL,
DECODE_ERROR,
RING_BUF_ERROR,
CONSECUTIVE_STX_CHARS,
CONSECUTIVE_ETX_CHARS
};
union ErrorInfo {
size_t len;
ReturnValue_t res;
};
using ErrorPair = std::pair<ErrorTypes, ErrorInfo>;
struct Context {
public:
Context() { setType(ContextType::PACKET_FOUND); }
void setType(ContextType type) {
this->type = type;
if (type == ContextType::PACKET_FOUND) {
error.first = ErrorTypes::NONE;
error.second.len = 0;
} else {
decodedPacket.first = nullptr;
decodedPacket.second = 0;
}
}
ContextType getType() const { return type; }
BufPair decodedPacket = {};
ErrorPair error;
private:
ContextType type;
};
/**
* Base class constructor
* @param decodeRingBuf Ring buffer used to store multiple packets to allow detecting DLE packets
* split across multiple packets
* @param decoder Decoder instance
* @param encodedBuf Buffer used to store encoded packets. It has to be large enough to hold
* the largest expected encoded DLE packet size
* @param decodedBuf Buffer used to store decoded packets. It has to be large enough to hold the
* largest expected decoded DLE packet size
* @param handler Function which will be called on a found packet
* @param args Arbitrary user argument
*/
DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
BufPair decodedBuf);
/**
* This function allows to pass new data into the parser. It then scans for DLE packets
* automatically and inserts (part of) the packet into a ring buffer if necessary.
* @param data
* @param len
* @return
*/
ReturnValue_t passData(const uint8_t* data, size_t len);
ReturnValue_t parseRingBuf(size_t& bytesRead);
ReturnValue_t confirmBytesRead(size_t bytesRead);
const Context& getContext();
/**
* Example found packet handler
* function call
* @param packet Decoded packet
* @param len Length of detected packet
*/
void defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args);
/**
* Will be called if an error occured in the #passData call
* @param err
* @param ctx Context information depending on the error type
* - For buffer length errors, will be set to the detected packet length which is too large
* - For decode or ring buffer errors, will be set to the result returned from the failed call
*/
void defaultErrorHandler();
static void errorPrinter(const char* str, const char* opt = nullptr);
void setErrorContext(ErrorTypes err, ErrorInfo ctx);
/**
* Resets the parser by resetting the internal states and clearing the decoding ring buffer
*/
void reset();
private:
SimpleRingBuffer& decodeRingBuf;
DleEncoder& decoder;
BufPair encodedBuf;
BufPair decodedBuf;
Context ctx;
};

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

@ -16,26 +16,24 @@ class HasHealthIF {
}; };
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF; static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1); static constexpr ReturnValue_t OBJECT_NOT_HEALTHY = returnvalue::makeCode(INTERFACE_ID, 1);
static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2); static constexpr ReturnValue_t INVALID_HEALTH_STATE = returnvalue::makeCode(INTERFACE_ID, 2);
static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED = returnvalue::makeCode(INTERFACE_ID, 3);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
//! P1: New Health, P2: Old Health
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO); static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO); static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW); static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
static const Event OVERWRITING_HEALTH = //! Assembly overwrites health information of children to keep satellite alive.
MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW);
//!< satellite alive. //! Someone starts a recovery of a component (typically power-cycle). No parameters.
static const Event TRYING_RECOVERY = static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically //! Recovery is ongoing. Comes twice during recovery.
//!< power-cycle). No parameters. //! P1: 0 for the first, 1 for the second event. P2: 0
static const Event RECOVERY_STEP = static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1: //! Recovery was completed. Not necessarily successful. No parameters.
//!< 0 for the first, 1 for the second event. P2: 0 static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
static const Event RECOVERY_DONE = MAKE_EVENT(
12,
severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters.
virtual ~HasHealthIF() {} virtual ~HasHealthIF() {}
virtual MessageQueueId_t getCommandQueue() const = 0; virtual MessageQueueId_t getCommandQueue() const = 0;

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

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

View File

@ -24,3 +24,19 @@ void ModeMessage::setCantReachMode(CommandMessage* message, ReturnValue_t reason
message->setParameter(reason); message->setParameter(reason);
message->setParameter2(0); message->setParameter2(0);
} }
void ModeMessage::setModeAnnounceMessage(CommandMessage& message, bool recursive) {
Command_t cmd;
if (recursive) {
cmd = CMD_MODE_ANNOUNCE_RECURSIVELY;
} else {
cmd = CMD_MODE_ANNOUNCE;
}
message.setCommand(cmd);
}
void ModeMessage::setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode) {
setModeMessage(&message, CMD_MODE_COMMAND, mode, submode);
}
void ModeMessage::setModeReadMessage(CommandMessage& message) { message.setCommand(CMD_MODE_READ); }

View File

@ -45,6 +45,9 @@ class ModeMessage {
static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode, static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode,
Submode_t submode); Submode_t submode);
static void setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode);
static void setModeAnnounceMessage(CommandMessage& message, bool recursive);
static void setModeReadMessage(CommandMessage& message);
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,16 +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(
WARNING
"${MSG_PREFIX} The FSFW_OSAL 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 +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,8 +63,23 @@ 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 +95,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

@ -19,7 +19,7 @@ ReturnValue_t CService200ModeCommanding::isValidSubservice(uint8_t subservice) {
switch (subservice) { switch (subservice) {
case (Subservice::COMMAND_MODE_COMMAND): case (Subservice::COMMAND_MODE_COMMAND):
case (Subservice::COMMAND_MODE_READ): case (Subservice::COMMAND_MODE_READ):
case (Subservice::COMMAND_MODE_ANNCOUNCE): case (Subservice::COMMAND_MODE_ANNOUNCE):
return returnvalue::OK; return returnvalue::OK;
default: default:
return AcceptsTelecommandsIF::INVALID_SUBSERVICE; return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
@ -53,6 +53,9 @@ ReturnValue_t CService200ModeCommanding::checkInterfaceAndAcquireMessageQueue(
ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice, ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
const uint8_t *tcData, size_t tcDataLen, const uint8_t *tcData, size_t tcDataLen,
uint32_t *state, object_id_t objectId) { uint32_t *state, object_id_t objectId) {
bool recursive = false;
switch (subservice) {
case (Subservice::COMMAND_MODE_COMMAND): {
ModePacket modeCommandPacket; ModePacket modeCommandPacket;
ReturnValue_t result = ReturnValue_t result =
modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG); modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
@ -60,9 +63,22 @@ ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message,
return result; return result;
} }
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(), ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND,
modeCommandPacket.getSubmode()); modeCommandPacket.getMode(), modeCommandPacket.getSubmode());
return result; return returnvalue::OK;
}
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
recursive = true;
[[fallthrough]];
case (Subservice::COMMAND_MODE_ANNOUNCE):
ModeMessage::setModeAnnounceMessage(*message, recursive);
return EXECUTION_COMPLETE;
case (Subservice::COMMAND_MODE_READ):
ModeMessage::setModeReadMessage(*message);
return returnvalue::OK;
default:
return CommandingServiceBase::INVALID_SUBSERVICE;
}
} }
ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply, ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply,
@ -73,8 +89,10 @@ ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply
ReturnValue_t result = returnvalue::FAILED; ReturnValue_t result = returnvalue::FAILED;
switch (replyId) { switch (replyId) {
case (ModeMessage::REPLY_MODE_REPLY): { case (ModeMessage::REPLY_MODE_REPLY): {
result = prepareModeReply(reply, objectId); if (previousCommand != ModeMessage::CMD_MODE_COMMAND) {
break; return prepareModeReply(reply, objectId);
}
return returnvalue::OK;
} }
case (ModeMessage::REPLY_WRONG_MODE_REPLY): { case (ModeMessage::REPLY_WRONG_MODE_REPLY): {
result = prepareWrongModeReply(reply, objectId); result = prepareWrongModeReply(reply, objectId);

View File

@ -52,7 +52,7 @@ class CService200ModeCommanding : public CommandingServiceBase {
COMMAND_MODE_READ = 3, COMMAND_MODE_READ = 3,
//!< [EXPORT] : [COMMAND] Trigger an ModeInfo Event. //!< [EXPORT] : [COMMAND] Trigger an ModeInfo Event.
//! This command does NOT have a reply //! This command does NOT have a reply
COMMAND_MODE_ANNCOUNCE = 4, COMMAND_MODE_ANNOUNCE = 4,
//!< [EXPORT] : [COMMAND] Trigger a ModeInfo Event and to send this //!< [EXPORT] : [COMMAND] Trigger a ModeInfo Event and to send this
//! command to every child. This command does NOT have a reply. //! command to every child. This command does NOT have a reply.
COMMAND_MODE_ANNOUNCE_RECURSIVELY = 5, COMMAND_MODE_ANNOUNCE_RECURSIVELY = 5,

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;
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,
}; };
}; };

View File

@ -4,6 +4,8 @@
#include "fsfw/timemanager/Clock.h" #include "fsfw/timemanager/Clock.h"
CdsShortTimeStamper::CdsShortTimeStamper() : SystemObject(0, false) {}
CdsShortTimeStamper::CdsShortTimeStamper(object_id_t objectId) : SystemObject(objectId) {} CdsShortTimeStamper::CdsShortTimeStamper(object_id_t objectId) : SystemObject(objectId) {}
ReturnValue_t CdsShortTimeStamper::serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t CdsShortTimeStamper::serialize(uint8_t **buffer, size_t *size, size_t maxSize,

View File

@ -18,6 +18,7 @@
class CdsShortTimeStamper : public TimeWriterIF, public TimeReaderIF, public SystemObject { class CdsShortTimeStamper : public TimeWriterIF, public TimeReaderIF, public SystemObject {
public: public:
static constexpr size_t TIMESTAMP_LEN = 7; static constexpr size_t TIMESTAMP_LEN = 7;
CdsShortTimeStamper();
/** /**
* @brief Default constructor which also registers the time stamper as a * @brief Default constructor which also registers the time stamper as a
* system object so it can be found with the #objectManager. * system object so it can be found with the #objectManager.

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

@ -5,20 +5,28 @@
class SourceSequenceCounter { class SourceSequenceCounter {
private: private:
uint16_t sequenceCount; uint16_t sequenceCount = 0;
public: public:
SourceSequenceCounter() : sequenceCount(0) {} SourceSequenceCounter(uint16_t initialSequenceCount = 0) : sequenceCount(initialSequenceCount) {}
void increment() { void increment() { sequenceCount = (sequenceCount + 1) % (ccsds::LIMIT_SEQUENCE_COUNT); }
sequenceCount = (sequenceCount + 1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); void decrement() { sequenceCount = (sequenceCount - 1) % (ccsds::LIMIT_SEQUENCE_COUNT); }
uint16_t get() const { return this->sequenceCount; }
void reset(uint16_t toValue = 0) { sequenceCount = toValue % (ccsds::LIMIT_SEQUENCE_COUNT); }
SourceSequenceCounter& operator++(int) {
this->increment();
return *this;
} }
void decrement() { SourceSequenceCounter& operator--(int) {
sequenceCount = (sequenceCount - 1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); this->decrement();
return *this;
} }
uint16_t get() { return this->sequenceCount; } SourceSequenceCounter& operator=(const uint16_t& newCount) {
void reset(uint16_t toValue = 0) { sequenceCount = newCount;
sequenceCount = toValue % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); return *this;
} }
operator uint16_t() { return this->get(); }
}; };
#endif /* FSFW_TMTCSERVICES_SOURCESEQUENCECOUNTER_H_ */ #endif /* FSFW_TMTCSERVICES_SOURCESEQUENCECOUNTER_H_ */

View File

@ -16,7 +16,9 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
tcDestination(tcDestination) tcDestination(tcDestination)
{ {
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH); auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
} }
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); } TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
@ -35,7 +37,7 @@ ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerC
} }
} }
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored) { ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) {
if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) { if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) {
this->maxNumberOfPacketsStored = maxNumberOfPacketsStored; this->maxNumberOfPacketsStored = maxNumberOfPacketsStored;
return returnvalue::OK; return returnvalue::OK;
@ -143,13 +145,17 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
#endif /* FSFW_VERBOSE_LEVEL >= 3 */ #endif /* FSFW_VERBOSE_LEVEL >= 3 */
if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) { if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) {
storeDownlinkData(&message); ReturnValue_t result = storeDownlinkData(&message);
if (result != returnvalue::OK) {
tmStore->deleteData(message.getStorageId());
}
continue; continue;
} }
result = tmStore->getData(message.getStorageId(), &data, &size); result = tmStore->getData(message.getStorageId(), &data, &size);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
status = result; status = result;
tmStore->deleteData(message.getStorageId());
continue; continue;
} }
@ -157,9 +163,9 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
status = result; status = result;
} else { } else {
tmStore->deleteData(message.getStorageId());
packetSentCounter++; packetSentCounter++;
} }
tmStore->deleteData(message.getStorageId());
} }
return status; return status;
} }
@ -171,6 +177,7 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
} }
if (tmFifo->full()) { if (tmFifo->full()) {
if (warningSwitch) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number " sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
"of stored packet IDs reached!" "of stored packet IDs reached!"
@ -180,6 +187,8 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
"TmTcBridge::storeDownlinkData: TM downlink max. number " "TmTcBridge::storeDownlinkData: TM downlink max. number "
"of stored packet IDs reached!\n"); "of stored packet IDs reached!\n");
#endif #endif
warningSwitch = false;
}
if (overwriteOld) { if (overwriteOld) {
tmFifo->retrieve(&storeId); tmFifo->retrieve(&storeId);
tmStore->deleteData(storeId); tmStore->deleteData(storeId);
@ -221,6 +230,7 @@ ReturnValue_t TmTcBridge::handleStoredTm() {
packetSentCounter++; packetSentCounter++;
if (tmFifo->empty()) { if (tmFifo->empty()) {
warningSwitch = true;
tmStored = false; tmStored = false;
} }
tmStore->deleteData(storeId); tmStore->deleteData(storeId);

View File

@ -17,7 +17,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
public: public:
static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20; static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20;
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15; static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 200; static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500;
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
@ -42,7 +42,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
* @return -@c returnvalue::OK if value was set successfully * @return -@c returnvalue::OK if value was set successfully
* -@c returnvalue::FAILED otherwise, stored value stays the same * -@c returnvalue::FAILED otherwise, stored value stays the same
*/ */
ReturnValue_t setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored); ReturnValue_t setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored);
/** /**
* This will set up the bridge to overwrite old data in the FIFO. * This will set up the bridge to overwrite old data in the FIFO.
@ -91,6 +91,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
//! by default, so telemetry will be handled immediately. //! by default, so telemetry will be handled immediately.
bool communicationLinkUp = true; bool communicationLinkUp = true;
bool tmStored = false; bool tmStored = false;
bool warningSwitch = true;
bool overwriteOld = true; bool overwriteOld = true;
uint8_t packetSentCounter = 0; uint8_t packetSentCounter = 0;
@ -152,7 +153,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
*/ */
DynamicFIFO<store_address_t>* tmFifo = nullptr; DynamicFIFO<store_address_t>* tmFifo = nullptr;
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED; unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
}; };
#endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */ #endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */

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

@ -32,6 +32,8 @@ ReturnValue_t CommandExecutor::execute() {
} else if (state == States::PENDING) { } else if (state == States::PENDING) {
return COMMAND_PENDING; return COMMAND_PENDING;
} }
// Reset data in read vector
std::memset(readVec.data(), 0, readVec.size());
currentCmdFile = popen(currentCmd.c_str(), "r"); currentCmdFile = popen(currentCmd.c_str(), "r");
if (currentCmdFile == nullptr) { if (currentCmdFile == nullptr) {
lastError = errno; lastError = errno;
@ -205,3 +207,5 @@ ReturnValue_t CommandExecutor::executeBlocking() {
} }
return returnvalue::OK; return returnvalue::OK;
} }
const std::vector<char>& CommandExecutor::getReadVector() const { return readVec; }

View File

@ -107,6 +107,8 @@ class CommandExecutor {
*/ */
void reset(); void reset();
const std::vector<char>& getReadVector() const;
private: private:
std::string currentCmd; std::string currentCmd;
bool blocking = true; bool blocking = true;

View File

@ -168,16 +168,18 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
int readLen = read(fd, replyBuffer, requestLen); int readLen = read(fd, replyBuffer, requestLen);
if (readLen != static_cast<int>(requestLen)) { if (readLen != static_cast<int>(requestLen)) {
#if FSFW_VERBOSE_LEVEL >= 1 and FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_VERBOSE_LEVEL >= 1
sif::error << "I2cComIF::requestReceiveMessage: Reading from I2C "
<< "device failed with error code " << errno << ". Description"
<< " of error: " << strerror(errno) << std::endl;
sif::error << "I2cComIF::requestReceiveMessage: Read only " << readLen << " from " << requestLen
<< " bytes" << std::endl;
#endif
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "I2cComIF::requestReceiveMessage: Read " << readLen << " of " << requestLen if (readLen < 0) {
<< " bytes" << std::endl; sif::warning << "I2cComIF::requestReceiveMessage: Reading from I2C "
<< "device failed with error code " << errno << " | " << strerror(errno)
<< std::endl;
} else {
sif::warning << "I2cComIF::requestReceiveMessage: Read only " << readLen << " from "
<< requestLen << " bytes" << std::endl;
}
#else
#endif
#endif #endif
return returnvalue::FAILED; return returnvalue::FAILED;
} }

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,25 +1,21 @@
#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"
// binary semaphores currently only supported on linux
#ifdef FSFW_OSAL_LINUX
TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") { TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") {
// perform set-up here // perform set-up here
SemaphoreIF* binSemaph = SemaphoreFactory::instance()-> SemaphoreIF* binSemaph = SemaphoreFactory::instance()->createBinarySemaphore();
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);
@ -29,18 +25,14 @@ TEST_CASE("Binary Semaphore Test" , "[BinSemaphore]") {
// 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

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_ */