Compare commits
85 Commits
511d07c0c7
...
b814e7198f
Author | SHA1 | Date | |
---|---|---|---|
b814e7198f | |||
6328b70d7b | |||
a937b457f9 | |||
4415dc24e1 | |||
e704295cce | |||
d16b3c7e67 | |||
3b86545725 | |||
cf6150cc18 | |||
bfb5c2ff03 | |||
bf02061d47 | |||
2c4e110254 | |||
7ed75ea87b | |||
db4587bb59 | |||
33ac395072 | |||
f8a7c1d4ed | |||
341437df13 | |||
227524a21d | |||
43fd0b2f59 | |||
d0607824ad | |||
cf27954a86 | |||
f84e3284ab | |||
5250423d1d | |||
522bd41d6e | |||
c61c85280b | |||
afbe5e1f65 | |||
4c88ab80c8 | |||
5ba69b169f | |||
40405fe6c7 | |||
aac32e763c | |||
bf980d74c0 | |||
b6b9d1d790 | |||
0973ba6bf2 | |||
1cfebb5d47 | |||
0b0a0299bc | |||
8382d61b92 | |||
7208343b6d | |||
9a8d775eb1 | |||
4d6f6e6b23 | |||
55f6825a03 | |||
c162acb7df | |||
87462afe6d | |||
a8de395ea0 | |||
f0bddfcb21 | |||
23d9b44b3e | |||
26e4445189 | |||
9ee3cdf729 | |||
1b7493f945 | |||
7f6ba5f40b | |||
070b48ada2 | |||
d9a139e1ef | |||
c80a3752d9 | |||
af58c414fc | |||
4c48668125 | |||
2745b2080d | |||
e9d9f44605 | |||
2c5af91db1 | |||
5cd7b98ba7 | |||
a39f1271ec | |||
bbf0d7a0d2 | |||
04ee3c7362 | |||
95dab69b35 | |||
33de15205b | |||
4d353a1ad2 | |||
6006c97e48 | |||
6e17e45506 | |||
64537d442a | |||
78cf00315d | |||
245886c555 | |||
f84097543e | |||
dc7afc5415 | |||
9bf3ff95b7 | |||
61562b18ab | |||
d76d97a36b | |||
76b377c4c0 | |||
3562bf11b9 | |||
fffb2b61e5 | |||
94e5f62331 | |||
0a9c563bbc | |||
5b92247fbd | |||
d9da55fdab | |||
066f7a6f9b | |||
c1f42618db | |||
61df451dd8 | |||
29ea89044e | |||
e487f5be87 |
122
CHANGELOG.md
122
CHANGELOG.md
@ -8,16 +8,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
# [unreleased]
|
# [unreleased]
|
||||||
|
|
||||||
# [v6.0.0]
|
# [v6.0.0] 2023-02-10
|
||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
|
|
||||||
- Bugfix in `Service11TelecommandScheduling` which allowed commands
|
- Mode Service: Add allowed subservice
|
||||||
time tagged in the past to be inserted.
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/739
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/738
|
|
||||||
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
|
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
|
||||||
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
|
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
|
||||||
subservice not working properly.
|
subservice not working properly.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/736
|
||||||
- Memory leak fixes for the TCP/IP TMTC bridge.
|
- Memory leak fixes for the TCP/IP TMTC bridge.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737
|
||||||
- `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval
|
- `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,
|
- HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously,
|
||||||
only the X scaling factor was used.
|
only the X scaling factor was used.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724
|
||||||
- Bugfix for RM3100 MGM sensors. Z value was previously calculated
|
- HAL MGM3100 Handler: Z value was previously calculated with bytes of the X value.
|
||||||
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
|
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
|
||||||
to false correctly because the `read` and `write` calls were missing.
|
to false correctly because the `read` and `write` calls were missing.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/728
|
||||||
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
|
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
|
||||||
of the correct unsegmented flags (0b11) as specified in the standard.
|
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.
|
- 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
|
||||||
@ -45,6 +49,36 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- `TcpTmTcServer.cpp`: The server was actually not able to handle
|
- `TcpTmTcServer.cpp`: The server was actually not able to handle
|
||||||
CCSDS packets which were clumped together. This has been fixed now.
|
CCSDS packets which were clumped together. This has been fixed now.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
|
||||||
|
- `CServiceHealthCommanding`: Add announce all health info implementation
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/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
|
## 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
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
|
||||||
- Add new `UnsignedByteField` class
|
- Add new `UnsignedByteField` class
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
|
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
|
## Changes
|
||||||
|
|
||||||
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
|
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
|
||||||
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
|
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
|
||||||
`HealthServiceCfg` now
|
`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
|
- `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
|
||||||
@ -103,18 +156,41 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
|
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
|
||||||
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
|
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
|
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`:
|
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
|
||||||
- Make functions `const` where it makes sense
|
- Make functions `const` where it makes sense
|
||||||
- Add `const char* getName const` abstract function
|
- Add `const char* getName const` abstract function
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
|
||||||
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
|
- Generic TMTC Bridge Update
|
||||||
interface itself so it can be re-used more easily. Also add new
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734
|
||||||
abstract function `bool hasDataAtId(store_address_t storeId) const`.
|
- comment tweak to event parser can read everything
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
|
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
|
## CFDP
|
||||||
|
|
||||||
@ -134,17 +210,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
|
||||||
|
|
||||||
## HAL
|
# [v5.0.0] 2022-07-25
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
|
|||||||
# Version file handling #
|
# 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_SUBVERSION_IF_GIT_FAILS 0)
|
||||||
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||||
|
|
||||||
|
110
scripts/check_release.py
Executable file
110
scripts/check_release.py
Executable 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()
|
@ -70,8 +70,7 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
|
|||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation(uint8_t nonDiagInvlFactor) {
|
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation() {
|
||||||
setNonDiagnosticIntervalFactor(nonDiagInvlFactor);
|
|
||||||
return initializeHousekeepingPoolEntriesOnce();
|
return initializeHousekeepingPoolEntriesOnce();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,10 +660,6 @@ ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(HousekeepingPacke
|
|||||||
return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE);
|
return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalDataPoolManager::setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor) {
|
|
||||||
this->nonDiagnosticIntervalFactor = nonDiagInvlFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
||||||
sid_t sid = receiver.dataId.sid;
|
sid_t sid = receiver.dataId.sid;
|
||||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, 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
|
if ((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or
|
||||||
(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) {
|
(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) {
|
||||||
return REPORTING_STATUS_UNCHANGED;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable);
|
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable);
|
||||||
|
@ -102,7 +102,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
|||||||
* @param nonDiagInvlFactor
|
* @param nonDiagInvlFactor
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ReturnValue_t initializeAfterTaskCreation(uint8_t nonDiagInvlFactor = 5);
|
ReturnValue_t initializeAfterTaskCreation();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This should be called in the periodic handler of the owner.
|
* @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,
|
MessageQueueId_t targetQueueId,
|
||||||
bool generateSnapshot) override;
|
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.
|
* @brief The manager is also able to handle housekeeping messages.
|
||||||
* @details
|
* @details
|
||||||
|
@ -250,9 +250,8 @@ void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) {
|
|||||||
bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; }
|
bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; }
|
||||||
|
|
||||||
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
|
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
|
||||||
dur_millis_t minimumPeriodicInterval,
|
dur_millis_t minimumPeriodicInterval) {
|
||||||
uint8_t nonDiagIntervalFactor) {
|
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval);
|
||||||
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalPoolDataSetBase::setChanged(bool changed) { this->changed = changed; }
|
void LocalPoolDataSetBase::setChanged(bool changed) { this->changed = changed; }
|
||||||
|
@ -191,8 +191,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
|||||||
*/
|
*/
|
||||||
bool reportingEnabled = false;
|
bool reportingEnabled = false;
|
||||||
|
|
||||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval);
|
||||||
uint8_t nonDiagIntervalFactor = 5);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the valid state of a dataset is always relevant to the whole
|
* If the valid state of a dataset is always relevant to the whole
|
||||||
|
@ -12,10 +12,8 @@ class LocalPoolDataSetAttorney {
|
|||||||
static bool isDiagnostics(LocalPoolDataSetBase& set) { return set.isDiagnostics(); }
|
static bool isDiagnostics(LocalPoolDataSetBase& set) { return set.isDiagnostics(); }
|
||||||
|
|
||||||
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
|
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
|
||||||
uint32_t minimumPeriodicIntervalMs,
|
uint32_t minimumPeriodicIntervalMs) {
|
||||||
uint8_t nonDiagIntervalFactor = 5) {
|
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs);
|
||||||
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs,
|
|
||||||
nonDiagIntervalFactor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) {
|
static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) {
|
||||||
|
@ -49,6 +49,7 @@ class DeviceCommunicationIF {
|
|||||||
// is this needed if there is no open/close call?
|
// is this needed if there is no open/close call?
|
||||||
static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05);
|
static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05);
|
||||||
static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06);
|
static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06);
|
||||||
|
static constexpr ReturnValue_t BUSY = MAKE_RETURN_CODE(0x07);
|
||||||
|
|
||||||
virtual ~DeviceCommunicationIF() {}
|
virtual ~DeviceCommunicationIF() {}
|
||||||
|
|
||||||
|
@ -565,6 +565,9 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
|||||||
*/
|
*/
|
||||||
if (newMode == MODE_ON and continueToNormal) {
|
if (newMode == MODE_ON and continueToNormal) {
|
||||||
continueToNormal = false;
|
continueToNormal = false;
|
||||||
|
// TODO: Check whether the following two lines are okay to do so.
|
||||||
|
transitionSourceMode = MODE_ON;
|
||||||
|
transitionSourceSubMode = newSubmode;
|
||||||
mode = _MODE_TO_NORMAL;
|
mode = _MODE_TO_NORMAL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,12 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
|
|||||||
{fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, sizeof(EventIdRangeMatcher)},
|
{fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, sizeof(EventIdRangeMatcher)},
|
||||||
{fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, sizeof(ReporterRangeMatcher)}};
|
{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) {
|
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(
|
eventReportQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
eventQueueDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventManager::~EventManager() {
|
EventManager::~EventManager() {
|
||||||
|
@ -21,9 +21,9 @@ extern const char* translateEvents(Event event);
|
|||||||
|
|
||||||
class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject {
|
class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject {
|
||||||
public:
|
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();
|
virtual ~EventManager();
|
||||||
|
|
||||||
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
||||||
|
@ -10,7 +10,7 @@ enum : uint8_t {
|
|||||||
CDH = 28,
|
CDH = 28,
|
||||||
TCS_1 = 59,
|
TCS_1 = 59,
|
||||||
PCDU_1 = 42,
|
PCDU_1 = 42,
|
||||||
PCDU_2 = 43,
|
POWER_SWITCH_IF = 43,
|
||||||
HEATER = 50,
|
HEATER = 50,
|
||||||
T_SENSORS = 52,
|
T_SENSORS = 52,
|
||||||
FDIR = 70,
|
FDIR = 70,
|
||||||
|
@ -68,7 +68,7 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId,
|
|||||||
parameterWrapper->set(faultCount);
|
parameterWrapper->set(faultCount);
|
||||||
break;
|
break;
|
||||||
case ParameterIds::TIMEOUT:
|
case ParameterIds::TIMEOUT:
|
||||||
parameterWrapper->set(timer.timeout);
|
parameterWrapper->set(timer.getTimeoutMs());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return INVALID_IDENTIFIER_ID;
|
return INVALID_IDENTIFIER_ID;
|
||||||
|
@ -8,10 +8,8 @@ PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(LocalPoolDataSetBase* own
|
|||||||
: owner(owner) {}
|
: owner(owner) {}
|
||||||
|
|
||||||
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
|
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
|
||||||
dur_millis_t minimumPeriodicInterval,
|
dur_millis_t minimumPeriodicInterval) {
|
||||||
uint8_t nonDiagIntervalFactor) {
|
|
||||||
this->minimumPeriodicInterval = minimumPeriodicInterval;
|
this->minimumPeriodicInterval = minimumPeriodicInterval;
|
||||||
this->nonDiagIntervalFactor = nonDiagIntervalFactor;
|
|
||||||
collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval);
|
collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval);
|
||||||
/* This will cause a checkOpNecessary call to be true immediately. I think it's okay
|
/* 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. */
|
if a HK packet is generated immediately instead of waiting one generation cycle. */
|
||||||
@ -36,42 +34,17 @@ uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks(
|
|||||||
if (owner == nullptr) {
|
if (owner == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
bool isDiagnostics = owner->isDiagnostics();
|
|
||||||
|
|
||||||
/* Avoid division by zero */
|
/* Avoid division by zero */
|
||||||
if (minimumPeriodicInterval == 0) {
|
if (minimumPeriodicInterval == 0) {
|
||||||
if (isDiagnostics) {
|
|
||||||
/* Perform operation each cycle */
|
/* Perform operation each cycle */
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
|
||||||
return nonDiagIntervalFactor;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
dur_millis_t intervalInMs = collectionIntervalSeconds * 1000;
|
dur_millis_t intervalInMs = collectionIntervalSeconds * 1000;
|
||||||
uint32_t divisor = minimumPeriodicInterval;
|
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);
|
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;
|
return ticks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,7 @@ class PeriodicHousekeepingHelper {
|
|||||||
public:
|
public:
|
||||||
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
|
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
|
||||||
|
|
||||||
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval);
|
||||||
uint8_t nonDiagIntervalFactor);
|
|
||||||
|
|
||||||
void changeCollectionInterval(float newInterval);
|
void changeCollectionInterval(float newInterval);
|
||||||
float getCollectionIntervalInSeconds() const;
|
float getCollectionIntervalInSeconds() const;
|
||||||
@ -20,7 +19,6 @@ class PeriodicHousekeepingHelper {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
LocalPoolDataSetBase* owner = nullptr;
|
LocalPoolDataSetBase* owner = nullptr;
|
||||||
uint8_t nonDiagIntervalFactor = 0;
|
|
||||||
|
|
||||||
uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds);
|
uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds);
|
||||||
float intervalTicksToSeconds(uint32_t collectionInterval) const;
|
float intervalTicksToSeconds(uint32_t collectionInterval) const;
|
||||||
|
@ -7,14 +7,17 @@
|
|||||||
class MutexGuard {
|
class MutexGuard {
|
||||||
public:
|
public:
|
||||||
MutexGuard(MutexIF* mutex, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::BLOCKING,
|
MutexGuard(MutexIF* mutex, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::BLOCKING,
|
||||||
uint32_t timeoutMs = 0)
|
uint32_t timeoutMs = 0, const char* context = nullptr)
|
||||||
: internalMutex(mutex) {
|
: internalMutex(mutex) {
|
||||||
|
if (context == nullptr) {
|
||||||
|
context = "unknown";
|
||||||
|
}
|
||||||
if (mutex == nullptr) {
|
if (mutex == nullptr) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 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
|
#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_CPP_OSTREAM_ENABLED == 1 */
|
||||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
return;
|
return;
|
||||||
@ -23,11 +26,11 @@ class MutexGuard {
|
|||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
if (result == MutexIF::MUTEX_TIMEOUT) {
|
if (result == MutexIF::MUTEX_TIMEOUT) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "MutexGuard: Lock of mutex failed with timeout of " << timeoutMs
|
sif::error << "MutexGuard::" << context << ": Lock of mutex failed with timeout of "
|
||||||
<< " milliseconds!" << std::endl;
|
<< timeoutMs << " milliseconds!" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printError("MutexGuard: Lock of mutex failed with timeout of %lu milliseconds\n",
|
sif::printError("MutexGuard::%s: Lock of mutex failed with timeout of %lu milliseconds\n",
|
||||||
timeoutMs);
|
context, timeoutMs);
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
|
||||||
} else if (result != returnvalue::OK) {
|
} else if (result != returnvalue::OK) {
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId,
|
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
object_id_t tcStoreId)
|
uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId)
|
||||||
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) {
|
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
// Connection is always up, TM is requested by connecting to server and receiving packets
|
// Connection is always up, TM is requested by connecting to server and receiving packets
|
||||||
registerCommConnect();
|
registerCommConnect();
|
||||||
|
@ -38,7 +38,7 @@ class TcpTmTcBridge : public TmTcBridge {
|
|||||||
* @param tmStoreId TM store object ID. It is recommended to the default object ID
|
* @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
|
* @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 tmStoreId = objects::TM_STORE,
|
||||||
object_id_t tcStoreId = objects::TC_STORE);
|
object_id_t tcStoreId = objects::TC_STORE);
|
||||||
virtual ~TcpTmTcBridge();
|
virtual ~TcpTmTcBridge();
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
const std::string &udpServerPort_, object_id_t tmStoreId,
|
uint32_t msgQueueDepth, const std::string &udpServerPort_,
|
||||||
object_id_t tcStoreId)
|
object_id_t tmStoreId, object_id_t tcStoreId)
|
||||||
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) {
|
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
|
||||||
if (udpServerPort_.empty()) {
|
if (udpServerPort_.empty()) {
|
||||||
udpServerPort = DEFAULT_SERVER_PORT;
|
udpServerPort = DEFAULT_SERVER_PORT;
|
||||||
} else {
|
} else {
|
||||||
|
@ -29,7 +29,7 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
|
|||||||
/* The ports chosen here should not be used by any other process. */
|
/* The ports chosen here should not be used by any other process. */
|
||||||
static const std::string DEFAULT_SERVER_PORT;
|
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,
|
const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
|
||||||
object_id_t tcStoreId = objects::TC_STORE);
|
object_id_t tcStoreId = objects::TC_STORE);
|
||||||
~UdpTmTcBridge() override;
|
~UdpTmTcBridge() override;
|
||||||
|
@ -47,7 +47,32 @@ ReturnValue_t Clock::setClock(const timeval* time) {
|
|||||||
return returnvalue::OK;
|
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)
|
#if defined(PLATFORM_WIN)
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
||||||
@ -75,6 +100,8 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Clock::getClock_timeval(timeval* time) { return Clock::getClock(time); }
|
||||||
|
|
||||||
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
||||||
if (time == nullptr) {
|
if (time == nullptr) {
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
|
@ -20,16 +20,18 @@ TaskFactory::~TaskFactory() = default;
|
|||||||
|
|
||||||
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
||||||
|
|
||||||
PeriodicTaskIF* TaskFactory::createPeriodicTask(
|
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
|
||||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
TaskStackSize stackSize_,
|
||||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
TaskPeriod periodInSeconds_,
|
||||||
|
TaskDeadlineMissedFunction deadLineMissedFunction_,
|
||||||
|
void* args) {
|
||||||
return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||||
deadLineMissedFunction_);
|
deadLineMissedFunction_);
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
||||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_, void* args) {
|
||||||
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||||
deadLineMissedFunction_);
|
deadLineMissedFunction_);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
|
|||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
ReturnValue_t Clock::getClock(timeval* time) {
|
||||||
timespec timeUnix{};
|
timespec timeUnix{};
|
||||||
int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
|
int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
@ -53,6 +53,8 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
|||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Clock::getClock_timeval(timeval* time) { return Clock::getClock(time); }
|
||||||
|
|
||||||
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
||||||
timeval timeVal{};
|
timeval timeVal{};
|
||||||
ReturnValue_t result = getClock_timeval(&timeVal);
|
ReturnValue_t result = getClock_timeval(&timeVal);
|
||||||
@ -64,6 +66,17 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
|||||||
return returnvalue::OK;
|
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 Clock::getUptime() {
|
||||||
timeval uptime{};
|
timeval uptime{};
|
||||||
auto result = getUptime(&uptime);
|
auto result = getUptime(&uptime);
|
||||||
@ -79,12 +92,17 @@ ReturnValue_t Clock::getUptime(timeval* uptime) {
|
|||||||
// TODO This is not posix compatible and delivers only seconds precision
|
// TODO This is not posix compatible and delivers only seconds precision
|
||||||
// Linux specific file read but more precise.
|
// Linux specific file read but more precise.
|
||||||
double uptimeSeconds;
|
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_sec = uptimeSeconds;
|
||||||
uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6);
|
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.
|
// Wait for new FSFW Clock function delivering seconds uptime.
|
||||||
// uint32_t Clock::getUptimeSeconds() {
|
// uint32_t Clock::getUptimeSeconds() {
|
||||||
|
@ -7,10 +7,15 @@
|
|||||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
|
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
|
||||||
|
|
||||||
FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
||||||
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_)
|
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_,
|
||||||
|
PosixThreadArgs* args)
|
||||||
: FixedTimeslotTaskBase(periodSeconds_, dlmFunc_),
|
: FixedTimeslotTaskBase(periodSeconds_, dlmFunc_),
|
||||||
posixThread(name_, priority_, stackSize_),
|
posixThread(name_, SchedulingPolicy::REGULAR, priority_, stackSize_),
|
||||||
started(false) {}
|
started(false) {
|
||||||
|
if (args != nullptr) {
|
||||||
|
posixThread.setSchedPolicy(args->policy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
||||||
// The argument is re-interpreted as PollingTask.
|
// The argument is re-interpreted as PollingTask.
|
||||||
|
@ -23,7 +23,8 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase {
|
|||||||
* @param deadlineMissedFunc_
|
* @param deadlineMissedFunc_
|
||||||
*/
|
*/
|
||||||
FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
||||||
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_);
|
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_,
|
||||||
|
PosixThreadArgs* args);
|
||||||
~FixedTimeslotTask() override = default;
|
~FixedTimeslotTask() override = default;
|
||||||
|
|
||||||
ReturnValue_t startTask() override;
|
ReturnValue_t startTask() override;
|
||||||
|
@ -4,10 +4,15 @@
|
|||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
|
|
||||||
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
|
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
|
||||||
TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
|
TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_,
|
||||||
|
PosixThreadArgs* args)
|
||||||
: PeriodicTaskBase(period_, dlmFunc_),
|
: PeriodicTaskBase(period_, dlmFunc_),
|
||||||
posixThread(name_, priority_, stackSize_),
|
posixThread(name_, SchedulingPolicy::REGULAR, priority_, stackSize_),
|
||||||
started(false) {}
|
started(false) {
|
||||||
|
if (args != nullptr) {
|
||||||
|
posixThread.setSchedPolicy(args->policy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
||||||
// The argument is re-interpreted as PollingTask.
|
// The argument is re-interpreted as PollingTask.
|
||||||
|
@ -24,7 +24,7 @@ class PeriodicPosixTask : public PeriodicTaskBase {
|
|||||||
* @param deadlineMissedFunc_
|
* @param deadlineMissedFunc_
|
||||||
*/
|
*/
|
||||||
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_,
|
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_,
|
||||||
TaskDeadlineMissedFunction dlmFunc_);
|
TaskDeadlineMissedFunction dlmFunc_, PosixThreadArgs* args);
|
||||||
~PeriodicPosixTask() override = default;
|
~PeriodicPosixTask() override = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,8 +7,9 @@
|
|||||||
#include "fsfw/osal/linux/unixUtility.h"
|
#include "fsfw/osal/linux/unixUtility.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_)
|
PosixThread::PosixThread(const char* name_, SchedulingPolicy schedPolciy, int priority_,
|
||||||
: thread(0), priority(priority_), stackSize(stackSize_) {
|
size_t stackSize_)
|
||||||
|
: thread(0), schedPolicy(schedPolciy), priority(priority_), stackSize(stackSize_) {
|
||||||
name[0] = '\0';
|
name[0] = '\0';
|
||||||
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
|
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
|
#ifndef FSFW_USE_REALTIME_FOR_LINUX
|
||||||
#error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1"
|
#error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1"
|
||||||
#endif
|
#endif
|
||||||
|
if (schedPolicy == SchedulingPolicy::RR) {
|
||||||
|
// RR -> This needs root privileges for the process
|
||||||
#if FSFW_USE_REALTIME_FOR_LINUX == 1
|
#if FSFW_USE_REALTIME_FOR_LINUX == 1
|
||||||
// FIFO -> This needs root privileges for the process
|
status = pthread_attr_setschedpolicy(&attributes, SCHED_RR);
|
||||||
status = pthread_attr_setschedpolicy(&attributes, SCHED_FIFO);
|
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy");
|
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy");
|
||||||
}
|
}
|
||||||
|
|
||||||
sched_param scheduleParams;
|
sched_param scheduleParams;
|
||||||
scheduleParams.__sched_priority = priority;
|
scheduleParams.sched_priority = priority;
|
||||||
status = pthread_attr_setschedparam(&attributes, &scheduleParams);
|
status = pthread_attr_setschedparam(&attributes, &scheduleParams);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedparam");
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
}
|
sif::warning << "PosixThread: Setting priority failed" << std::endl;
|
||||||
#endif
|
#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
|
||||||
|
}
|
||||||
|
|
||||||
// Set Signal Mask for suspend until startTask is called
|
// Set Signal Mask for suspend until startTask is called
|
||||||
sigset_t waitSignal;
|
sigset_t waitSignal;
|
||||||
sigemptyset(&waitSignal);
|
sigemptyset(&waitSignal);
|
||||||
@ -243,3 +254,5 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
|
|||||||
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_destroy");
|
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_destroy");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PosixThread::setSchedPolicy(SchedulingPolicy policy) { this->schedPolicy = policy; }
|
||||||
|
@ -9,10 +9,15 @@
|
|||||||
|
|
||||||
#include "../../returnvalues/returnvalue.h"
|
#include "../../returnvalues/returnvalue.h"
|
||||||
|
|
||||||
|
enum SchedulingPolicy { REGULAR, RR };
|
||||||
|
struct PosixThreadArgs {
|
||||||
|
SchedulingPolicy policy = SchedulingPolicy::REGULAR;
|
||||||
|
};
|
||||||
|
|
||||||
class PosixThread {
|
class PosixThread {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16;
|
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();
|
virtual ~PosixThread();
|
||||||
/**
|
/**
|
||||||
* Set the Thread to sleep state
|
* Set the Thread to sleep state
|
||||||
@ -20,6 +25,9 @@ class PosixThread {
|
|||||||
* @return Returns Failed if sleep fails
|
* @return Returns Failed if sleep fails
|
||||||
*/
|
*/
|
||||||
static ReturnValue_t sleep(uint64_t ns);
|
static ReturnValue_t sleep(uint64_t ns);
|
||||||
|
|
||||||
|
void setSchedPolicy(SchedulingPolicy policy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Function to suspend the task until SIGUSR1 was received
|
* @brief Function to suspend the task until SIGUSR1 was received
|
||||||
*
|
*
|
||||||
@ -72,6 +80,7 @@ class PosixThread {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
char name[PTHREAD_MAX_NAMELEN];
|
char name[PTHREAD_MAX_NAMELEN];
|
||||||
|
SchedulingPolicy schedPolicy;
|
||||||
int priority;
|
int priority;
|
||||||
size_t stackSize = 0;
|
size_t stackSize = 0;
|
||||||
|
|
||||||
|
@ -12,18 +12,20 @@ TaskFactory::~TaskFactory() = default;
|
|||||||
|
|
||||||
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
||||||
|
|
||||||
PeriodicTaskIF* TaskFactory::createPeriodicTask(
|
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
|
||||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
TaskStackSize stackSize_,
|
||||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
TaskPeriod periodInSeconds_,
|
||||||
|
TaskDeadlineMissedFunction deadLineMissedFunction_,
|
||||||
|
void* args) {
|
||||||
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||||
deadLineMissedFunction_);
|
deadLineMissedFunction_, reinterpret_cast<PosixThreadArgs*>(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
||||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_, void* args) {
|
||||||
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||||
deadLineMissedFunction_);
|
deadLineMissedFunction_, reinterpret_cast<PosixThreadArgs*>(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
||||||
|
@ -32,7 +32,7 @@ class Fuse : public SystemObject,
|
|||||||
gp_id_t poolIdPower;
|
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.
|
//! PSS detected that current on a fuse is totally out of bounds.
|
||||||
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
|
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
|
||||||
//! PSS detected a fuse that went off.
|
//! PSS detected a fuse that went off.
|
||||||
|
@ -28,7 +28,9 @@ class PowerSwitchIF {
|
|||||||
static const ReturnValue_t SWITCH_TIMEOUT = MAKE_RETURN_CODE(2);
|
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_ON = MAKE_RETURN_CODE(3);
|
||||||
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
|
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:
|
//!< Someone detected that a switch went off which shouldn't. Severity:
|
||||||
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
||||||
static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
|
static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
|
||||||
@ -50,6 +52,7 @@ class PowerSwitchIF {
|
|||||||
* @return
|
* @return
|
||||||
* - @c SWITCH_ON if the specified switch is on.
|
* - @c SWITCH_ON if the specified switch is on.
|
||||||
* - @c SWITCH_OFF if the specified switch is off.
|
* - @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
|
* - @c returnvalue::FAILED if an error occured
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0;
|
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <fsfw/ipc/QueueFactory.h>
|
#include <fsfw/ipc/QueueFactory.h>
|
||||||
#include <fsfw/power/PowerSwitchIF.h>
|
#include <fsfw/power/PowerSwitchIF.h>
|
||||||
|
#include <fsfw/subsystem/helper.h>
|
||||||
|
|
||||||
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
||||||
power::Switch_t pwrSwitch)
|
power::Switch_t pwrSwitch)
|
||||||
@ -28,6 +29,9 @@ ReturnValue_t PowerSwitcherComponent::performOperation(uint8_t opCode) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (getHealth() == FAULTY) {
|
||||||
|
performFaultyOperation();
|
||||||
|
}
|
||||||
if (switcher.active()) {
|
if (switcher.active()) {
|
||||||
switcher.doStateMachine();
|
switcher.doStateMachine();
|
||||||
auto currState = switcher.getState();
|
auto currState = switcher.getState();
|
||||||
@ -111,9 +115,11 @@ const HasHealthIF* PowerSwitcherComponent::getOptHealthIF() const { return this;
|
|||||||
const HasModesIF& PowerSwitcherComponent::getModeIF() const { return *this; }
|
const HasModesIF& PowerSwitcherComponent::getModeIF() const { return *this; }
|
||||||
|
|
||||||
ReturnValue_t PowerSwitcherComponent::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
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(); }
|
object_id_t PowerSwitcherComponent::getObjectId() const { return SystemObject::getObjectId(); }
|
||||||
|
|
||||||
ModeTreeChildIF& PowerSwitcherComponent::getModeTreeChildIF() { return *this; }
|
ModeTreeChildIF& PowerSwitcherComponent::getModeTreeChildIF() { return *this; }
|
||||||
|
|
||||||
|
void PowerSwitcherComponent::performFaultyOperation() {}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#ifndef _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
|
#pragma once
|
||||||
#define _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
|
|
||||||
|
|
||||||
#include <fsfw/health/HasHealthIF.h>
|
#include <fsfw/health/HasHealthIF.h>
|
||||||
#include <fsfw/health/HealthHelper.h>
|
#include <fsfw/health/HealthHelper.h>
|
||||||
@ -37,9 +36,11 @@ class PowerSwitcherComponent : public SystemObject,
|
|||||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PowerSwitcher switcher;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MessageQueueIF *queue = nullptr;
|
MessageQueueIF *queue = nullptr;
|
||||||
PowerSwitcher switcher;
|
|
||||||
|
|
||||||
Mode_t mode = MODE_OFF;
|
Mode_t mode = MODE_OFF;
|
||||||
Submode_t submode = 0;
|
Submode_t submode = 0;
|
||||||
@ -49,24 +50,23 @@ class PowerSwitcherComponent : public SystemObject,
|
|||||||
|
|
||||||
void setMode(Mode_t newMode, Submode_t newSubmode);
|
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;
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
MessageQueueId_t getCommandQueue() const override;
|
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
|
||||||
void getMode(Mode_t *mode, Submode_t *submode) override;
|
void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
uint32_t *msToReachTheMode) override;
|
uint32_t *msToReachTheMode) override;
|
||||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||||
|
virtual void performFaultyOperation();
|
||||||
void setToExternalControl() override;
|
void setToExternalControl() override;
|
||||||
void announceMode(bool recursive) override;
|
void announceMode(bool recursive) override;
|
||||||
|
|
||||||
ReturnValue_t setHealth(HealthState health) override;
|
ReturnValue_t setHealth(HealthState health) override;
|
||||||
HasHealthIF::HealthState getHealth() override;
|
HasHealthIF::HealthState getHealth() override;
|
||||||
|
|
||||||
object_id_t getObjectId() const override;
|
[[nodiscard]] object_id_t getObjectId() const override;
|
||||||
const HasHealthIF *getOptHealthIF() const override;
|
[[nodiscard]] const HasHealthIF *getOptHealthIF() const override;
|
||||||
const HasModesIF &getModeIF() const override;
|
[[nodiscard]] const HasModesIF &getModeIF() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ */
|
|
||||||
|
@ -10,9 +10,23 @@
|
|||||||
CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args)
|
CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args)
|
||||||
: CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service,
|
: CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service,
|
||||||
args.numParallelCommands, args.commandTimeoutSeconds),
|
args.numParallelCommands, args.commandTimeoutSeconds),
|
||||||
healthTable(args.table),
|
healthTableId(args.table),
|
||||||
maxNumHealthInfoPerCycle(args.maxNumHealthInfoPerCycle) {}
|
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) {
|
ReturnValue_t CServiceHealthCommanding::isValidSubservice(uint8_t subservice) {
|
||||||
switch (subservice) {
|
switch (subservice) {
|
||||||
case (Subservice::COMMAND_SET_HEALTH):
|
case (Subservice::COMMAND_SET_HEALTH):
|
||||||
@ -68,6 +82,9 @@ ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message,
|
|||||||
ReturnValue_t result = returnvalue::OK;
|
ReturnValue_t result = returnvalue::OK;
|
||||||
switch (subservice) {
|
switch (subservice) {
|
||||||
case (Subservice::COMMAND_SET_HEALTH): {
|
case (Subservice::COMMAND_SET_HEALTH): {
|
||||||
|
if (tcDataLen != sizeof(object_id_t) + sizeof(HasHealthIF::HealthState)) {
|
||||||
|
return CommandingServiceBase::INVALID_TC;
|
||||||
|
}
|
||||||
HealthSetCommand healthCommand;
|
HealthSetCommand healthCommand;
|
||||||
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
@ -88,14 +105,6 @@ ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message,
|
|||||||
return EXECUTION_COMPLETE;
|
return EXECUTION_COMPLETE;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
while (true) {
|
|
||||||
ReturnValue_t result = iterateHealthTable(false);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
// Should never happen, subservice was already checked
|
// Should never happen, subservice was already checked
|
||||||
@ -142,7 +151,7 @@ void CServiceHealthCommanding::doPeriodicOperation() {
|
|||||||
ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) {
|
ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) {
|
||||||
std::pair<object_id_t, HasHealthIF::HealthState> pair;
|
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) {
|
if (result != returnvalue::OK) {
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include "fsfw/tmtcservices/CommandingServiceBase.h"
|
#include "fsfw/tmtcservices/CommandingServiceBase.h"
|
||||||
|
|
||||||
struct HealthServiceCfg {
|
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)
|
uint16_t maxNumHealthInfoPerCycle)
|
||||||
: objectId(objectId),
|
: objectId(objectId),
|
||||||
apid(apid),
|
apid(apid),
|
||||||
@ -14,7 +14,7 @@ struct HealthServiceCfg {
|
|||||||
maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {}
|
maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {}
|
||||||
object_id_t objectId;
|
object_id_t objectId;
|
||||||
uint16_t apid;
|
uint16_t apid;
|
||||||
HealthTable &table;
|
object_id_t table;
|
||||||
uint16_t maxNumHealthInfoPerCycle;
|
uint16_t maxNumHealthInfoPerCycle;
|
||||||
uint8_t service = 201;
|
uint8_t service = 201;
|
||||||
uint8_t numParallelCommands = 4;
|
uint8_t numParallelCommands = 4;
|
||||||
@ -40,6 +40,8 @@ class CServiceHealthCommanding : public CommandingServiceBase {
|
|||||||
CServiceHealthCommanding(HealthServiceCfg args);
|
CServiceHealthCommanding(HealthServiceCfg args);
|
||||||
~CServiceHealthCommanding() override = default;
|
~CServiceHealthCommanding() override = default;
|
||||||
|
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* CSB abstract function implementations */
|
/* CSB abstract function implementations */
|
||||||
ReturnValue_t isValidSubservice(uint8_t subservice) override;
|
ReturnValue_t isValidSubservice(uint8_t subservice) override;
|
||||||
@ -57,7 +59,8 @@ class CServiceHealthCommanding : public CommandingServiceBase {
|
|||||||
void doPeriodicOperation() override;
|
void doPeriodicOperation() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HealthTable &healthTable;
|
const object_id_t healthTableId;
|
||||||
|
HealthTable *healthTable;
|
||||||
uint16_t maxNumHealthInfoPerCycle = 0;
|
uint16_t maxNumHealthInfoPerCycle = 0;
|
||||||
bool reportAllHealth = false;
|
bool reportAllHealth = false;
|
||||||
ReturnValue_t iterateHealthTable(bool reset);
|
ReturnValue_t iterateHealthTable(bool reset);
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
#include "fsfw/FSFW.h"
|
#include "fsfw/FSFW.h"
|
||||||
|
|
||||||
PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPoolConfig)
|
PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPoolConfig)
|
||||||
: LocalPool(setObjectId, localPoolConfig, true) {
|
: LocalPool(setObjectId, localPoolConfig, true, true) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
PoolManager::~PoolManager() { MutexFactory::instance()->deleteMutex(mutex); }
|
PoolManager::~PoolManager() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||||
|
|
||||||
ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address) {
|
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);
|
ReturnValue_t status = LocalPool::reserveSpace(size, address);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -22,12 +22,12 @@ ReturnValue_t PoolManager::deleteData(store_address_t storeId) {
|
|||||||
<< storeId.poolIndex << ". id is " << storeId.packetIndex << std::endl;
|
<< storeId.poolIndex << ". id is " << storeId.packetIndex << std::endl;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs);
|
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX);
|
||||||
return LocalPool::deleteData(storeId);
|
return LocalPool::deleteData(storeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PoolManager::deleteData(uint8_t* buffer, size_t size, store_address_t* 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);
|
ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ class PoolManager : public LocalPool {
|
|||||||
protected:
|
protected:
|
||||||
//! Default mutex timeout value to prevent permanent blocking.
|
//! Default mutex timeout value to prevent permanent blocking.
|
||||||
uint32_t mutexTimeoutMs = 20;
|
uint32_t mutexTimeoutMs = 20;
|
||||||
|
static constexpr char LOCK_CTX[] = "PoolManager";
|
||||||
|
|
||||||
ReturnValue_t reserveSpace(size_t size, store_address_t* address) override;
|
ReturnValue_t reserveSpace(size_t size, store_address_t* address) override;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(c
|
|||||||
|
|
||||||
ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry> tableIter,
|
ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry> tableIter,
|
||||||
Submode_t targetSubmode) {
|
Submode_t targetSubmode) {
|
||||||
|
using namespace mode;
|
||||||
std::map<object_id_t, ChildInfo>::iterator childIter;
|
std::map<object_id_t, ChildInfo>::iterator childIter;
|
||||||
|
|
||||||
for (; tableIter.value != NULL; ++tableIter) {
|
for (; tableIter.value != NULL; ++tableIter) {
|
||||||
@ -34,15 +35,23 @@ ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry
|
|||||||
return returnvalue::FAILED;
|
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()) {
|
if (tableIter.value->inheritSubmode()) {
|
||||||
submodeToCheckAgainst = targetSubmode;
|
submodeToCheckAgainst = targetSubmode;
|
||||||
}
|
}
|
||||||
|
if (submodesAllowedMask) {
|
||||||
|
if ((childIter->second.submode | mask) != mask) {
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (childIter->second.submode != submodeToCheckAgainst) {
|
if (childIter->second.submode != submodeToCheckAgainst) {
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,111 +1,126 @@
|
|||||||
#ifndef FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
#ifndef FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
||||||
#define FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
#define FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
||||||
|
|
||||||
#include "../../modes/HasModesIF.h"
|
#include "fsfw/modes/HasModesIF.h"
|
||||||
#include "../../objectmanager/SystemObjectIF.h"
|
#include "fsfw/objectmanager/SystemObjectIF.h"
|
||||||
#include "../../serialize/SerialLinkedListAdapter.h"
|
#include "fsfw/serialize/SerialLinkedListAdapter.h"
|
||||||
#include "../../serialize/SerializeIF.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:
|
public:
|
||||||
ModeListEntry() : LinkedElement<ModeListEntry>(this) {}
|
static constexpr uint8_t ALL_SUBMODES_ALLOWED_MASK = 0xff;
|
||||||
|
|
||||||
uint32_t value1 = 0;
|
ModeListEntry() : SerialLinkedListAdapter(), LinkedElement<ModeListEntry>(this) { setLinks(); }
|
||||||
uint32_t value2 = 0;
|
|
||||||
uint8_t value3 = 0;
|
|
||||||
uint8_t value4 = 0;
|
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
SerializeElement<uint32_t> value1 = 0;
|
||||||
Endianness streamEndianness) const {
|
SerializeElement<uint32_t> value2 = 0;
|
||||||
ReturnValue_t result;
|
SerializeElement<uint8_t> value3 = 0;
|
||||||
|
SerializeElement<uint8_t> value4 = 0;
|
||||||
|
SerializeElement<uint8_t> value5 = 0;
|
||||||
|
|
||||||
result = SerializeAdapter::serialize(&value1, buffer, size, maxSize, streamEndianness);
|
ModeListEntry(const ModeListEntry& other)
|
||||||
|
: SerialLinkedListAdapter(), LinkedElement<ModeListEntry>(this) {
|
||||||
if (result != returnvalue::OK) {
|
value1.entry = other.value1.entry;
|
||||||
return result;
|
value2.entry = other.value2.entry;
|
||||||
}
|
value3.entry = other.value3.entry;
|
||||||
result = SerializeAdapter::serialize(&value2, buffer, size, maxSize, streamEndianness);
|
value4.entry = other.value4.entry;
|
||||||
|
value5.entry = other.value5.entry;
|
||||||
if (result != returnvalue::OK) {
|
setLinks();
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::serialize(&value3, buffer, size, maxSize, streamEndianness);
|
|
||||||
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = SerializeAdapter::serialize(&value4, buffer, size, maxSize, streamEndianness);
|
ModeListEntry& operator=(const ModeListEntry& other) {
|
||||||
|
this->value1.entry = other.value1.entry;
|
||||||
return result;
|
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 size_t getSerializedSize() const {
|
void setLinks() {
|
||||||
return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4);
|
setStart(&value1);
|
||||||
}
|
value1.setNext(&value2);
|
||||||
|
value2.setNext(&value3);
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
value3.setNext(&value4);
|
||||||
Endianness streamEndianness) {
|
value4.setNext(&value5);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// for Sequences
|
// 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
|
// 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; }
|
bool inheritSubmode() const {
|
||||||
|
return (value4.entry & mode::SpecialSubmodeFlags::INHERIT) ==
|
||||||
void setInheritSubmode(bool inherit) {
|
mode::SpecialSubmodeFlags::INHERIT;
|
||||||
if (inherit) {
|
|
||||||
value4 = 1;
|
|
||||||
} else {
|
|
||||||
value4 = 0;
|
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,7 +47,8 @@ class TaskFactory {
|
|||||||
*/
|
*/
|
||||||
PeriodicTaskIF* createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
|
PeriodicTaskIF* createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
|
||||||
TaskStackSize stackSize_, TaskPeriod periodInSeconds_,
|
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.
|
* 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_,
|
FixedTimeslotTaskIF* createFixedTimeslotTask(TaskName name_, TaskPriority taskPriority_,
|
||||||
TaskStackSize stackSize_,
|
TaskStackSize stackSize_,
|
||||||
TaskPeriod periodInSeconds_,
|
TaskPeriod periodInSeconds_,
|
||||||
TaskDeadlineMissedFunction deadLineMissedFunction_);
|
TaskDeadlineMissedFunction deadLineMissedFunction_,
|
||||||
|
void* args = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to be called to delete a task
|
* Function to be called to delete a task
|
||||||
|
@ -283,7 +283,7 @@ ReturnValue_t Heater::getParameter(uint8_t domainId, uint8_t uniqueId,
|
|||||||
}
|
}
|
||||||
switch (uniqueId) {
|
switch (uniqueId) {
|
||||||
case 0:
|
case 0:
|
||||||
parameterWrapper->set(heaterOnCountdown.timeout);
|
parameterWrapper->set(heaterOnCountdown.getTimeoutMs());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return INVALID_IDENTIFIER_ID;
|
return INVALID_IDENTIFIER_ID;
|
||||||
|
@ -49,6 +49,13 @@ class Clock {
|
|||||||
* @return -@c returnvalue::OK on success. Otherwise, the OS failure code is returned.
|
* @return -@c returnvalue::OK on success. Otherwise, the OS failure code is returned.
|
||||||
*/
|
*/
|
||||||
static ReturnValue_t setClock(const timeval *time);
|
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.
|
* 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
|
* 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.
|
* @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.
|
* @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
|
* Get the time since boot in a timeval struct
|
||||||
|
@ -1,49 +1,62 @@
|
|||||||
#include "fsfw/timemanager/Countdown.h"
|
#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) {
|
if (startImmediately) {
|
||||||
setTimeout(initialTimeout);
|
setTimeout(initialTimeout);
|
||||||
} else {
|
} 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 Countdown::setTimeout(uint32_t milliseconds) {
|
||||||
ReturnValue_t returnValue = Clock::getUptime(&startTime);
|
timeout.tv_sec = milliseconds / 1000;
|
||||||
timeout = milliseconds;
|
timeout.tv_usec = (milliseconds % 1000) * 1000;
|
||||||
return returnValue;
|
return Clock::getClockMonotonic(&startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Countdown::hasTimedOut() const {
|
bool Countdown::hasTimedOut() const {
|
||||||
if (uint32_t(this->getCurrentTime() - startTime) >= timeout) {
|
// Account for system clock going back in time.
|
||||||
|
if (getCurrentTime() < startTime) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
if (getCurrentTime() - startTime >= timeout) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Countdown::isBusy() const { return !hasTimedOut(); }
|
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; }
|
void Countdown::timeOut() { startTime = this->getCurrentTime() - timeout; }
|
||||||
|
|
||||||
uint32_t Countdown::getRemainingMillis() const {
|
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()) {
|
if (this->hasTimedOut()) {
|
||||||
return 0;
|
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 Countdown::timevalToMs(timeval &tv) { return tv.tv_sec * 1000 + tv.tv_usec / 1000; }
|
||||||
uint32_t currentTime;
|
|
||||||
Clock::getUptime(¤tTime);
|
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(¤tTime);
|
||||||
return currentTime;
|
return currentTime;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Countdown keeps track of a timespan.
|
* 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::resetTimer restarts the timer.
|
||||||
* Countdown::setTimeout sets a new countdown duration and resets.
|
* Countdown::setTimeout sets a new countdown duration and resets.
|
||||||
@ -39,6 +43,8 @@ class Countdown {
|
|||||||
* @return Returnvalue from Clock::getUptime
|
* @return Returnvalue from Clock::getUptime
|
||||||
*/
|
*/
|
||||||
ReturnValue_t setTimeout(uint32_t milliseconds);
|
ReturnValue_t setTimeout(uint32_t milliseconds);
|
||||||
|
ReturnValue_t setTimeoutTv(timeval tv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the countdown duration has passed.
|
* Returns true if the countdown duration has passed.
|
||||||
*
|
*
|
||||||
@ -61,22 +67,31 @@ class Countdown {
|
|||||||
* Returns the remaining milliseconds (0 if timeout)
|
* Returns the remaining milliseconds (0 if timeout)
|
||||||
*/
|
*/
|
||||||
uint32_t getRemainingMillis() const;
|
uint32_t getRemainingMillis() const;
|
||||||
|
|
||||||
|
uint32_t getTimeoutMs() const;
|
||||||
|
|
||||||
|
timeval getTimeout() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes hasTimedOut() return true
|
* Makes hasTimedOut() return true
|
||||||
*/
|
*/
|
||||||
void timeOut();
|
void timeOut();
|
||||||
/**
|
|
||||||
* Internal countdown duration in milliseconds
|
static inline uint32_t timevalToMs(timeval& tv);
|
||||||
*/
|
|
||||||
uint32_t timeout;
|
|
||||||
|
|
||||||
private:
|
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_ */
|
#endif /* FSFW_TIMEMANAGER_COUNTDOWN_H_ */
|
||||||
|
@ -9,10 +9,10 @@
|
|||||||
Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode)
|
Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode)
|
||||||
: displayOnDestruction(displayOnDestruction), displayMode(displayMode) {
|
: displayOnDestruction(displayOnDestruction), displayMode(displayMode) {
|
||||||
// Measures start time on initialization.
|
// 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) {
|
dur_millis_t Stopwatch::stop(bool display) {
|
||||||
stopInternal();
|
stopInternal();
|
||||||
@ -63,6 +63,6 @@ StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; }
|
|||||||
|
|
||||||
void Stopwatch::stopInternal() {
|
void Stopwatch::stopInternal() {
|
||||||
timeval endTime;
|
timeval endTime;
|
||||||
Clock::getClock_timeval(&endTime);
|
Clock::getClockMonotonic(&endTime);
|
||||||
elapsedTime = endTime - startTime;
|
elapsedTime = endTime - startTime;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#define TMTCBRIDGE_WIRETAPPING 0
|
#define TMTCBRIDGE_WIRETAPPING 0
|
||||||
|
|
||||||
TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
|
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),
|
: SystemObject(objectId),
|
||||||
name(name),
|
name(name),
|
||||||
tmStoreId(tmStoreId),
|
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));
|
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||||
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
|
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); }
|
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
|
||||||
|
@ -15,7 +15,6 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
|||||||
public ExecutableObjectIF,
|
public ExecutableObjectIF,
|
||||||
public SystemObject {
|
public SystemObject {
|
||||||
public:
|
public:
|
||||||
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 unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500;
|
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;
|
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
|
||||||
|
|
||||||
TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
|
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;
|
~TmTcBridge() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,7 +15,8 @@ ReturnValue_t HostFilesystem::writeToFile(FileOpParams params, const uint8_t *da
|
|||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
path path(params.path());
|
path path(params.path());
|
||||||
if (not exists(path)) {
|
std::error_code e;
|
||||||
|
if (not exists(path, e)) {
|
||||||
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
|
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
// This is equivalent to "r+" mode, which is what we need here. Only using ::out would truncate
|
// 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;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
path path(params.path());
|
path path(params.path());
|
||||||
if (not exists(path)) {
|
std::error_code e;
|
||||||
|
if (not exists(path, e)) {
|
||||||
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
|
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
ifstream file(path);
|
ifstream file(path);
|
||||||
@ -59,7 +61,8 @@ ReturnValue_t HostFilesystem::createFile(FilesystemParams params, const uint8_t
|
|||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
path path(params.path);
|
path path(params.path);
|
||||||
if (exists(path)) {
|
std::error_code e;
|
||||||
|
if (exists(path, e)) {
|
||||||
return HasFileSystemIF::FILE_ALREADY_EXISTS;
|
return HasFileSystemIF::FILE_ALREADY_EXISTS;
|
||||||
}
|
}
|
||||||
ofstream file(path);
|
ofstream file(path);
|
||||||
@ -74,7 +77,8 @@ ReturnValue_t HostFilesystem::removeFile(const char *path_, FileSystemArgsIF *ar
|
|||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
path path(path_);
|
path path(path_);
|
||||||
if (not exists(path)) {
|
std::error_code e;
|
||||||
|
if (not exists(path, e)) {
|
||||||
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
|
return HasFileSystemIF::FILE_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
if (remove(path, errorCode)) {
|
if (remove(path, errorCode)) {
|
||||||
@ -89,7 +93,8 @@ ReturnValue_t HostFilesystem::createDirectory(FilesystemParams params, bool crea
|
|||||||
}
|
}
|
||||||
path dirPath(params.path);
|
path dirPath(params.path);
|
||||||
|
|
||||||
if (exists(dirPath)) {
|
std::error_code e;
|
||||||
|
if (exists(dirPath, e)) {
|
||||||
return HasFileSystemIF::DIRECTORY_ALREADY_EXISTS;
|
return HasFileSystemIF::DIRECTORY_ALREADY_EXISTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +115,8 @@ ReturnValue_t HostFilesystem::removeDirectory(FilesystemParams params, bool dele
|
|||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
path dirPath(params.path);
|
path dirPath(params.path);
|
||||||
if (not exists(dirPath)) {
|
std::error_code e;
|
||||||
|
if (not exists(dirPath, e)) {
|
||||||
return HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST;
|
return HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
if (is_regular_file(dirPath)) {
|
if (is_regular_file(dirPath)) {
|
||||||
@ -149,12 +155,14 @@ ReturnValue_t HostFilesystem::rename(const char *oldPath_, const char *newPath_,
|
|||||||
|
|
||||||
bool HostFilesystem::fileExists(FilesystemParams params) {
|
bool HostFilesystem::fileExists(FilesystemParams params) {
|
||||||
path path(params.path);
|
path path(params.path);
|
||||||
return filesystem::exists(path);
|
std::error_code e;
|
||||||
|
return filesystem::exists(path, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t HostFilesystem::truncateFile(FilesystemParams params) {
|
ReturnValue_t HostFilesystem::truncateFile(FilesystemParams params) {
|
||||||
path path(params.path);
|
path path(params.path);
|
||||||
if (not filesystem::exists(path)) {
|
std::error_code e;
|
||||||
|
if (not filesystem::exists(path, e)) {
|
||||||
return FILE_DOES_NOT_EXIST;
|
return FILE_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
ofstream of(path);
|
ofstream of(path);
|
||||||
|
@ -17,7 +17,7 @@ ReturnValue_t CommandExecutor::load(std::string command, bool blocking, bool pri
|
|||||||
return COMMAND_PENDING;
|
return COMMAND_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCmd = command;
|
currentCmd = std::move(command);
|
||||||
this->blocking = blocking;
|
this->blocking = blocking;
|
||||||
this->printOutput = printOutput;
|
this->printOutput = printOutput;
|
||||||
if (state == States::IDLE) {
|
if (state == States::IDLE) {
|
||||||
|
@ -112,8 +112,9 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s
|
|||||||
if (i2cCookie->errorCounter < 3) {
|
if (i2cCookie->errorCounter < 3) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "I2cComIF::sendMessage: Failed to send data to I2C "
|
sif::error << "I2cComIF::sendMessage: Failed to send data to I2C "
|
||||||
"device with error code "
|
"device from "
|
||||||
<< errno << ". Error description: " << strerror(errno) << std::endl;
|
<< deviceFile << " with error code " << errno
|
||||||
|
<< ". Error description: " << strerror(errno) << std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
|
@ -88,11 +88,11 @@ int SerialComIF::configureUartPort(SerialCookie* uartCookie) {
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
uart::setParity(options, uartCookie->getParity());
|
serial::setParity(options, uartCookie->getParity());
|
||||||
setStopBitOptions(&options, uartCookie);
|
setStopBitOptions(&options, uartCookie);
|
||||||
setDatasizeOptions(&options, uartCookie);
|
setDatasizeOptions(&options, uartCookie);
|
||||||
setFixedOptions(&options);
|
setFixedOptions(&options);
|
||||||
uart::setMode(options, uartCookie->getUartMode());
|
serial::setMode(options, uartCookie->getUartMode());
|
||||||
if (uartCookie->getInputShouldBeFlushed()) {
|
if (uartCookie->getInputShouldBeFlushed()) {
|
||||||
tcflush(fd, TCIFLUSH);
|
tcflush(fd, TCIFLUSH);
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ int SerialComIF::configureUartPort(SerialCookie* uartCookie) {
|
|||||||
options.c_cc[VTIME] = 0;
|
options.c_cc[VTIME] = 0;
|
||||||
options.c_cc[VMIN] = 0;
|
options.c_cc[VMIN] = 0;
|
||||||
|
|
||||||
uart::setBaudrate(options, uartCookie->getBaudrate());
|
serial::setBaudrate(options, uartCookie->getBaudrate());
|
||||||
|
|
||||||
/* Save option settings */
|
/* Save option settings */
|
||||||
if (tcsetattr(fd, TCSANOW, &options) != 0) {
|
if (tcsetattr(fd, TCSANOW, &options) != 0) {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "fsfw/serviceinterface.h"
|
#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) {
|
if (mode == UartModes::NON_CANONICAL) {
|
||||||
/* Disable canonical mode */
|
/* Disable canonical mode */
|
||||||
options.c_lflag &= ~ICANON;
|
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) {
|
switch (baud) {
|
||||||
case UartBaudRate::RATE_50:
|
case UartBaudRate::RATE_50:
|
||||||
cfsetspeed(&options, B50);
|
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
|
options.c_cflag &= ~CSIZE; // Clear all the size bits
|
||||||
if (bits == BitsPerWord::BITS_5) {
|
if (bits == BitsPerWord::BITS_5) {
|
||||||
options.c_cflag |= CS5;
|
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 */
|
/* Clear parity bit */
|
||||||
options.c_cflag &= ~PARENB;
|
options.c_cflag &= ~PARENB;
|
||||||
switch (parity) {
|
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);
|
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) {
|
if (bits == StopBits::TWO_STOP_BITS) {
|
||||||
// Use two stop bits
|
// Use two stop bits
|
||||||
options.c_cflag |= CSTOPB;
|
options.c_cflag |= CSTOPB;
|
||||||
@ -161,3 +161,7 @@ void uart::setStopbits(struct termios& options, StopBits bits) {
|
|||||||
options.c_cflag &= ~CSTOPB;
|
options.c_cflag &= ~CSTOPB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void serial::flushRxBuf(int fd) { tcflush(fd, TCIFLUSH); }
|
||||||
|
|
||||||
|
void serial::flushTxRxBuf(int fd) { tcflush(fd, TCIOFLUSH); }
|
||||||
|
@ -45,7 +45,7 @@ enum class UartBaudRate {
|
|||||||
RATE_4000000
|
RATE_4000000
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace uart {
|
namespace serial {
|
||||||
|
|
||||||
void setMode(struct termios& options, UartModes mode);
|
void setMode(struct termios& options, UartModes mode);
|
||||||
/**
|
/**
|
||||||
@ -64,8 +64,11 @@ void setParity(struct termios& options, Parity parity);
|
|||||||
|
|
||||||
void ignoreCtrlLines(struct termios& options);
|
void ignoreCtrlLines(struct termios& options);
|
||||||
|
|
||||||
|
void flushRxBuf(int fd);
|
||||||
|
void flushTxRxBuf(int fd);
|
||||||
|
|
||||||
int readCountersAndErrors(int serialPort, serial_icounter_struct& icounter);
|
int readCountersAndErrors(int serialPort, serial_icounter_struct& icounter);
|
||||||
|
|
||||||
} // namespace uart
|
} // namespace serial
|
||||||
|
|
||||||
#endif /* FSFW_HAL_LINUX_UART_HELPER_H_ */
|
#endif /* FSFW_HAL_LINUX_UART_HELPER_H_ */
|
||||||
|
@ -13,6 +13,7 @@ add_subdirectory(util)
|
|||||||
add_subdirectory(container)
|
add_subdirectory(container)
|
||||||
add_subdirectory(osal)
|
add_subdirectory(osal)
|
||||||
add_subdirectory(pus)
|
add_subdirectory(pus)
|
||||||
|
add_subdirectory(subsystem)
|
||||||
add_subdirectory(serialize)
|
add_subdirectory(serialize)
|
||||||
add_subdirectory(datapoollocal)
|
add_subdirectory(datapoollocal)
|
||||||
add_subdirectory(storagemanager)
|
add_subdirectory(storagemanager)
|
||||||
|
1
unittests/subsystem/CMakeLists.txt
Normal file
1
unittests/subsystem/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
target_sources(${FSFW_TEST_TGT} PRIVATE testModeDef.cpp)
|
49
unittests/subsystem/testModeDef.cpp
Normal file
49
unittests/subsystem/testModeDef.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,18 @@
|
|||||||
#include <fsfw/timemanager/Countdown.h>
|
#include <fsfw/timemanager/Countdown.h>
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "CatchDefinitions.h"
|
#include "CatchDefinitions.h"
|
||||||
|
|
||||||
|
static constexpr bool TEST_LONGER_CD = false;
|
||||||
TEST_CASE("Countdown Tests", "[TestCountdown]") {
|
TEST_CASE("Countdown Tests", "[TestCountdown]") {
|
||||||
INFO("Countdown Tests");
|
INFO("Countdown Tests");
|
||||||
Countdown count(20);
|
Countdown count(20);
|
||||||
REQUIRE(count.timeout == 20);
|
REQUIRE(count.getTimeoutMs() == 20);
|
||||||
REQUIRE(count.setTimeout(100) == static_cast<uint16_t>(returnvalue::OK));
|
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.setTimeout(150) == static_cast<uint16_t>(returnvalue::OK));
|
||||||
REQUIRE(count.isBusy());
|
REQUIRE(count.isBusy());
|
||||||
REQUIRE(not count.hasTimedOut());
|
REQUIRE(not count.hasTimedOut());
|
||||||
@ -25,4 +28,19 @@ TEST_CASE("Countdown Tests", "[TestCountdown]") {
|
|||||||
count.resetTimer();
|
count.resetTimer();
|
||||||
REQUIRE(not count.hasTimedOut());
|
REQUIRE(not count.hasTimedOut());
|
||||||
REQUIRE(count.isBusy());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user