Compare commits

...

85 Commits

Author SHA1 Message Date
b814e7198f Merge pull request 'Allow creating regular threads' (#140) from allow_creating_regular_threads into develop
Reviewed-on: #140
2023-03-24 14:15:53 +01:00
6328b70d7b Merge branch 'develop' into allow_creating_regular_threads 2023-03-24 14:15:39 +01:00
a937b457f9 this is so confusing 2023-03-24 14:10:47 +01:00
4415dc24e1 fix host OSAL 2023-03-24 13:25:34 +01:00
e704295cce default value 2023-03-24 11:58:23 +01:00
d16b3c7e67 try to do this cleanly 2023-03-24 11:53:41 +01:00
3b86545725 Merge pull request 'add BUSY retval' (#141) from busy_retval_dhb_com into develop
Reviewed-on: #141
2023-03-24 11:35:09 +01:00
cf6150cc18 add BUSY retval 2023-03-24 00:57:44 +01:00
bfb5c2ff03 Merge branch 'develop' into allow_creating_regular_threads 2023-03-23 18:45:49 +01:00
bf02061d47 Merge pull request 'use RR sched instead of FIFO for Linux RT' (#139) from use_rr_sched into develop
Reviewed-on: #139
2023-03-23 18:45:09 +01:00
2c4e110254 Merge branch 'develop' into use_rr_sched 2023-03-23 18:44:59 +01:00
7ed75ea87b Merge remote-tracking branch 'origin/develop' into allow_creating_regular_threads 2023-03-23 18:44:06 +01:00
db4587bb59 allow creating regular threads 2023-03-23 18:29:17 +01:00
33ac395072 use RR sched instead of FIFO for Linux RT 2023-03-23 15:42:14 +01:00
f8a7c1d4ed rename namespace 2023-03-22 01:03:49 +01:00
341437df13 add flush functions for serial helpers 2023-03-21 20:20:13 +01:00
227524a21d transition source submode is tricky 2023-03-20 15:49:09 +01:00
43fd0b2f59 resolve some more merge conflicts 2023-03-15 11:48:50 +01:00
d0607824ad Merge remote-tracking branch 'upstream/development' into develop 2023-03-15 11:40:48 +01:00
cf27954a86 changelog 2023-03-14 19:55:01 +01:00
f84e3284ab just hardcode spill option to true 2023-03-14 19:54:21 +01:00
5250423d1d Merge pull request 'Periodic HK helper simplification' (#136) from periodic_hk_helper_simplification into develop
Reviewed-on: #136
2023-03-14 18:27:14 +01:00
522bd41d6e changelog 2023-03-14 18:26:44 +01:00
c61c85280b remove more code 2023-03-14 18:26:04 +01:00
afbe5e1f65 Merge remote-tracking branch 'origin/develop' into periodic_hk_helper_simplification 2023-03-14 18:23:57 +01:00
4c88ab80c8 Merge pull request 'Pool Manager spill to higher pools option' (#135) from pool_manager_spilling_opt into develop
Reviewed-on: #135
2023-03-14 18:22:31 +01:00
5ba69b169f changelog 2023-03-14 18:22:00 +01:00
40405fe6c7 add spill option 2023-03-14 18:21:16 +01:00
aac32e763c some compile fixes 2023-03-14 18:20:17 +01:00
bf980d74c0 HK helper simplification 2023-03-14 17:40:39 +01:00
b6b9d1d790 make dataset enable idempotent 2023-03-14 16:49:46 +01:00
0973ba6bf2 Merge pull request 'basic faulty cb for power switcher component' (#134) from feature_power_switch_faulty_cb into develop
Reviewed-on: #134
2023-03-14 14:15:11 +01:00
1cfebb5d47 Merge branch 'develop' into feature_power_switch_faulty_cb 2023-03-14 14:14:50 +01:00
0b0a0299bc power switch IF improvements 2023-03-14 13:45:03 +01:00
8382d61b92 possible fix for power switch component 2023-03-14 11:44:13 +01:00
7208343b6d basic faulty cb for power switcher component 2023-03-13 16:01:13 +01:00
9a8d775eb1 optimization for cmd executor 2023-03-12 20:49:34 +01:00
4d6f6e6b23 event manager queue depth configurable 2023-03-10 14:58:20 +01:00
55f6825a03 Revert "Modes: reusing submode for mode mask, more unittests"
This reverts commit f0bddfcb21.
2023-03-10 14:50:16 +01:00
c162acb7df Merge branch 'develop' of https://egit.irs.uni-stuttgart.de/eive/fsfw into develop 2023-03-10 14:23:51 +01:00
87462afe6d better error printout for i2c write error 2023-03-10 14:23:40 +01:00
a8de395ea0 Merge pull request 'Modes: reusing submode for mode mask, more unittests' (#133) from mohr/submode_mask into develop
Reviewed-on: #133
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-03-10 11:22:11 +01:00
f0bddfcb21 Modes: reusing submode for mode mask, more unittests 2023-03-09 16:43:45 +01:00
23d9b44b3e Merge pull request 'exceptionless host filesystem' (#132) from avoid_exceptions into develop
Reviewed-on: #132
2023-03-08 14:55:18 +01:00
26e4445189 exceptionless host filesystem 2023-03-08 14:47:03 +01:00
9ee3cdf729 Merge pull request 'OFF -> NORMAL: Set transition source modes' (#131) from off_to_normal_transition_sources into develop
Reviewed-on: #131
2023-03-08 01:24:54 +01:00
1b7493f945 OFF -> NORMAL: Set transition source modes 2023-03-08 01:18:11 +01:00
7f6ba5f40b Merge pull request 'Feature: Allowed Submodes Mask for Mode List Entry' (#130) from feature_allow_submodes_mode_list_entry into develop
Reviewed-on: #130
Reviewed-by: Steffen Gaisser <gaisser@irs.uni-stuttgart.de>
2023-03-07 17:20:47 +01:00
070b48ada2 review improvements 2023-03-07 17:15:34 +01:00
d9a139e1ef Merge remote-tracking branch 'origin/develop' into feature_allow_submodes_mode_list_entry 2023-03-07 16:31:28 +01:00
c80a3752d9 afmt 2023-03-07 16:31:08 +01:00
af58c414fc bugfix in submode check logic 2023-03-07 16:29:10 +01:00
4c48668125 add copy and assignment ctor for mode definition 2023-03-07 16:03:28 +01:00
2745b2080d allow submode mask now 2023-03-07 13:55:40 +01:00
e9d9f44605 added length check 2023-03-06 14:01:45 +01:00
2c5af91db1 Merge pull request 'new monotonic clock API' (#128) from feature_monotonic_clock_api into develop
Reviewed-on: #128
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-03-04 11:47:37 +01:00
5cd7b98ba7 more todo docs 2023-03-04 11:38:16 +01:00
a39f1271ec return FAILED for win 2023-03-04 11:32:32 +01:00
bbf0d7a0d2 add basic impl (no windows) for host 2023-03-04 11:31:54 +01:00
04ee3c7362 renaming 2023-03-04 11:04:55 +01:00
95dab69b35 new monotonic clock API 2023-03-04 11:03:22 +01:00
33de15205b Merge pull request 'configurable queue depth' (#127) from feature_configurable_queue_depth_tcpip_servers into develop
Reviewed-on: #127
2023-03-03 16:33:29 +01:00
4d353a1ad2 remove obsolete constant 2023-03-03 16:36:30 +01:00
6006c97e48 configurable queue depth 2023-03-03 15:45:44 +01:00
6e17e45506 Merge pull request 'timeval: Use system clock' (#126) from feature_timeval_use_sysclock into develop
Reviewed-on: #126
2023-03-03 15:25:38 +01:00
64537d442a extneded and fixed countdown unittests 2023-03-03 14:54:52 +01:00
78cf00315d use sys clock for Countdown 2023-03-03 14:30:35 +01:00
245886c555 add lock context for pool manager 2023-03-02 15:33:49 +01:00
f84097543e allow passing context to mutex guard 2023-03-02 15:20:59 +01:00
dc7afc5415 Version bump, CHANGELOG update, format 2023-02-23 13:38:24 +01:00
9bf3ff95b7 Merge pull request 'Add Health Service Announce All Health Info' (#725) from eive/fsfw:add_health_service_announce_all into development
Reviewed-on: fsfw/fsfw#725
2023-02-23 13:13:56 +01:00
61562b18ab Merge branch 'development' into add_health_service_announce_all 2023-02-23 12:56:12 +01:00
d76d97a36b changed health table parameter to objectId 2023-02-23 12:44:42 +01:00
76b377c4c0 Merge pull request 'Mode Service: Add allowed subservice' (#739) from eive/fsfw:small_mode_service_fix into development
Reviewed-on: fsfw/fsfw#739
2023-02-20 13:40:53 +01:00
3562bf11b9 CHANGELOG update 2023-02-10 11:06:46 +01:00
fffb2b61e5 release check helper 2023-02-10 11:06:30 +01:00
94e5f62331 add allowed subservice 2023-02-09 18:30:08 +01:00
0a9c563bbc format 2023-02-09 15:58:48 +01:00
5b92247fbd Merge branch 'development' into add_health_service_announce_all 2023-02-06 16:31:05 +01:00
d9da55fdab Merge branch 'development' into add_health_service_announce_all 2023-02-06 15:03:52 +01:00
066f7a6f9b remove unreachable code 2023-02-06 14:41:14 +01:00
c1f42618db small but important bugfix for health service 2023-02-01 19:59:32 +01:00
61df451dd8 update changelog 2023-02-01 17:41:47 +01:00
29ea89044e beatufil 2023-02-01 17:35:49 +01:00
e487f5be87 proper announce all impl 2023-02-01 17:35:32 +01:00
61 changed files with 729 additions and 335 deletions

View File

@ -8,16 +8,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
# [v6.0.0]
# [v6.0.0] 2023-02-10
## Fixes
- Bugfix in `Service11TelecommandScheduling` which allowed commands
time tagged in the past to be inserted.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/738
- Mode Service: Add allowed subservice
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/739
- `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
@ -26,16 +26,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- 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
- Bugfix for RM3100 MGM sensors. Z value was previously calculated
with bytes of the X value.
- 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
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.
Also properly reset the reply size for successfull transfers and erroneous transfers.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
@ -45,6 +49,36 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `TcpTmTcServer.cpp`: The server was actually not able to handle
CCSDS packets which were clumped together. This has been fixed now.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
- `CServiceHealthCommanding`: Add announce all health info implementation
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
- various fixes related to linux Unittests and memory leaks
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/715
- small fix to allow teardown handling
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/713
- fix compiler warning for fixed array list copy ctor
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/704
- missing include
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/703
- defaultconfig did not build anymore
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/702
- hotfix
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/699
- small fix for helper
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/698
- missing retval conv
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/697
- DHB Countdown Bug
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/693
- doc corrections
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/687
- better error printout
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/686
- include correction
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/683
- better warning for missing include paths
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/676
- Service 11 regression
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/670
## Added
@ -63,17 +97,36 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
- Add new `UnsignedByteField` class
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
- publish documentation for development and master branch
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/681
- Add Linux HAL options
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/663
- Expand SerializeIF
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/656
- PUS Service 11: Additional Safety Check
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/666
- improvements for auto-formatter script
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/665
- provide a weak print char impl
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/674
## Removed
- now that doc server is up, remove markdown files
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/688
- remove bsp specific code
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/679
## Changes
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
`HealthServiceCfg` now
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
- 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
- Remove default secondary header argument for
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
@ -103,18 +156,41 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
interface itself so it can be re-used more easily. Also add new
abstract function `bool hasDataAtId(store_address_t storeId) const`.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
- Make functions `const` where it makes sense
- Add `const char* getName const` abstract function
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
interface itself so it can be re-used more easily. Also add new
abstract function `bool hasDataAtId(store_address_t storeId) const`.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
- Generic TMTC Bridge Update
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734
- comment tweak to event parser can read everything
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/732
- CMakeLists file updates
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/731
- improve srv20 error messages
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/723
- I2C Linux: remove duplicate printout
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/718
- printout handling improvements
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/717
- vec getter, reset for content
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/716
- updates for source sequence counter
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/714
- SP reader getPacketData is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/708
- refactoring of serial drivers for linux
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/705
- Local Pool Update Remove Add Data Ignore Fault Argument
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/701
- Switch to new documentation server
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/694
- Windows Tweaks
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/691
- Refactor Local Pool API
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/667
- group MGM data in local pool vectors
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/664
## CFDP
@ -134,17 +210,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
implementation without an extra component
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
## HAL
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
lot more sense because each ComIF should be responsible for one SPI bus.
- SPI: Move the empty transfer to update the line polarity to separate function. This means
it is not automatically called when calling the setter function for SPI speed and mode.
The user should call this function after locking the CS mutex if multiple SPI devices with
differing speeds and modes are attached to one bus.
- SPI: Getter functions for SPI speed and mode.
# [v5.0.0] 25.07.2022
# [v5.0.0] 2022-07-25
## Changes

View File

@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
# Version file handling #
# ##############################################################################
set(FSFW_VERSION_IF_GIT_FAILS 5)
set(FSFW_VERSION_IF_GIT_FAILS 6)
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
set(FSFW_REVISION_IF_GIT_FAILS 0)

110
scripts/check_release.py Executable file
View File

@ -0,0 +1,110 @@
#! /bin/python
import argparse
import json
import urllib.request
import re
from pathlib import Path
def main() -> None:
parser = argparse.ArgumentParser(
description="List undocumented PRs"
)
parser.add_argument("-v", "--version", type=str, required=True)
args = parser.parse_args()
match = re.search("([0-9]+\.[0-9]+\.[0-9]+)", args.version)
if not match:
print("invalid version")
exit(1)
version = "v" + match.group(1)
print("looking for milestone for " + version + " ...")
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/milestones?name=" + version) as milestone_json:
milestones = json.load(milestone_json)
if (len(milestones) == 0):
print("did not find any milestone")
exit(1)
if (len(milestones) > 1):
print("found multiple milestons")
milestone_title = milestones[0]['title']
milestone = str(milestones[0]['id'])
print("Using Milestone \""+ milestone_title + "\" with id " + milestone)
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({'number': str(pr['number']), 'title' : pr['title']})
page += 1
last_count = len(pull_requests)
print("Found " + str(len(milestone_prs)) + " closed PRs in Milestone")
print("looking for CHANGELOG.md ...")
path = Path(".")
files = list(path.glob("CHANGELOG.md"))
if (len(files) != 1):
files = list(path.glob("../CHANGELOG.md"))
if (len(files) != 1):
print("did not find CHANGELOG.md. Run script in either root directory or scripts subfolder.")
exit(1)
print("Scanning CHANGELOG.md ...")
changelog_prs = []
with open(files[0]) as changelog:
line = changelog.readline()
while (line):
#print("line: " + line)
match = re.search("\#.+(v[0-9]+\.[0-9]+\.[0-9]+)", line)
if (match):
if match.group(1) == version:
#print("found version")
line = changelog.readline()
continue
else:
#print("done with " + match.group(1))
break
match = re.search("PR: https://egit\.irs\.uni-stuttgart\.de/fsfw/fsfw/pulls/([0-9]+)", line)
if match:
changelog_prs.append(match.group(1))
line = changelog.readline()
print("Found " + str(len(changelog_prs)) + " PRs in CHANGELOG.md")
print("")
copy_array = changelog_prs.copy()
print("PRs in CHANGELOG.md that are not in Milestone:")
for pr in milestone_prs:
if pr['number'] in copy_array:
copy_array.remove(pr['number'])
for pr in copy_array:
print("https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr)
print("")
print("PRs in milestone that are not in CHANGELOG.md:")
for pr in milestone_prs:
if pr['number'] not in changelog_prs:
print("- " + pr['title'] + "\n PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr['number'])
main()

View File

@ -70,8 +70,7 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
return returnvalue::OK;
}
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation(uint8_t nonDiagInvlFactor) {
setNonDiagnosticIntervalFactor(nonDiagInvlFactor);
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation() {
return initializeHousekeepingPoolEntriesOnce();
}
@ -661,10 +660,6 @@ ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(HousekeepingPacke
return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE);
}
void LocalDataPoolManager::setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor) {
this->nonDiagnosticIntervalFactor = nonDiagInvlFactor;
}
void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
sid_t sid = receiver.dataId.sid;
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
@ -718,7 +713,7 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool ena
if ((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or
(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) {
return REPORTING_STATUS_UNCHANGED;
return returnvalue::OK;
}
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable);

View File

@ -102,7 +102,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
* @param nonDiagInvlFactor
* @return
*/
ReturnValue_t initializeAfterTaskCreation(uint8_t nonDiagInvlFactor = 5);
ReturnValue_t initializeAfterTaskCreation();
/**
* @brief This should be called in the periodic handler of the owner.
@ -152,17 +152,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
MessageQueueId_t targetQueueId,
bool generateSnapshot) override;
/**
* Non-Diagnostics packets usually have a lower minimum sampling frequency
* than diagnostic packets.
* A factor can be specified to determine the minimum sampling frequency
* for non-diagnostic packets. The minimum sampling frequency of the
* diagnostics packets,which is usually jusst the period of the
* performOperation calls, is multiplied with that factor.
* @param factor
*/
void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor);
/**
* @brief The manager is also able to handle housekeeping messages.
* @details

View File

@ -250,9 +250,8 @@ void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) {
bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; }
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor) {
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor);
dur_millis_t minimumPeriodicInterval) {
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval);
}
void LocalPoolDataSetBase::setChanged(bool changed) { this->changed = changed; }

View File

@ -191,8 +191,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
*/
bool reportingEnabled = false;
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor = 5);
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval);
/**
* If the valid state of a dataset is always relevant to the whole

View File

@ -12,10 +12,8 @@ class LocalPoolDataSetAttorney {
static bool isDiagnostics(LocalPoolDataSetBase& set) { return set.isDiagnostics(); }
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
uint32_t minimumPeriodicIntervalMs,
uint8_t nonDiagIntervalFactor = 5) {
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs,
nonDiagIntervalFactor);
uint32_t minimumPeriodicIntervalMs) {
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs);
}
static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) {

View File

@ -49,6 +49,7 @@ class DeviceCommunicationIF {
// is this needed if there is no open/close call?
static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05);
static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06);
static constexpr ReturnValue_t BUSY = MAKE_RETURN_CODE(0x07);
virtual ~DeviceCommunicationIF() {}

View File

@ -565,6 +565,9 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
*/
if (newMode == MODE_ON and continueToNormal) {
continueToNormal = false;
// TODO: Check whether the following two lines are okay to do so.
transitionSourceMode = MODE_ON;
transitionSourceSubMode = newSubmode;
mode = _MODE_TO_NORMAL;
return;
}

View File

@ -15,12 +15,12 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
{fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, sizeof(EventIdRangeMatcher)},
{fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, sizeof(ReporterRangeMatcher)}};
EventManager::EventManager(object_id_t setObjectId)
EventManager::EventManager(object_id_t setObjectId, uint32_t eventQueueDepth)
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
mutex = MutexFactory::instance()->createMutex();
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
eventReportQueue = QueueFactory::instance()->createMessageQueue(
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
eventQueueDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
}
EventManager::~EventManager() {

View File

@ -21,9 +21,9 @@ extern const char* translateEvents(Event event);
class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject {
public:
static const uint16_t MAX_EVENTS_PER_CYCLE = 80;
static const uint16_t DEFAULT_MAX_EVENTS_PER_CYCLE = 80;
EventManager(object_id_t setObjectId);
EventManager(object_id_t setObjectId, uint32_t eventQueueDepth);
virtual ~EventManager();
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);

View File

@ -10,7 +10,7 @@ enum : uint8_t {
CDH = 28,
TCS_1 = 59,
PCDU_1 = 42,
PCDU_2 = 43,
POWER_SWITCH_IF = 43,
HEATER = 50,
T_SENSORS = 52,
FDIR = 70,

View File

@ -68,7 +68,7 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId,
parameterWrapper->set(faultCount);
break;
case ParameterIds::TIMEOUT:
parameterWrapper->set(timer.timeout);
parameterWrapper->set(timer.getTimeoutMs());
break;
default:
return INVALID_IDENTIFIER_ID;

View File

@ -8,10 +8,8 @@ PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(LocalPoolDataSetBase* own
: owner(owner) {}
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor) {
dur_millis_t minimumPeriodicInterval) {
this->minimumPeriodicInterval = minimumPeriodicInterval;
this->nonDiagIntervalFactor = nonDiagIntervalFactor;
collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval);
/* This will cause a checkOpNecessary call to be true immediately. I think it's okay
if a HK packet is generated immediately instead of waiting one generation cycle. */
@ -36,42 +34,17 @@ uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks(
if (owner == nullptr) {
return 0;
}
bool isDiagnostics = owner->isDiagnostics();
/* Avoid division by zero */
if (minimumPeriodicInterval == 0) {
if (isDiagnostics) {
/* Perform operation each cycle */
return 1;
} else {
return nonDiagIntervalFactor;
}
/* Perform operation each cycle */
return 1;
} else {
dur_millis_t intervalInMs = collectionIntervalSeconds * 1000;
uint32_t divisor = minimumPeriodicInterval;
if (not isDiagnostics) {
/* We need to multiply the divisor because non-diagnostics only
allow a multiple of the minimum periodic interval */
divisor *= nonDiagIntervalFactor;
}
uint32_t ticks = std::ceil(static_cast<float>(intervalInMs) / divisor);
if (not isDiagnostics) {
/* Now we need to multiply the calculated ticks with the factor as as well
because the minimum tick count to generate a non-diagnostic is the factor itself.
Example calculation for non-diagnostic with
0.4 second interval and 0.2 second task interval.
Resultant tick count of 5 is equal to operation each second.
Examle calculation for non-diagnostic with 2.0 second interval and 0.2 second
task interval.
Resultant tick count of 10 is equal to operatin every 2 seconds.
Example calculation for diagnostic with 0.4 second interval and 0.3
second task interval. Resulting tick count of 2 is equal to operation
every 0.6 seconds. */
ticks *= nonDiagIntervalFactor;
}
return ticks;
}
}

View File

@ -11,8 +11,7 @@ class PeriodicHousekeepingHelper {
public:
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor);
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval);
void changeCollectionInterval(float newInterval);
float getCollectionIntervalInSeconds() const;
@ -20,7 +19,6 @@ class PeriodicHousekeepingHelper {
private:
LocalPoolDataSetBase* owner = nullptr;
uint8_t nonDiagIntervalFactor = 0;
uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds);
float intervalTicksToSeconds(uint32_t collectionInterval) const;

View File

@ -7,14 +7,17 @@
class MutexGuard {
public:
MutexGuard(MutexIF* mutex, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::BLOCKING,
uint32_t timeoutMs = 0)
uint32_t timeoutMs = 0, const char* context = nullptr)
: internalMutex(mutex) {
if (context == nullptr) {
context = "unknown";
}
if (mutex == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexGuard: Passed mutex is invalid!" << std::endl;
sif::error << "MutexGuard::" << context << ": Passed mutex is invalid!" << std::endl;
#else
sif::printError("MutexGuard: Passed mutex is invalid!\n");
sif::printError("MutexGuard::%s: Passed mutex is invalid!\n", context);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return;
@ -23,11 +26,11 @@ class MutexGuard {
#if FSFW_VERBOSE_LEVEL >= 1
if (result == MutexIF::MUTEX_TIMEOUT) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexGuard: Lock of mutex failed with timeout of " << timeoutMs
<< " milliseconds!" << std::endl;
sif::error << "MutexGuard::" << context << ": Lock of mutex failed with timeout of "
<< timeoutMs << " milliseconds!" << std::endl;
#else
sif::printError("MutexGuard: Lock of mutex failed with timeout of %lu milliseconds\n",
timeoutMs);
sif::printError("MutexGuard::%s: Lock of mutex failed with timeout of %lu milliseconds\n",
context, timeoutMs);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
} else if (result != returnvalue::OK) {

View File

@ -16,9 +16,9 @@
#endif
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId,
object_id_t tcStoreId)
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) {
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId)
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
// Connection is always up, TM is requested by connecting to server and receiving packets
registerCommConnect();

View File

@ -38,7 +38,7 @@ class TcpTmTcBridge : public TmTcBridge {
* @param tmStoreId TM store object ID. It is recommended to the default object ID
* @param tcStoreId TC store object ID. It is recommended to the default object ID
*/
TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, uint32_t msgQueueDepth,
object_id_t tmStoreId = objects::TM_STORE,
object_id_t tcStoreId = objects::TC_STORE);
virtual ~TcpTmTcBridge();

View File

@ -20,9 +20,9 @@
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
const std::string &udpServerPort_, object_id_t tmStoreId,
object_id_t tcStoreId)
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) {
uint32_t msgQueueDepth, const std::string &udpServerPort_,
object_id_t tmStoreId, object_id_t tcStoreId)
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
if (udpServerPort_.empty()) {
udpServerPort = DEFAULT_SERVER_PORT;
} else {

View File

@ -29,7 +29,7 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
/* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_SERVER_PORT;
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, uint32_t msgQueueDepth,
const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
object_id_t tcStoreId = objects::TC_STORE);
~UdpTmTcBridge() override;

View File

@ -47,7 +47,32 @@ ReturnValue_t Clock::setClock(const timeval* time) {
return returnvalue::OK;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
ReturnValue_t Clock::getClockMonotonic(timeval* time) {
#if defined(PLATFORM_WIN)
// TODO: Implement with std::chrono::steady_clock.. or in some other way. I am not even sure
// whether this is possible with steady_clock. The conversion we have to do here just to be
// generic is kind of awkward..
return returnvalue::FAILED;
#elif defined(PLATFORM_UNIX)
timespec timeMonotonic;
int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic);
if (status != 0) {
return returnvalue::FAILED;
}
time->tv_sec = timeMonotonic.tv_sec;
time->tv_usec = timeMonotonic.tv_nsec / 1000.0;
return returnvalue::OK;
#else
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl;
#else
sif::printWarning("Clock::getUptime: Not implemented for found OS!\n");
#endif
return returnvalue::FAILED;
#endif
}
ReturnValue_t Clock::getClock(timeval* time) {
#if defined(PLATFORM_WIN)
auto now = std::chrono::system_clock::now();
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
@ -75,6 +100,8 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
#endif
}
ReturnValue_t Clock::getClock_timeval(timeval* time) { return Clock::getClock(time); }
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
if (time == nullptr) {
return returnvalue::FAILED;

View File

@ -20,16 +20,18 @@ TaskFactory::~TaskFactory() = default;
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
PeriodicTaskIF* TaskFactory::createPeriodicTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_,
void* args) {
return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_, void* args) {
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
}

View File

@ -42,7 +42,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
return returnvalue::OK;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
ReturnValue_t Clock::getClock(timeval* time) {
timespec timeUnix{};
int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
if (status != 0) {
@ -53,6 +53,8 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
return returnvalue::OK;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) { return Clock::getClock(time); }
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval timeVal{};
ReturnValue_t result = getClock_timeval(&timeVal);
@ -64,6 +66,17 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
return returnvalue::OK;
}
ReturnValue_t Clock::getClockMonotonic(timeval* time) {
timespec timeMonotonic{};
int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic);
if (status != 0) {
return returnvalue::FAILED;
}
time->tv_sec = timeMonotonic.tv_sec;
time->tv_usec = timeMonotonic.tv_nsec / 1000.0;
return returnvalue::OK;
}
timeval Clock::getUptime() {
timeval uptime{};
auto result = getUptime(&uptime);
@ -79,11 +92,16 @@ ReturnValue_t Clock::getUptime(timeval* uptime) {
// TODO This is not posix compatible and delivers only seconds precision
// Linux specific file read but more precise.
double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) {
std::ifstream ifile("/proc/uptime");
if (ifile.bad()) {
return returnvalue::FAILED;
}
if (ifile >> uptimeSeconds) {
uptime->tv_sec = uptimeSeconds;
uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6);
return returnvalue::OK;
}
return returnvalue::OK;
return returnvalue::FAILED;
}
// Wait for new FSFW Clock function delivering seconds uptime.

View File

@ -7,10 +7,15 @@
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_)
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_,
PosixThreadArgs* args)
: FixedTimeslotTaskBase(periodSeconds_, dlmFunc_),
posixThread(name_, priority_, stackSize_),
started(false) {}
posixThread(name_, SchedulingPolicy::REGULAR, priority_, stackSize_),
started(false) {
if (args != nullptr) {
posixThread.setSchedPolicy(args->policy);
}
}
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
// The argument is re-interpreted as PollingTask.

View File

@ -23,7 +23,8 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase {
* @param deadlineMissedFunc_
*/
FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_);
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_,
PosixThreadArgs* args);
~FixedTimeslotTask() override = default;
ReturnValue_t startTask() override;

View File

@ -4,10 +4,15 @@
#include "fsfw/tasks/ExecutableObjectIF.h"
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_,
PosixThreadArgs* args)
: PeriodicTaskBase(period_, dlmFunc_),
posixThread(name_, priority_, stackSize_),
started(false) {}
posixThread(name_, SchedulingPolicy::REGULAR, priority_, stackSize_),
started(false) {
if (args != nullptr) {
posixThread.setSchedPolicy(args->policy);
}
}
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
// The argument is re-interpreted as PollingTask.

View File

@ -24,7 +24,7 @@ class PeriodicPosixTask : public PeriodicTaskBase {
* @param deadlineMissedFunc_
*/
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_,
TaskDeadlineMissedFunction dlmFunc_);
TaskDeadlineMissedFunction dlmFunc_, PosixThreadArgs* args);
~PeriodicPosixTask() override = default;
/**

View File

@ -7,8 +7,9 @@
#include "fsfw/osal/linux/unixUtility.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_)
: thread(0), priority(priority_), stackSize(stackSize_) {
PosixThread::PosixThread(const char* name_, SchedulingPolicy schedPolciy, int priority_,
size_t stackSize_)
: thread(0), schedPolicy(schedPolciy), priority(priority_), stackSize(stackSize_) {
name[0] = '\0';
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
}
@ -178,20 +179,30 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
#ifndef FSFW_USE_REALTIME_FOR_LINUX
#error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1"
#endif
if (schedPolicy == SchedulingPolicy::RR) {
// RR -> This needs root privileges for the process
#if FSFW_USE_REALTIME_FOR_LINUX == 1
// FIFO -> This needs root privileges for the process
status = pthread_attr_setschedpolicy(&attributes, SCHED_FIFO);
if (status != 0) {
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy");
status = pthread_attr_setschedpolicy(&attributes, SCHED_RR);
if (status != 0) {
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy");
}
sched_param scheduleParams;
scheduleParams.sched_priority = priority;
status = pthread_attr_setschedparam(&attributes, &scheduleParams);
if (status != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "PosixThread: Setting priority failed" << std::endl;
#endif
}
#else
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning
<< "Real time priorities are only allowed if FSFW_USE_REALTIME_FOR_LINUX is set to 1"
<< std::endl;
#endif
#endif
}
sched_param scheduleParams;
scheduleParams.__sched_priority = priority;
status = pthread_attr_setschedparam(&attributes, &scheduleParams);
if (status != 0) {
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedparam");
}
#endif
// Set Signal Mask for suspend until startTask is called
sigset_t waitSignal;
sigemptyset(&waitSignal);
@ -243,3 +254,5 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_destroy");
}
}
void PosixThread::setSchedPolicy(SchedulingPolicy policy) { this->schedPolicy = policy; }

View File

@ -9,10 +9,15 @@
#include "../../returnvalues/returnvalue.h"
enum SchedulingPolicy { REGULAR, RR };
struct PosixThreadArgs {
SchedulingPolicy policy = SchedulingPolicy::REGULAR;
};
class PosixThread {
public:
static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16;
PosixThread(const char* name_, int priority_, size_t stackSize_);
PosixThread(const char* name_, SchedulingPolicy schedPolicy, int priority_, size_t stackSize_);
virtual ~PosixThread();
/**
* Set the Thread to sleep state
@ -20,6 +25,9 @@ class PosixThread {
* @return Returns Failed if sleep fails
*/
static ReturnValue_t sleep(uint64_t ns);
void setSchedPolicy(SchedulingPolicy policy);
/**
* @brief Function to suspend the task until SIGUSR1 was received
*
@ -72,6 +80,7 @@ class PosixThread {
private:
char name[PTHREAD_MAX_NAMELEN];
SchedulingPolicy schedPolicy;
int priority;
size_t stackSize = 0;

View File

@ -12,18 +12,20 @@ TaskFactory::~TaskFactory() = default;
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
PeriodicTaskIF* TaskFactory::createPeriodicTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_,
void* args) {
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
deadLineMissedFunction_, reinterpret_cast<PosixThreadArgs*>(args));
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_, void* args) {
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
deadLineMissedFunction_, reinterpret_cast<PosixThreadArgs*>(args));
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {

View File

@ -1,5 +1,5 @@
#include "fsfw/osal/rtems/BinarySemaphore.h"
//#include "fsfw/osal/rtems/CountingSemaphore.h"
// #include "fsfw/osal/rtems/CountingSemaphore.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tasks/SemaphoreFactory.h"

View File

@ -32,7 +32,7 @@ class Fuse : public SystemObject,
gp_id_t poolIdPower;
};
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1;
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::POWER_SWITCH_IF;
//! PSS detected that current on a fuse is totally out of bounds.
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
//! PSS detected a fuse that went off.

View File

@ -28,7 +28,9 @@ class PowerSwitchIF {
static const ReturnValue_t SWITCH_TIMEOUT = MAKE_RETURN_CODE(2);
static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3);
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2;
static const ReturnValue_t SWITCH_UNKNOWN = MAKE_RETURN_CODE(5);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::POWER_SWITCH_IF;
//!< Someone detected that a switch went off which shouldn't. Severity:
//!< Low, Parameter1: switchId1, Parameter2: switchId2
static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
@ -50,6 +52,7 @@ class PowerSwitchIF {
* @return
* - @c SWITCH_ON if the specified switch is on.
* - @c SWITCH_OFF if the specified switch is off.
* - @c SWITCH_UNKNOWN if the state of the specified switch is unknown.
* - @c returnvalue::FAILED if an error occured
*/
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0;

View File

@ -2,6 +2,7 @@
#include <fsfw/ipc/QueueFactory.h>
#include <fsfw/power/PowerSwitchIF.h>
#include <fsfw/subsystem/helper.h>
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
power::Switch_t pwrSwitch)
@ -28,6 +29,9 @@ ReturnValue_t PowerSwitcherComponent::performOperation(uint8_t opCode) {
continue;
}
}
if (getHealth() == FAULTY) {
performFaultyOperation();
}
if (switcher.active()) {
switcher.doStateMachine();
auto currState = switcher.getState();
@ -111,9 +115,11 @@ const HasHealthIF* PowerSwitcherComponent::getOptHealthIF() const { return this;
const HasModesIF& PowerSwitcherComponent::getModeIF() const { return *this; }
ReturnValue_t PowerSwitcherComponent::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
return parent.registerChild(*this);
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
}
object_id_t PowerSwitcherComponent::getObjectId() const { return SystemObject::getObjectId(); }
ModeTreeChildIF& PowerSwitcherComponent::getModeTreeChildIF() { return *this; }
void PowerSwitcherComponent::performFaultyOperation() {}

View File

@ -1,5 +1,4 @@
#ifndef _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
#define _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
#pragma once
#include <fsfw/health/HasHealthIF.h>
#include <fsfw/health/HealthHelper.h>
@ -37,9 +36,11 @@ class PowerSwitcherComponent : public SystemObject,
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
ModeTreeChildIF &getModeTreeChildIF() override;
protected:
PowerSwitcher switcher;
private:
MessageQueueIF *queue = nullptr;
PowerSwitcher switcher;
Mode_t mode = MODE_OFF;
Submode_t submode = 0;
@ -49,24 +50,23 @@ class PowerSwitcherComponent : public SystemObject,
void setMode(Mode_t newMode, Submode_t newSubmode);
virtual ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initialize() override;
MessageQueueId_t getCommandQueue() const override;
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
void getMode(Mode_t *mode, Submode_t *submode) override;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override;
void startTransition(Mode_t mode, Submode_t submode) override;
virtual void performFaultyOperation();
void setToExternalControl() override;
void announceMode(bool recursive) override;
ReturnValue_t setHealth(HealthState health) override;
HasHealthIF::HealthState getHealth() override;
object_id_t getObjectId() const override;
const HasHealthIF *getOptHealthIF() const override;
const HasModesIF &getModeIF() const override;
[[nodiscard]] object_id_t getObjectId() const override;
[[nodiscard]] const HasHealthIF *getOptHealthIF() const override;
[[nodiscard]] const HasModesIF &getModeIF() const override;
};
#endif /* _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ */

View File

@ -10,9 +10,23 @@
CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args)
: CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service,
args.numParallelCommands, args.commandTimeoutSeconds),
healthTable(args.table),
healthTableId(args.table),
maxNumHealthInfoPerCycle(args.maxNumHealthInfoPerCycle) {}
ReturnValue_t CServiceHealthCommanding::initialize() {
ReturnValue_t result = CommandingServiceBase::initialize();
if (result != returnvalue::OK) {
return result;
}
healthTable = ObjectManager::instance()->get<HealthTable>(healthTableId);
if (healthTable == nullptr) {
return returnvalue::FAILED;
}
return returnvalue::OK;
}
ReturnValue_t CServiceHealthCommanding::isValidSubservice(uint8_t subservice) {
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH):
@ -68,6 +82,9 @@ ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message,
ReturnValue_t result = returnvalue::OK;
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH): {
if (tcDataLen != sizeof(object_id_t) + sizeof(HasHealthIF::HealthState)) {
return CommandingServiceBase::INVALID_TC;
}
HealthSetCommand healthCommand;
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
if (result != returnvalue::OK) {
@ -88,14 +105,6 @@ ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message,
return EXECUTION_COMPLETE;
}
return result;
while (true) {
ReturnValue_t result = iterateHealthTable(false);
if (result != returnvalue::OK) {
break;
}
}
return returnvalue::OK;
}
default: {
// Should never happen, subservice was already checked
@ -142,7 +151,7 @@ void CServiceHealthCommanding::doPeriodicOperation() {
ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) {
std::pair<object_id_t, HasHealthIF::HealthState> pair;
ReturnValue_t result = healthTable.iterate(&pair, reset);
ReturnValue_t result = healthTable->iterate(&pair, reset);
if (result != returnvalue::OK) {
return result;
} else {

View File

@ -6,7 +6,7 @@
#include "fsfw/tmtcservices/CommandingServiceBase.h"
struct HealthServiceCfg {
HealthServiceCfg(object_id_t objectId, uint16_t apid, HealthTable &healthTable,
HealthServiceCfg(object_id_t objectId, uint16_t apid, object_id_t healthTable,
uint16_t maxNumHealthInfoPerCycle)
: objectId(objectId),
apid(apid),
@ -14,7 +14,7 @@ struct HealthServiceCfg {
maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {}
object_id_t objectId;
uint16_t apid;
HealthTable &table;
object_id_t table;
uint16_t maxNumHealthInfoPerCycle;
uint8_t service = 201;
uint8_t numParallelCommands = 4;
@ -40,6 +40,8 @@ class CServiceHealthCommanding : public CommandingServiceBase {
CServiceHealthCommanding(HealthServiceCfg args);
~CServiceHealthCommanding() override = default;
ReturnValue_t initialize() override;
protected:
/* CSB abstract function implementations */
ReturnValue_t isValidSubservice(uint8_t subservice) override;
@ -57,7 +59,8 @@ class CServiceHealthCommanding : public CommandingServiceBase {
void doPeriodicOperation() override;
private:
HealthTable &healthTable;
const object_id_t healthTableId;
HealthTable *healthTable;
uint16_t maxNumHealthInfoPerCycle = 0;
bool reportAllHealth = false;
ReturnValue_t iterateHealthTable(bool reset);

View File

@ -10,11 +10,11 @@
//////////////////////////////////////////////////////////////////////////////////
// RMAP command bits
//#define RMAP_COMMAND_BIT_INCREMENT 2
//#define RMAP_COMMAND_BIT_REPLY 3
//#define RMAP_COMMAND_BIT_WRITE 5
//#define RMAP_COMMAND_BIT_VERIFY 4
//#define RMAP_COMMAND_BIT 6
// #define RMAP_COMMAND_BIT_INCREMENT 2
// #define RMAP_COMMAND_BIT_REPLY 3
// #define RMAP_COMMAND_BIT_WRITE 5
// #define RMAP_COMMAND_BIT_VERIFY 4
// #define RMAP_COMMAND_BIT 6
namespace RMAPIds {
@ -32,14 +32,14 @@ static const uint8_t RMAP_COMMAND_READ = ((1 << RMAP_COMMAND_BIT) | (1 << RMAP_C
static const uint8_t RMAP_REPLY_WRITE =
((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY));
static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY));
//#define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE)
// #define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE)
//| (1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) |
//(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define
// RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
// RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
//#define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
// #define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
//(1<<RMAP_COMMAND_BIT_REPLY))
//#define RMAP_REPLY_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT_WRITE) |
// #define RMAP_REPLY_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT_WRITE) |
//(1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define RMAP_REPLY_READ
//((1<<RMAP_COMMAND_BIT_REPLY))
@ -49,9 +49,9 @@ static const uint8_t RMAP_COMMAND_HEADER_LEN = 16;
static const uint8_t RMAP_WRITE_REPLY_HEADER_LEN = 8;
static const uint8_t RMAP_READ_REPLY_HEADER_LEN = 12;
static const uint8_t RMAP_DATA_FOOTER_SIZE = 1; // SIZE OF CRC
//#define RMAP_COMMAND_HEADER_LEN 16
//#define RMAP_WRITE_REPLY_HEADER_LEN 8
//#define RMAP_READ_REPLY_HEADER_LEN 12
// #define RMAP_COMMAND_HEADER_LEN 16
// #define RMAP_WRITE_REPLY_HEADER_LEN 8
// #define RMAP_READ_REPLY_HEADER_LEN 12
} // namespace RMAPIds

View File

@ -3,14 +3,14 @@
#include "fsfw/FSFW.h"
PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPoolConfig)
: LocalPool(setObjectId, localPoolConfig, true) {
: LocalPool(setObjectId, localPoolConfig, true, true) {
mutex = MutexFactory::instance()->createMutex();
}
PoolManager::~PoolManager() { MutexFactory::instance()->deleteMutex(mutex); }
ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address) {
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs);
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX);
ReturnValue_t status = LocalPool::reserveSpace(size, address);
return status;
}
@ -22,12 +22,12 @@ ReturnValue_t PoolManager::deleteData(store_address_t storeId) {
<< storeId.poolIndex << ". id is " << storeId.packetIndex << std::endl;
#endif
#endif
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs);
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX);
return LocalPool::deleteData(storeId);
}
ReturnValue_t PoolManager::deleteData(uint8_t* buffer, size_t size, store_address_t* storeId) {
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20);
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX);
ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId);
return status;
}

View File

@ -56,6 +56,7 @@ class PoolManager : public LocalPool {
protected:
//! Default mutex timeout value to prevent permanent blocking.
uint32_t mutexTimeoutMs = 20;
static constexpr char LOCK_CTX[] = "PoolManager";
ReturnValue_t reserveSpace(size_t size, store_address_t* address) override;

View File

@ -21,6 +21,7 @@ SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(c
ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry> tableIter,
Submode_t targetSubmode) {
using namespace mode;
std::map<object_id_t, ChildInfo>::iterator childIter;
for (; tableIter.value != NULL; ++tableIter) {
@ -34,13 +35,21 @@ ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry
return returnvalue::FAILED;
}
Submode_t submodeToCheckAgainst = tableIter.value->getSubmode();
// Check submodes here.
uint8_t mask;
bool submodesAllowedMask = tableIter.value->submodesAllowed(&mask);
uint8_t submodeToCheckAgainst = tableIter.value->getSubmode();
if (tableIter.value->inheritSubmode()) {
submodeToCheckAgainst = targetSubmode;
}
if (childIter->second.submode != submodeToCheckAgainst) {
return returnvalue::FAILED;
if (submodesAllowedMask) {
if ((childIter->second.submode | mask) != mask) {
return returnvalue::FAILED;
}
} else {
if (childIter->second.submode != submodeToCheckAgainst) {
return returnvalue::FAILED;
}
}
}
return returnvalue::OK;

View File

@ -1,111 +1,126 @@
#ifndef FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
#define FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
#include "../../modes/HasModesIF.h"
#include "../../objectmanager/SystemObjectIF.h"
#include "../../serialize/SerialLinkedListAdapter.h"
#include "../../serialize/SerializeIF.h"
#include "fsfw/modes/HasModesIF.h"
#include "fsfw/objectmanager/SystemObjectIF.h"
#include "fsfw/serialize/SerialLinkedListAdapter.h"
#include "fsfw/serialize/SerializeIF.h"
class ModeListEntry : public SerializeIF, public LinkedElement<ModeListEntry> {
namespace mode {
enum SpecialSubmodeFlags : uint8_t { INHERIT = 1 << 0, ALLOWED_MASK = 1 << 1 };
}
class ModeListEntry : public SerialLinkedListAdapter<SerializeIF>,
public LinkedElement<ModeListEntry> {
public:
ModeListEntry() : LinkedElement<ModeListEntry>(this) {}
static constexpr uint8_t ALL_SUBMODES_ALLOWED_MASK = 0xff;
uint32_t value1 = 0;
uint32_t value2 = 0;
uint8_t value3 = 0;
uint8_t value4 = 0;
ModeListEntry() : SerialLinkedListAdapter(), LinkedElement<ModeListEntry>(this) { setLinks(); }
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const {
ReturnValue_t result;
SerializeElement<uint32_t> value1 = 0;
SerializeElement<uint32_t> value2 = 0;
SerializeElement<uint8_t> value3 = 0;
SerializeElement<uint8_t> value4 = 0;
SerializeElement<uint8_t> value5 = 0;
result = SerializeAdapter::serialize(&value1, buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
result = SerializeAdapter::serialize(&value2, buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
result = SerializeAdapter::serialize(&value3, buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
result = SerializeAdapter::serialize(&value4, buffer, size, maxSize, streamEndianness);
return result;
ModeListEntry(const ModeListEntry& other)
: SerialLinkedListAdapter(), LinkedElement<ModeListEntry>(this) {
value1.entry = other.value1.entry;
value2.entry = other.value2.entry;
value3.entry = other.value3.entry;
value4.entry = other.value4.entry;
value5.entry = other.value5.entry;
setLinks();
}
virtual size_t getSerializedSize() const {
return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4);
ModeListEntry& operator=(const ModeListEntry& other) {
this->value1.entry = other.value1.entry;
this->value2.entry = other.value2.entry;
this->value3.entry = other.value3.entry;
this->value4.entry = other.value4.entry;
this->value5.entry = other.value5.entry;
return *this;
}
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
ReturnValue_t result;
result = SerializeAdapter::deSerialize(&value1, buffer, size, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
result = SerializeAdapter::deSerialize(&value2, buffer, size, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
result = SerializeAdapter::deSerialize(&value3, buffer, size, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
result = SerializeAdapter::deSerialize(&value4, buffer, size, streamEndianness);
return result;
void setLinks() {
setStart(&value1);
value1.setNext(&value2);
value2.setNext(&value3);
value3.setNext(&value4);
value4.setNext(&value5);
}
// for Sequences
Mode_t getTableId() const { return value1; }
Mode_t getTableId() const { return value1.entry; }
void setTableId(Mode_t tableId) { this->value1 = tableId; }
void setTableId(Mode_t tableId) { this->value1.entry = tableId; }
uint8_t getWaitSeconds() const { return value2; }
uint8_t getWaitSeconds() const { return value2.entry; }
void setWaitSeconds(uint8_t waitSeconds) { this->value2 = waitSeconds; }
void setWaitSeconds(uint8_t waitSeconds) { this->value2.entry = waitSeconds; }
bool checkSuccess() const { return value3 == 1; }
bool checkSuccess() const { return value3.entry == 1; }
void setCheckSuccess(bool checkSuccess) { this->value3 = checkSuccess; }
void setCheckSuccess(bool checkSuccess) { this->value3.entry = checkSuccess; }
// for Tables
object_id_t getObject() const { return value1; }
object_id_t getObject() const { return value1.entry; }
void setObject(object_id_t object) { this->value1 = object; }
void setObject(object_id_t object) { this->value1.entry = object; }
Mode_t getMode() const { return value2; }
Mode_t getMode() const { return value2.entry; }
void setMode(Mode_t mode) { this->value2 = mode; }
void setMode(Mode_t mode) { this->value2.entry = mode; }
Submode_t getSubmode() const { return value3; }
Submode_t getSubmode() const { return value3.entry; }
void setSubmode(Submode_t submode) { this->value3 = submode; }
void setSubmode(Submode_t submode) { this->value3.entry = submode; }
bool inheritSubmode() const { return value4 == 1; }
void setInheritSubmode(bool inherit) {
if (inherit) {
value4 = 1;
} else {
value4 = 0;
bool inheritSubmode() const {
return (value4.entry & mode::SpecialSubmodeFlags::INHERIT) ==
mode::SpecialSubmodeFlags::INHERIT;
}
bool submodesAllowed(uint8_t* mask) const {
bool submodesAllowed = (value4.entry & mode::SpecialSubmodeFlags::ALLOWED_MASK) ==
mode::SpecialSubmodeFlags::ALLOWED_MASK;
if (submodesAllowed and mask != nullptr) {
*mask = value5.entry;
}
return submodesAllowed;
}
bool operator==(ModeListEntry other) {
return ((value1 == other.value1) && (value2 == other.value2) && (value3 == other.value3));
/**
* Enable the inheritance of submodes. This is relevant for both the execution
* of mode tables and for mode checking.
*/
void enableInheritSubmode() { value4.entry |= mode::SpecialSubmodeFlags::INHERIT; }
/**
* Disable the inheritance of submodes. This is relevant for both the execution
* of mode tables and for mode checking.
*/
void disableInheritSubmode() { value4.entry &= ~mode::SpecialSubmodeFlags::INHERIT; }
/**
* Specialization of @enableSubmodeAllowed which allows all submodes.
*/
void allowAllSubmodes() { enableSubmodeAllowed(ALL_SUBMODES_ALLOWED_MASK); }
/**
* Enable an allowed submode mask for mode checks. Any submode which contains bits
* outside of the mask will be declined.
*
* For example, for a mask of 0b11, only the modes 0b00, 0b01 and 0b11 will be accepted.
*/
void enableSubmodeAllowed(uint8_t mask) {
value4.entry |= mode::SpecialSubmodeFlags::ALLOWED_MASK;
value5.entry = mask;
}
/**
* Enforce the equality of submodes for mode checks. This is the default.
*/
void disableSubmodeAllowed() {
value4.entry &= ~mode::SpecialSubmodeFlags::ALLOWED_MASK;
value5.entry = 0;
}
};

View File

@ -47,7 +47,8 @@ class TaskFactory {
*/
PeriodicTaskIF* createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
TaskStackSize stackSize_, TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_);
TaskDeadlineMissedFunction deadLineMissedFunction_,
void* args = nullptr);
/**
* The meaning for the variables for fixed timeslot tasks is the same as for periodic tasks.
@ -62,7 +63,8 @@ class TaskFactory {
FixedTimeslotTaskIF* createFixedTimeslotTask(TaskName name_, TaskPriority taskPriority_,
TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_);
TaskDeadlineMissedFunction deadLineMissedFunction_,
void* args = nullptr);
/**
* Function to be called to delete a task

View File

@ -283,7 +283,7 @@ ReturnValue_t Heater::getParameter(uint8_t domainId, uint8_t uniqueId,
}
switch (uniqueId) {
case 0:
parameterWrapper->set(heaterOnCountdown.timeout);
parameterWrapper->set(heaterOnCountdown.getTimeoutMs());
break;
default:
return INVALID_IDENTIFIER_ID;

View File

@ -49,6 +49,13 @@ class Clock {
* @return -@c returnvalue::OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t setClock(const timeval *time);
/**
* @deprecated Use getClock instead, which does the same.
* @param time
* @return
*/
static ReturnValue_t getClock_timeval(timeval *time);
/**
* This system call returns the current system clock in timeval format.
* The timval format has the fields @c tv_sec with seconds and @c tv_usec with
@ -56,7 +63,18 @@ class Clock {
* @param time A pointer to a timeval struct where the current time is stored.
* @return @c returnvalue::OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t getClock_timeval(timeval *time);
static ReturnValue_t getClock(timeval *time);
/**
* Retrieve a monotonic clock. This clock this is also more suited for measuring elapsed times
* between two time points, but less suited when the absolute time is required.
*
* Implementation example: A generic UNIX implementation can use CLOCK_MONOTONIC_RAW with
* `clock_gettime`.
* @param time
* @return
*/
static ReturnValue_t getClockMonotonic(timeval *time);
/**
* Get the time since boot in a timeval struct

View File

@ -1,49 +1,62 @@
#include "fsfw/timemanager/Countdown.h"
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
#include "fsfw/globalfunctions/timevalOperations.h"
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) {
if (startImmediately) {
setTimeout(initialTimeout);
} else {
timeout = initialTimeout;
timeout.tv_sec = initialTimeout / 1000;
timeout.tv_usec = (initialTimeout % 1000) * 1000;
}
}
Countdown::~Countdown() {}
Countdown::~Countdown() = default;
ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) {
ReturnValue_t returnValue = Clock::getUptime(&startTime);
timeout = milliseconds;
return returnValue;
timeout.tv_sec = milliseconds / 1000;
timeout.tv_usec = (milliseconds % 1000) * 1000;
return Clock::getClockMonotonic(&startTime);
}
bool Countdown::hasTimedOut() const {
if (uint32_t(this->getCurrentTime() - startTime) >= timeout) {
// Account for system clock going back in time.
if (getCurrentTime() < startTime) {
return true;
} else {
return false;
}
if (getCurrentTime() - startTime >= timeout) {
return true;
}
return false;
}
bool Countdown::isBusy() const { return !hasTimedOut(); }
ReturnValue_t Countdown::resetTimer() { return setTimeout(timeout); }
ReturnValue_t Countdown::resetTimer() { return setTimeoutTv(timeout); }
void Countdown::timeOut() { startTime = this->getCurrentTime() - timeout; }
uint32_t Countdown::getRemainingMillis() const {
// We fetch the time before the if-statement
// to be sure that the return is in
// range 0 <= number <= timeout
uint32_t currentTime = this->getCurrentTime();
if (this->hasTimedOut()) {
return 0;
} else {
return (startTime + timeout) - currentTime;
}
timeval remainingMillisTv = (startTime + timeout) - this->getCurrentTime();
return remainingMillisTv.tv_sec * 1000 + remainingMillisTv.tv_usec / 1000;
}
uint32_t Countdown::getCurrentTime() const {
uint32_t currentTime;
Clock::getUptime(&currentTime);
uint32_t Countdown::timevalToMs(timeval &tv) { return tv.tv_sec * 1000 + tv.tv_usec / 1000; }
ReturnValue_t Countdown::setTimeoutTv(timeval tv) {
timeout = tv;
return Clock::getClockMonotonic(&startTime);
}
uint32_t Countdown::getTimeoutMs() const { return timeout.tv_sec * 1000 + timeout.tv_usec / 1000; }
timeval Countdown::getTimeout() const { return timeout; }
timeval Countdown::getCurrentTime() const {
timeval currentTime{};
Clock::getClockMonotonic(&currentTime);
return currentTime;
}

View File

@ -6,6 +6,10 @@
/**
*
* Countdown keeps track of a timespan.
* This class uses the system clock internally to achieve
* a high resolution. This means that the API is only partially
* resistant against time jumps. The user must take care to account
* for time jumps in some from if this relevant.
*
* Countdown::resetTimer restarts the timer.
* Countdown::setTimeout sets a new countdown duration and resets.
@ -39,6 +43,8 @@ class Countdown {
* @return Returnvalue from Clock::getUptime
*/
ReturnValue_t setTimeout(uint32_t milliseconds);
ReturnValue_t setTimeoutTv(timeval tv);
/**
* Returns true if the countdown duration has passed.
*
@ -61,22 +67,31 @@ class Countdown {
* Returns the remaining milliseconds (0 if timeout)
*/
uint32_t getRemainingMillis() const;
uint32_t getTimeoutMs() const;
timeval getTimeout() const;
/**
* Makes hasTimedOut() return true
*/
void timeOut();
/**
* Internal countdown duration in milliseconds
*/
uint32_t timeout;
static inline uint32_t timevalToMs(timeval& tv);
private:
/**
* Last time the timer was started (uptime)
* Start time of the countdown.
*/
uint32_t startTime = 0;
timeval startTime{};
uint32_t getCurrentTime() const;
/**
* Timeout as timeval type. The countdown has timed out when the
* current time exceeds the start time plus the timeout.
*/
timeval timeout{};
timeval getCurrentTime() const;
};
#endif /* FSFW_TIMEMANAGER_COUNTDOWN_H_ */

View File

@ -9,10 +9,10 @@
Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode)
: displayOnDestruction(displayOnDestruction), displayMode(displayMode) {
// Measures start time on initialization.
Clock::getClock_timeval(&startTime);
Clock::getClockMonotonic(&startTime);
}
void Stopwatch::start() { Clock::getUptime(&startTime); }
void Stopwatch::start() { Clock::getClockMonotonic(&startTime); }
dur_millis_t Stopwatch::stop(bool display) {
stopInternal();
@ -63,6 +63,6 @@ StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; }
void Stopwatch::stopInternal() {
timeval endTime;
Clock::getClock_timeval(&endTime);
Clock::getClockMonotonic(&endTime);
elapsedTime = endTime - startTime;
}

View File

@ -8,7 +8,7 @@
#define TMTCBRIDGE_WIRETAPPING 0
TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId)
uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId)
: SystemObject(objectId),
name(name),
tmStoreId(tmStoreId),
@ -18,7 +18,7 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
{
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
msgQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }

View File

@ -15,7 +15,6 @@ class TmTcBridge : public AcceptsTelemetryIF,
public ExecutableObjectIF,
public SystemObject {
public:
static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20;
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500;
@ -23,7 +22,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId);
uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId);
~TmTcBridge() override;
/**

View File

@ -15,7 +15,8 @@ ReturnValue_t HostFilesystem::writeToFile(FileOpParams params, const uint8_t *da
return returnvalue::FAILED;
}
path path(params.path());
if (not exists(path)) {
std::error_code e;
if (not exists(path, e)) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
}
// This is equivalent to "r+" mode, which is what we need here. Only using ::out would truncate
@ -35,7 +36,8 @@ ReturnValue_t HostFilesystem::readFromFile(FileOpParams params, uint8_t **buffer
return returnvalue::FAILED;
}
path path(params.path());
if (not exists(path)) {
std::error_code e;
if (not exists(path, e)) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
}
ifstream file(path);
@ -59,7 +61,8 @@ ReturnValue_t HostFilesystem::createFile(FilesystemParams params, const uint8_t
return returnvalue::FAILED;
}
path path(params.path);
if (exists(path)) {
std::error_code e;
if (exists(path, e)) {
return HasFileSystemIF::FILE_ALREADY_EXISTS;
}
ofstream file(path);
@ -74,7 +77,8 @@ ReturnValue_t HostFilesystem::removeFile(const char *path_, FileSystemArgsIF *ar
return returnvalue::FAILED;
}
path path(path_);
if (not exists(path)) {
std::error_code e;
if (not exists(path, e)) {
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
}
if (remove(path, errorCode)) {
@ -89,7 +93,8 @@ ReturnValue_t HostFilesystem::createDirectory(FilesystemParams params, bool crea
}
path dirPath(params.path);
if (exists(dirPath)) {
std::error_code e;
if (exists(dirPath, e)) {
return HasFileSystemIF::DIRECTORY_ALREADY_EXISTS;
}
@ -110,7 +115,8 @@ ReturnValue_t HostFilesystem::removeDirectory(FilesystemParams params, bool dele
return returnvalue::FAILED;
}
path dirPath(params.path);
if (not exists(dirPath)) {
std::error_code e;
if (not exists(dirPath, e)) {
return HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST;
}
if (is_regular_file(dirPath)) {
@ -149,12 +155,14 @@ ReturnValue_t HostFilesystem::rename(const char *oldPath_, const char *newPath_,
bool HostFilesystem::fileExists(FilesystemParams params) {
path path(params.path);
return filesystem::exists(path);
std::error_code e;
return filesystem::exists(path, e);
}
ReturnValue_t HostFilesystem::truncateFile(FilesystemParams params) {
path path(params.path);
if (not filesystem::exists(path)) {
std::error_code e;
if (not filesystem::exists(path, e)) {
return FILE_DOES_NOT_EXIST;
}
ofstream of(path);

View File

@ -17,7 +17,7 @@ ReturnValue_t CommandExecutor::load(std::string command, bool blocking, bool pri
return COMMAND_PENDING;
}
currentCmd = command;
currentCmd = std::move(command);
this->blocking = blocking;
this->printOutput = printOutput;
if (state == States::IDLE) {

View File

@ -112,8 +112,9 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s
if (i2cCookie->errorCounter < 3) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "I2cComIF::sendMessage: Failed to send data to I2C "
"device with error code "
<< errno << ". Error description: " << strerror(errno) << std::endl;
"device from "
<< deviceFile << " with error code " << errno
<< ". Error description: " << strerror(errno) << std::endl;
#endif
}
return returnvalue::FAILED;

View File

@ -88,11 +88,11 @@ int SerialComIF::configureUartPort(SerialCookie* uartCookie) {
return fd;
}
uart::setParity(options, uartCookie->getParity());
serial::setParity(options, uartCookie->getParity());
setStopBitOptions(&options, uartCookie);
setDatasizeOptions(&options, uartCookie);
setFixedOptions(&options);
uart::setMode(options, uartCookie->getUartMode());
serial::setMode(options, uartCookie->getUartMode());
if (uartCookie->getInputShouldBeFlushed()) {
tcflush(fd, TCIFLUSH);
}
@ -101,7 +101,7 @@ int SerialComIF::configureUartPort(SerialCookie* uartCookie) {
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 0;
uart::setBaudrate(options, uartCookie->getBaudrate());
serial::setBaudrate(options, uartCookie->getBaudrate());
/* Save option settings */
if (tcsetattr(fd, TCSANOW, &options) != 0) {

View File

@ -3,7 +3,7 @@
#include "fsfw/serviceinterface.h"
void uart::setMode(struct termios& options, UartModes mode) {
void serial::setMode(struct termios& options, UartModes mode) {
if (mode == UartModes::NON_CANONICAL) {
/* Disable canonical mode */
options.c_lflag &= ~ICANON;
@ -12,7 +12,7 @@ void uart::setMode(struct termios& options, UartModes mode) {
}
}
void uart::setBaudrate(struct termios& options, UartBaudRate baud) {
void serial::setBaudrate(struct termios& options, UartBaudRate baud) {
switch (baud) {
case UartBaudRate::RATE_50:
cfsetspeed(&options, B50);
@ -114,7 +114,7 @@ void uart::setBaudrate(struct termios& options, UartBaudRate baud) {
}
}
void uart::setBitsPerWord(struct termios& options, BitsPerWord bits) {
void serial::setBitsPerWord(struct termios& options, BitsPerWord bits) {
options.c_cflag &= ~CSIZE; // Clear all the size bits
if (bits == BitsPerWord::BITS_5) {
options.c_cflag |= CS5;
@ -127,11 +127,11 @@ void uart::setBitsPerWord(struct termios& options, BitsPerWord bits) {
}
}
void uart::enableRead(struct termios& options) { options.c_cflag |= CREAD; }
void serial::enableRead(struct termios& options) { options.c_cflag |= CREAD; }
void uart::ignoreCtrlLines(struct termios& options) { options.c_cflag |= CLOCAL; }
void serial::ignoreCtrlLines(struct termios& options) { options.c_cflag |= CLOCAL; }
void uart::setParity(struct termios& options, Parity parity) {
void serial::setParity(struct termios& options, Parity parity) {
/* Clear parity bit */
options.c_cflag &= ~PARENB;
switch (parity) {
@ -148,11 +148,11 @@ void uart::setParity(struct termios& options, Parity parity) {
}
}
int uart::readCountersAndErrors(int serialPort, serial_icounter_struct& icounter) {
int serial::readCountersAndErrors(int serialPort, serial_icounter_struct& icounter) {
return ioctl(serialPort, TIOCGICOUNT, &icounter);
}
void uart::setStopbits(struct termios& options, StopBits bits) {
void serial::setStopbits(struct termios& options, StopBits bits) {
if (bits == StopBits::TWO_STOP_BITS) {
// Use two stop bits
options.c_cflag |= CSTOPB;
@ -161,3 +161,7 @@ void uart::setStopbits(struct termios& options, StopBits bits) {
options.c_cflag &= ~CSTOPB;
}
}
void serial::flushRxBuf(int fd) { tcflush(fd, TCIFLUSH); }
void serial::flushTxRxBuf(int fd) { tcflush(fd, TCIOFLUSH); }

View File

@ -45,7 +45,7 @@ enum class UartBaudRate {
RATE_4000000
};
namespace uart {
namespace serial {
void setMode(struct termios& options, UartModes mode);
/**
@ -64,8 +64,11 @@ void setParity(struct termios& options, Parity parity);
void ignoreCtrlLines(struct termios& options);
void flushRxBuf(int fd);
void flushTxRxBuf(int fd);
int readCountersAndErrors(int serialPort, serial_icounter_struct& icounter);
} // namespace uart
} // namespace serial
#endif /* FSFW_HAL_LINUX_UART_HELPER_H_ */

View File

@ -13,6 +13,7 @@ add_subdirectory(util)
add_subdirectory(container)
add_subdirectory(osal)
add_subdirectory(pus)
add_subdirectory(subsystem)
add_subdirectory(serialize)
add_subdirectory(datapoollocal)
add_subdirectory(storagemanager)

View File

@ -0,0 +1 @@
target_sources(${FSFW_TEST_TGT} PRIVATE testModeDef.cpp)

View File

@ -0,0 +1,49 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/subsystem/modes/ModeDefinitions.h"
TEST_CASE("Mode Definitions", "[mode]") {
ModeListEntry entry;
SECTION("Basic") {
entry.setMode(HasModesIF::MODE_OFF);
entry.setSubmode(2);
CHECK(entry.getMode() == HasModesIF::MODE_OFF);
CHECK(entry.getSubmode() == 2);
uint8_t mask;
CHECK(entry.submodesAllowed(&mask) == false);
}
SECTION("Allowed submode mask") {
entry.allowAllSubmodes();
uint8_t mask;
CHECK(entry.submodesAllowed(&mask) == true);
CHECK(mask == 0xff);
}
SECTION("Serialization") {
std::array<uint8_t, 32> buf{};
entry.setObject(0x1f2f3f4f);
entry.setMode(HasModesIF::MODE_ON);
entry.setSubmode(2);
entry.enableInheritSubmode();
entry.enableSubmodeAllowed(0x1f);
uint8_t* serPtr = buf.data();
size_t serLen = 0;
REQUIRE(entry.serialize(&serPtr, &serLen, buf.size(), SerializeIF::Endianness::NETWORK) ==
returnvalue::OK);
CHECK(buf[0] == 0x1f);
CHECK(buf[1] == 0x2f);
CHECK(buf[2] == 0x3f);
CHECK(buf[3] == 0x4f);
CHECK(buf[4] == 0);
CHECK(buf[5] == 0);
CHECK(buf[6] == 0);
CHECK(buf[7] == HasModesIF::MODE_ON);
CHECK(buf[8] == 2);
CHECK(buf[9] == (mode::SpecialSubmodeFlags::ALLOWED_MASK | mode::SpecialSubmodeFlags::INHERIT));
CHECK(buf[10] == 0x1f);
}
}

View File

@ -1,15 +1,18 @@
#include <fsfw/timemanager/Countdown.h>
#include <catch2/catch_test_macros.hpp>
#include <chrono>
#include <thread>
#include "CatchDefinitions.h"
static constexpr bool TEST_LONGER_CD = false;
TEST_CASE("Countdown Tests", "[TestCountdown]") {
INFO("Countdown Tests");
Countdown count(20);
REQUIRE(count.timeout == 20);
REQUIRE(count.getTimeoutMs() == 20);
REQUIRE(count.setTimeout(100) == static_cast<uint16_t>(returnvalue::OK));
REQUIRE(count.timeout == 100);
REQUIRE(count.getTimeoutMs() == 100);
REQUIRE(count.setTimeout(150) == static_cast<uint16_t>(returnvalue::OK));
REQUIRE(count.isBusy());
REQUIRE(not count.hasTimedOut());
@ -25,4 +28,19 @@ TEST_CASE("Countdown Tests", "[TestCountdown]") {
count.resetTimer();
REQUIRE(not count.hasTimedOut());
REQUIRE(count.isBusy());
count.setTimeout(100);
REQUIRE(not count.hasTimedOut());
std::this_thread::sleep_for(std::chrono::milliseconds(50));
REQUIRE(not count.hasTimedOut());
std::this_thread::sleep_for(std::chrono::milliseconds(50));
REQUIRE(count.hasTimedOut());
// Takes longer, disabled by default
if (TEST_LONGER_CD) {
count.setTimeout(2500);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
REQUIRE(not count.hasTimedOut());
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
REQUIRE(count.hasTimedOut());
}
}