Compare commits

..

127 Commits

Author SHA1 Message Date
6fa453940f move semantics 2023-03-13 13:29:16 +01:00
9a8d775eb1 optimization for cmd executor 2023-03-12 20:49:34 +01:00
4d6f6e6b23 event manager queue depth configurable 2023-03-10 14:58:20 +01:00
55f6825a03 Revert "Modes: reusing submode for mode mask, more unittests"
This reverts commit f0bddfcb21.
2023-03-10 14:50:16 +01:00
c162acb7df Merge branch 'develop' of https://egit.irs.uni-stuttgart.de/eive/fsfw into develop 2023-03-10 14:23:51 +01:00
87462afe6d better error printout for i2c write error 2023-03-10 14:23:40 +01:00
a8de395ea0 Merge pull request 'Modes: reusing submode for mode mask, more unittests' (#133) from mohr/submode_mask into develop
Reviewed-on: #133
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-03-10 11:22:11 +01:00
f0bddfcb21 Modes: reusing submode for mode mask, more unittests 2023-03-09 16:43:45 +01:00
23d9b44b3e Merge pull request 'exceptionless host filesystem' (#132) from avoid_exceptions into develop
Reviewed-on: #132
2023-03-08 14:55:18 +01:00
26e4445189 exceptionless host filesystem 2023-03-08 14:47:03 +01:00
9ee3cdf729 Merge pull request 'OFF -> NORMAL: Set transition source modes' (#131) from off_to_normal_transition_sources into develop
Reviewed-on: #131
2023-03-08 01:24:54 +01:00
1b7493f945 OFF -> NORMAL: Set transition source modes 2023-03-08 01:18:11 +01:00
7f6ba5f40b Merge pull request 'Feature: Allowed Submodes Mask for Mode List Entry' (#130) from feature_allow_submodes_mode_list_entry into develop
Reviewed-on: #130
Reviewed-by: Steffen Gaisser <gaisser@irs.uni-stuttgart.de>
2023-03-07 17:20:47 +01:00
070b48ada2 review improvements 2023-03-07 17:15:34 +01:00
d9a139e1ef Merge remote-tracking branch 'origin/develop' into feature_allow_submodes_mode_list_entry 2023-03-07 16:31:28 +01:00
c80a3752d9 afmt 2023-03-07 16:31:08 +01:00
af58c414fc bugfix in submode check logic 2023-03-07 16:29:10 +01:00
4c48668125 add copy and assignment ctor for mode definition 2023-03-07 16:03:28 +01:00
2745b2080d allow submode mask now 2023-03-07 13:55:40 +01:00
e9d9f44605 added length check 2023-03-06 14:01:45 +01:00
2c5af91db1 Merge pull request 'new monotonic clock API' (#128) from feature_monotonic_clock_api into develop
Reviewed-on: #128
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-03-04 11:47:37 +01:00
5cd7b98ba7 more todo docs 2023-03-04 11:38:16 +01:00
a39f1271ec return FAILED for win 2023-03-04 11:32:32 +01:00
bbf0d7a0d2 add basic impl (no windows) for host 2023-03-04 11:31:54 +01:00
04ee3c7362 renaming 2023-03-04 11:04:55 +01:00
95dab69b35 new monotonic clock API 2023-03-04 11:03:22 +01:00
33de15205b Merge pull request 'configurable queue depth' (#127) from feature_configurable_queue_depth_tcpip_servers into develop
Reviewed-on: #127
2023-03-03 16:33:29 +01:00
4d353a1ad2 remove obsolete constant 2023-03-03 16:36:30 +01:00
6006c97e48 configurable queue depth 2023-03-03 15:45:44 +01:00
6e17e45506 Merge pull request 'timeval: Use system clock' (#126) from feature_timeval_use_sysclock into develop
Reviewed-on: #126
2023-03-03 15:25:38 +01:00
64537d442a extneded and fixed countdown unittests 2023-03-03 14:54:52 +01:00
78cf00315d use sys clock for Countdown 2023-03-03 14:30:35 +01:00
245886c555 add lock context for pool manager 2023-03-02 15:33:49 +01:00
f84097543e allow passing context to mutex guard 2023-03-02 15:20:59 +01:00
511d07c0c7 refactored MGM device code 2023-02-26 21:26:24 +01:00
cf735143fe update for SPI/gyro dev handler code 2023-02-26 14:54:35 +01:00
bdfe31dba4 Merge branch 'mueller/pus-15-tm-storage' into develop 2023-02-24 19:03:21 +01:00
216f603d62 Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-02-24 16:56:32 +01:00
174a6aa862 Merge pull request 'use timeval instead of uptime for stopwatch' (#125) from stopwatch-fix into develop
Reviewed-on: #125
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-02-24 16:51:28 +01:00
c2d9370aa1 Merge branch 'develop' into stopwatch-fix 2023-02-24 16:51:08 +01:00
893b434728 allow dest handler to handle folder destinations 2023-02-24 16:49:23 +01:00
6eba84566d use timeval instead of uptime 2023-02-24 16:39:49 +01:00
f0415a97b1 some fixes and improvements 2023-02-24 15:49:05 +01:00
abcf1b29b2 execution complete 2023-02-24 14:50:36 +01:00
d373c45d36 Merge branch 'develop' into mueller/pus-15-tm-storage 2023-02-22 15:45:54 +01:00
bd208038dd printout fixes 2023-02-22 15:45:39 +01:00
206af00c8b Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-02-21 11:14:19 +01:00
2efff4d2c5 missing include 2023-02-21 02:59:13 +01:00
2a0c244468 add pus 15 store ID 2023-02-20 16:10:21 +01:00
e1711f0345 Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-02-20 15:04:13 +01:00
c327985222 printout tweak 2023-02-20 15:02:00 +01:00
b45206ccd6 Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-02-20 13:33:10 +01:00
c8469ca647 a lot of bug potential here 2023-02-18 14:03:19 +01:00
2d6622b8b8 wtf is this interface 2023-02-18 13:51:24 +01:00
5f9eb01d94 better naming 2023-02-18 13:46:51 +01:00
3568bdbecf lets see if this fixes the issue 2023-02-18 13:45:49 +01:00
fcd84b59ae how the hell does this break anything 2023-02-18 13:37:39 +01:00
e3c968096b i2c small improvements 2023-02-18 13:07:38 +01:00
c745c0c8b4 Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-02-17 13:18:09 +01:00
be015b4c66 service 11: cast to fix warning 2023-02-17 12:07:50 +01:00
dae5e988fd Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-02-17 11:52:23 +01:00
a6d707a7db SubsystemBase: Add function to update child modes 2023-02-17 02:04:17 +01:00
fe41d73895 remove obsolete mode 2023-02-16 17:57:03 +01:00
70b785984c Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-02-14 17:33:59 +01:00
9de6c4b3aa printout corrections 2023-02-14 14:33:02 +01:00
d256ede8c1 fix cppcheck lint 2023-02-14 10:33:22 +01:00
f0b8457ba2 bugfix for SPI
- Set transfer length to 0 for failed transfers
2023-02-13 13:51:52 +01:00
dac2d210b5 updates for thermal module in DHB 2023-02-13 00:36:54 +01:00
8b4f73a97b better error msg 2023-02-12 21:07:11 +01:00
7fae6cbd6d added missing CS unlock 2023-02-12 20:06:32 +01:00
d302ba7185 afmt 2023-02-10 13:51:16 +01:00
14a92b3d89 typo 2023-02-09 18:28:16 +01:00
e4fd424d66 Merge branch 'possible_tc_sched_fixes' into develop 2023-02-09 18:25:44 +01:00
341a66c265 changelog 2023-02-09 18:22:00 +01:00
b9b076aa4c logic error 2023-02-09 18:18:25 +01:00
d93486a340 that time margin check is possible broken 2023-02-09 18:18:05 +01:00
820a7f059c logic error 2023-02-09 18:13:58 +01:00
f4d188c36f that time margin check is possible broken 2023-02-09 18:12:43 +01:00
1841f92944 important bugfix for thermal set 2023-02-09 17:17:42 +01:00
b279985859 refactor DHB: Bugfix for thermal module 2023-02-09 16:42:38 +01:00
fa7675897d Merge pull request 'Mode Service Bugfixes' (#736) from eive/fsfw:mode_service_fixes into development
Reviewed-on: fsfw/fsfw#736
2023-02-09 15:56:26 +01:00
3a2393885f more style 2023-02-09 15:44:39 +01:00
c752b6d143 Merge pull request 'Generic TMTC Bridge Update' (#734) from eive/fsfw:tmtcbridge_tweaks into development
Reviewed-on: fsfw/fsfw#734
2023-02-09 15:37:35 +01:00
b676040c7c Merge pull request 'CMakeLists file updates' (#731) from eive/fsfw:cmakelists_update into development
Reviewed-on: fsfw/fsfw#731
2023-02-09 15:29:46 +01:00
010509efb4 removed unneeded find_package parameter for etl 2023-02-09 13:50:16 +01:00
dfb1633f00 Merge branch 'development' into mode_service_fixes 2023-02-09 13:46:19 +01:00
5f7172e130 Merge pull request 'TCP/IP TMTC bridge memory leak fixes' (#737) from eive/fsfw:possible_tcpip_bridge_fixes into development
Reviewed-on: fsfw/fsfw#737
2023-02-09 12:15:45 +01:00
0c6465cd95 Merge pull request 'time stamper empty ctor' (#730) from eive/fsfw:empty_cds_short_ctor into development
Reviewed-on: fsfw/fsfw#730
2023-02-09 11:45:49 +01:00
f94987c46d Merge pull request 'RM3100 important bugfix' (#733) from eive/fsfw:rm3100_fixes into development
Reviewed-on: fsfw/fsfw#733
2023-02-09 11:41:53 +01:00
1809ce359b Merge pull request 'comment tweak to event parser can read everything' (#732) from eive/fsfw:health_if_update into development
Reviewed-on: fsfw/fsfw#732
2023-02-09 11:39:53 +01:00
8c712441ab Making fetch Catch2 quiet as well. 2023-02-09 11:34:58 +01:00
6ce80ea6c5 Merge branch 'possible_tcpip_bridge_fixes' into develop 2023-02-08 21:27:26 +01:00
f1b0ca7cff add PR link 2023-02-08 21:26:37 +01:00
000df85556 bump changelog 2023-02-08 21:24:00 +01:00
1fffcc2229 possiible leak fixes 2023-02-08 21:23:21 +01:00
7f907fb9d3 Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-02-08 17:17:33 +01:00
a419806a05 Merge remote-tracking branch 'upstream/development' into mode_service_fixes 2023-02-08 09:33:13 +01:00
134d908f26 that stuff is not in upstream yet.. 2023-02-07 12:52:18 +01:00
40a9e12416 1000 is a bit much 2023-02-07 12:47:40 +01:00
f39054edd4 introduce warning switch 2023-02-07 12:45:29 +01:00
5adf89b911 changelog update 2023-02-07 12:41:42 +01:00
c2e6a22dec important bugfix for RM3100 2023-02-07 12:39:43 +01:00
c8e065a713 comment tweak to event parser can read everything 2023-02-07 12:36:42 +01:00
3ed49dbae3 Merge remote-tracking branch 'upstream/development' into empty_cds_short_ctor 2023-02-07 12:24:02 +01:00
a1567de9e8 Merge branch 'develop' into mueller/pus-15-tm-storage 2023-02-07 12:21:35 +01:00
4cf52d5dfe Merge pull request 'Time Service 9 update' (#726) from eive/fsfw:updates_fixes_pus_time_service into development
Reviewed-on: fsfw/fsfw#726
2023-02-07 12:19:45 +01:00
46230e6c6d Merge remote-tracking branch 'upstream/development' into updates_fixes_pus_time_service 2023-02-07 12:11:29 +01:00
b22d439300 bump changelog 2023-02-07 12:10:11 +01:00
7e7b3bbbc9 time stamper empty ctor 2023-02-07 12:07:41 +01:00
06dca7608a time stamper empty ctor 2023-02-07 12:06:34 +01:00
6af5274b68 Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-02-07 10:51:17 +01:00
b1e9dd9e4a Merge remote-tracking branch 'upstream/development' into updates_fixes_pus_time_service 2023-02-06 14:24:38 +01:00
0cc3231ceb Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-01-23 14:20:38 +01:00
041d1b8795 Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2023-01-11 09:17:57 +01:00
2aa4af6974 make function public 2022-12-14 13:50:57 +01:00
75fc7a056d Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2022-12-12 09:02:04 +01:00
1b005d706a Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2022-12-01 16:40:39 +01:00
e68f54b9bd Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2022-11-28 11:37:15 +01:00
296bc56e2a Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2022-11-24 15:16:34 +01:00
2b6a33e718 afmt 2022-11-11 14:13:46 +01:00
61fd5d1b62 impl function to generate ASCII timestamp sec accuracy 2022-11-11 14:12:42 +01:00
046dbe1deb Merge branch 'develop' into mueller/pus-15-tm-storage 2022-11-11 11:38:32 +01:00
0303c1a885 remove file 2022-11-11 11:31:22 +01:00
4d2802a470 Merge remote-tracking branch 'origin/develop' into mueller/pus-15-tm-storage 2022-11-11 11:29:29 +01:00
819a2bfac4 add prototype for new ToAscii CCSDSTime function 2022-10-25 18:20:48 +02:00
096af44e39 needs some fixing 2022-10-24 10:56:01 +02:00
56e8e5a8b3 dont know if I am going to need this 2022-10-24 10:39:43 +02:00
80 changed files with 1046 additions and 661 deletions

View File

@ -12,15 +12,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Fixes ## Fixes
- Add monotonic watchdog Clock API and use it in `Countdown` and `Stopwatch` class.
- Bugfix in `Service11TelecommandScheduling` which allowed commands
time tagged in the past to be inserted.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/738
- `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.
- Memory leak fixes for the TCP/IP TMTC bridge.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737
- `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval - `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval
seconds instead of uptime. seconds instead of uptime.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/726 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/726
- 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
with bytes of the X value.
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity - DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
to false correctly because the `read` and `write` calls were missing. to false correctly because the `read` and `write` calls were missing.
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead - PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
@ -43,6 +51,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `CServiceHealthCommanding`: Add announce all health info implementation - `CServiceHealthCommanding`: Add announce all health info implementation
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122 PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice. - `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT` - `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT`
option on the TCP server. CTOR prototype has changed and expects an explicit option on the TCP server. CTOR prototype has changed and expects an explicit

View File

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

View File

@ -178,16 +178,25 @@ ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info)
dp.user.fileSegmentRecvdIndication(segParams); dp.user.fileSegmentRecvdIndication(segParams);
} }
result = dp.user.vfs.writeToFile(fileOpParams, fileData); result = dp.user.vfs.writeToFile(fileOpParams, fileData);
if (offset.value() + fileSegmentLen > tp.progress) {
tp.progress = offset.value() + fileSegmentLen;
}
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
// TODO: Proper Error handling // TODO: Proper Error handling
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "File write error" << std::endl; sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2)
<< result << std::endl;
#endif #endif
tp.vfsErrorCount++;
if (tp.vfsErrorCount < 3) {
// TODO: Provide execution step as parameter
fp.eventReporter->forwardEvent(events::FILESTORE_ERROR, static_cast<uint8_t>(fsmRes.step),
result);
}
return result;
} else { } else {
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE; tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
tp.vfsErrorCount = 0;
}
if (offset.value() + fileSegmentLen > tp.progress) {
tp.progress = offset.value() + fileSegmentLen;
} }
return result; return result;
} }
@ -271,35 +280,55 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, Met
return OK; return OK;
} }
ReturnValue_t result = OK; ReturnValue_t result = OK;
fsmRes.step = TransactionStep::TRANSACTION_START;
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
}
tp.checksumType = info.getChecksumType();
tp.closureRequested = info.isClosureRequested();
size_t sourceNameSize = 0; size_t sourceNameSize = 0;
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize); const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
if (sourceNameSize > tp.sourceName.size()) { if (sourceNameSize + 1 > tp.sourceName.size()) {
// TODO: Warning, event etc. fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
return FAILED; return FAILED;
} }
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize); std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
tp.sourceName[sourceNameSize] = '\0'; tp.sourceName[sourceNameSize] = '\0';
size_t destNameSize = 0; size_t destNameSize = 0;
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize); const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
if (destNameSize > tp.destName.size()) { if (destNameSize + 1 > tp.destName.size()) {
// TODO: Warning, event etc. fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
return FAILED; return FAILED;
} }
std::memcpy(tp.destName.data(), destNamePtr, destNameSize); std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
tp.destName[destNameSize] = '\0'; tp.destName[destNameSize] = '\0';
reader.fillConfig(tp.pduConf);
tp.pduConf.direction = Direction::TOWARDS_SENDER; // If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
tp.transactionId.entityId = tp.pduConf.sourceId; // so there is no need to create a file or truncate an existing file
tp.transactionId.seqNum = tp.pduConf.seqNum; if (destNameSize > 0 and sourceNameSize > 0) {
if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) { FilesystemParams fparams(tp.destName.data());
// handling to allow only specifying target directory. Example:
// Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt
if (dp.user.vfs.isDirectory(tp.destName.data())) {
result = tryBuildingAbsoluteDestName(destNameSize);
if (result != OK) {
return result;
}
}
if (dp.user.vfs.fileExists(fparams)) {
result = dp.user.vfs.truncateFile(fparams);
if (result != returnvalue::OK) {
fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error");
return FAILED;
// TODO: Relevant for filestore rejection error?
}
} else {
result = dp.user.vfs.createFile(fparams);
if (result != OK) {
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
return FAILED;
// TODO: Relevant for filestore rejection error?
}
}
}
EntityId sourceId;
reader.getSourceId(sourceId);
if (not dp.remoteCfgTable.getRemoteCfg(sourceId, &tp.remoteCfg)) {
// TODO: Warning, event etc. // TODO: Warning, event etc.
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler" << __func__ sif::warning << "cfdp::DestHandler" << __func__
@ -308,22 +337,18 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, Met
#endif #endif
return FAILED; return FAILED;
} }
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU, fsmRes.step = TransactionStep::TRANSACTION_START;
// so there is no need to create a file or truncate an existing file if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
if (destNameSize > 0 and sourceNameSize > 0) { fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
FilesystemParams fparams(tp.destName.data()); } else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
// TODO: Filesystem errors? fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
if (dp.user.vfs.fileExists(fparams)) {
dp.user.vfs.truncateFile(fparams);
} else {
result = dp.user.vfs.createFile(fparams);
if (result != OK) {
// TODO: Handle FS error. This is probably a case for the filestore rejection mechanism of
// CFDP.
// In any case, it does not really make sense to continue here
}
}
} }
tp.checksumType = info.getChecksumType();
tp.closureRequested = info.isClosureRequested();
reader.fillConfig(tp.pduConf);
tp.pduConf.direction = Direction::TOWARDS_SENDER;
tp.transactionId.entityId = tp.pduConf.sourceId;
tp.transactionId.seqNum = tp.pduConf.seqNum;
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS; fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId); MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
params.fileSize = tp.fileSize.getSize(); params.fileSize = tp.fileSize.getSize();
@ -362,6 +387,37 @@ ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
return OK; return OK;
} }
ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) {
char baseNameBuf[tp.destName.size()]{};
FilesystemParams fparamsSrc(tp.sourceName.data());
size_t baseNameLen = 0;
ReturnValue_t result =
dp.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, sizeof(baseNameBuf), baseNameLen);
if (result != returnvalue::OK or baseNameLen == 0) {
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name");
return FAILED;
}
// Destination name + slash + base name + null termination
if (destNameSize + 1 + baseNameLen + 1 > tp.destName.size()) {
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0,
"dest filename too large after adding source base name");
return FAILED;
}
tp.destName[destNameSize++] = '/';
std::memcpy(tp.destName.data() + destNameSize, baseNameBuf, baseNameLen);
destNameSize += baseNameLen;
tp.destName[destNameSize++] = '\0';
return OK;
}
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result, const char* info) {
fp.eventReporter->forwardEvent(events::FILENAME_TOO_LARGE_ERROR,
static_cast<uint8_t>(fsmRes.step), result);
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler: " << info << std::endl;
#endif
}
void cfdp::DestHandler::finish() { void cfdp::DestHandler::finish() {
tp.reset(); tp.reset();
dp.packetListRef.clear(); dp.packetListRef.clear();

View File

@ -84,7 +84,7 @@ enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
class DestHandler { class DestHandler {
public: public:
enum class TransactionStep { enum class TransactionStep : uint8_t {
IDLE = 0, IDLE = 0,
TRANSACTION_START = 1, TRANSACTION_START = 1,
RECEIVING_FILE_DATA_PDUS = 2, RECEIVING_FILE_DATA_PDUS = 2,
@ -157,11 +157,13 @@ class DestHandler {
progress = 0; progress = 0;
remoteCfg = nullptr; remoteCfg = nullptr;
closureRequested = false; closureRequested = false;
vfsErrorCount = 0;
checksumType = ChecksumType::NULL_CHECKSUM; checksumType = ChecksumType::NULL_CHECKSUM;
} }
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM; ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
bool closureRequested = false; bool closureRequested = false;
uint16_t vfsErrorCount = 0;
std::vector<char> sourceName; std::vector<char> sourceName;
std::vector<char> destName; std::vector<char> destName;
cfdp::FileSize fileSize; cfdp::FileSize fileSize;
@ -189,9 +191,11 @@ class DestHandler {
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData, ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
size_t maxSize); size_t maxSize);
ReturnValue_t handleTransferCompletion(); ReturnValue_t handleTransferCompletion();
ReturnValue_t tryBuildingAbsoluteDestName(size_t destNameSize);
ReturnValue_t sendFinishedPdu(); ReturnValue_t sendFinishedPdu();
ReturnValue_t noticeOfCompletion(); ReturnValue_t noticeOfCompletion();
ReturnValue_t checksumVerification(); ReturnValue_t checksumVerification();
void fileErrorHandler(Event event, ReturnValue_t result, const char* info);
const FsmResult& updateFsmRes(uint8_t errors); const FsmResult& updateFsmRes(uint8_t errors);
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx); void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
void finish(); void finish();

View File

@ -12,6 +12,9 @@ namespace events {
static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, severity::LOW); static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, severity::LOW);
static constexpr Event MSG_QUEUE_ERROR = event::makeEvent(SSID, 1, severity::LOW); static constexpr Event MSG_QUEUE_ERROR = event::makeEvent(SSID, 1, severity::LOW);
static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW); static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW);
//! [EXPORT] : [COMMENT] P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name
static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW);
} // namespace events } // namespace events

View File

@ -58,12 +58,7 @@ void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
this->hkDestination = hkDestination; this->hkDestination = hkDestination;
} }
void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId, void DeviceHandlerBase::enableThermalModule(ThermalStateCfg cfg) { this->thermalStateCfg = cfg; }
lp_id_t heaterRequestPoolId,
uint32_t thermalSetId) {
thermalSet =
new DeviceHandlerThermalSet(this, thermalSetId, thermalStatePoolId, heaterRequestPoolId);
}
DeviceHandlerBase::~DeviceHandlerBase() { DeviceHandlerBase::~DeviceHandlerBase() {
if (comCookie != nullptr) { if (comCookie != nullptr) {
@ -227,12 +222,11 @@ ReturnValue_t DeviceHandlerBase::initialize() {
fillCommandAndReplyMap(); fillCommandAndReplyMap();
if (thermalSet != nullptr) { if (thermalSet != nullptr) {
PoolReadGuard pg(thermalSet);
// Set temperature target state to NON_OP. // Set temperature target state to NON_OP.
result = thermalSet->read(); if (pg.getReadResult() == returnvalue::OK) {
if (result == returnvalue::OK) {
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
thermalSet->heaterRequest.setValid(true); thermalSet->heaterRequest.setValid(true);
thermalSet->commit();
} }
} }
@ -382,7 +376,7 @@ void DeviceHandlerBase::doStateMachine() {
} }
ReturnValue_t switchState = getStateOfSwitches(); ReturnValue_t switchState = getStateOfSwitches();
if ((switchState == PowerSwitchIF::SWITCH_OFF) || (switchState == NO_SWITCH)) { if ((switchState == PowerSwitchIF::SWITCH_OFF) || (switchState == NO_SWITCH)) {
setMode(_MODE_SWITCH_IS_OFF); setMode(MODE_OFF, SUBMODE_NONE);
} }
} break; } break;
case MODE_OFF: case MODE_OFF:
@ -395,9 +389,6 @@ void DeviceHandlerBase::doStateMachine() {
case MODE_NORMAL: case MODE_NORMAL:
case MODE_ERROR_ON: case MODE_ERROR_ON:
break; break;
case _MODE_SWITCH_IS_OFF:
setMode(MODE_OFF, SUBMODE_NONE);
break;
default: default:
triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode); triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode);
setMode(_MODE_POWER_DOWN, 0); setMode(_MODE_POWER_DOWN, 0);
@ -574,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 = submode;
mode = _MODE_TO_NORMAL; mode = _MODE_TO_NORMAL;
return; return;
} }
@ -594,12 +588,12 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
Clock::getUptime(&timeoutStart); Clock::getUptime(&timeoutStart);
if (mode == MODE_OFF and thermalSet != nullptr) { if (mode == MODE_OFF and thermalSet != nullptr) {
ReturnValue_t result = thermalSet->read(); PoolReadGuard pg(thermalSet);
if (result == returnvalue::OK) { if (pg.getReadResult() == returnvalue::OK) {
if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) { if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) {
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
} }
thermalSet->heaterRequest.commit(PoolVariableIF::VALID); thermalSet->heaterRequest.setValid(true);
} }
} }
/* TODO: This will probably be done by the LocalDataPoolManager now */ /* TODO: This will probably be done by the LocalDataPoolManager now */
@ -1088,8 +1082,8 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
// Do not check thermal state for MODE_RAW // Do not check thermal state for MODE_RAW
if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and
(thermalSet != nullptr)) { (thermalSet != nullptr)) {
ReturnValue_t result = thermalSet->read(); PoolReadGuard pg(thermalSet);
if (result == returnvalue::OK) { if (pg.getReadResult() == returnvalue::OK) {
if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
(not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) { (not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) {
triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value); triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value);
@ -1150,11 +1144,10 @@ void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, Submode_t
childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON); childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON);
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
if (thermalSet != nullptr) { if (thermalSet != nullptr) {
ReturnValue_t result = thermalSet->read(); PoolReadGuard pg(thermalSet);
if (result == returnvalue::OK) { if (pg.getReadResult() == returnvalue::OK) {
if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL; thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
thermalSet->commit();
} }
} }
} }
@ -1477,11 +1470,11 @@ void DeviceHandlerBase::performOperationHook() {}
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) { LocalDataPoolManager& poolManager) {
if (thermalSet != nullptr) { if (thermalStateCfg.has_value()) {
localDataPoolMap.emplace(thermalSet->thermalStatePoolId, localDataPoolMap.emplace(thermalStateCfg.value().thermalStatePoolId,
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>); new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>());
localDataPoolMap.emplace(thermalSet->heaterRequestPoolId, localDataPoolMap.emplace(thermalStateCfg.value().thermalRequestPoolId,
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>); new PoolEntry<DeviceHandlerIF::dh_heater_request_t>());
} }
return returnvalue::OK; return returnvalue::OK;
} }
@ -1494,6 +1487,10 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
} }
this->poolManager.initializeAfterTaskCreation(); this->poolManager.initializeAfterTaskCreation();
if (thermalStateCfg.has_value()) {
ThermalStateCfg& cfg = thermalStateCfg.value();
thermalSet = new DeviceHandlerThermalSet(this, cfg);
}
if (setStartupImmediately) { if (setStartupImmediately) {
startTransition(MODE_ON, getInitialSubmode()); startTransition(MODE_ON, getInitialSubmode());
} }

View File

@ -2,6 +2,7 @@
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ #define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
#include <map> #include <map>
#include <optional>
#include "DeviceCommunicationIF.h" #include "DeviceCommunicationIF.h"
#include "DeviceHandlerFailureIsolation.h" #include "DeviceHandlerFailureIsolation.h"
@ -149,11 +150,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
//! has been commanded on and the handler waits for it to be on. //! has been commanded on and the handler waits for it to be on.
//! When the switch is on, the mode changes to @c _MODE_TO_ON. //! When the switch is on, the mode changes to @c _MODE_TO_ON.
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4; static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
//! This is a transitional state which can not be commanded. The switch has
//! been commanded off and is off now. This state is only to do an RMAP
//! cycle once more where the doSendRead() function will set the mode to
//! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board.
static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5;
void setHkDestination(object_id_t hkDestination); void setHkDestination(object_id_t hkDestination);
@ -163,13 +159,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* The device handler will then take care of creating local pool entries * The device handler will then take care of creating local pool entries
* for the device thermal state and device heating request. * for the device thermal state and device heating request.
* Custom local pool IDs can be assigned as well. * Custom local pool IDs can be assigned as well.
* @param thermalStatePoolId
* @param thermalRequestPoolId
*/ */
void setThermalStateRequestPoolIds( void enableThermalModule(ThermalStateCfg cfg);
lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID,
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID);
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override; ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
ModeTreeChildIF &getModeTreeChildIF() override; ModeTreeChildIF &getModeTreeChildIF() override;
@ -931,6 +922,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
//! Object which may be the root cause of an identified fault. //! Object which may be the root cause of an identified fault.
static object_id_t defaultFdirParentId; static object_id_t defaultFdirParentId;
std::optional<ThermalStateCfg> thermalStateCfg;
/** /**
* @brief Send a reply to a received device handler command. * @brief Send a reply to a received device handler command.
* *

View File

@ -136,4 +136,10 @@ class DeviceHandlerIF {
virtual MessageQueueId_t getCommandQueue() const = 0; virtual MessageQueueId_t getCommandQueue() const = 0;
}; };
struct ThermalStateCfg {
lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID;
lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID;
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID;
};
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */ #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */

View File

@ -7,27 +7,21 @@
class DeviceHandlerThermalSet : public StaticLocalDataSet<2> { class DeviceHandlerThermalSet : public StaticLocalDataSet<2> {
public: public:
DeviceHandlerThermalSet( DeviceHandlerThermalSet(HasLocalDataPoolIF* hkOwner, ThermalStateCfg cfg)
HasLocalDataPoolIF* hkOwner, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID, : DeviceHandlerThermalSet(hkOwner->getObjectId(), cfg) {}
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
lp_id_t heaterRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID)
: DeviceHandlerThermalSet(hkOwner->getObjectId(), setId, thermalStateId, heaterRequestId) {}
DeviceHandlerThermalSet( DeviceHandlerThermalSet(object_id_t deviceHandler, ThermalStateCfg cfg)
object_id_t deviceHandler, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID, : StaticLocalDataSet(sid_t(deviceHandler, cfg.thermalSetId)),
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, thermalStatePoolId(cfg.thermalStatePoolId),
lp_id_t thermalStateRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID) heaterRequestPoolId(cfg.thermalRequestPoolId) {}
: StaticLocalDataSet(sid_t(deviceHandler, setId)),
thermalStatePoolId(thermalStateId),
heaterRequestPoolId(thermalStateRequestId) {}
const lp_id_t thermalStatePoolId; const lp_id_t thermalStatePoolId;
const lp_id_t heaterRequestPoolId; const lp_id_t heaterRequestPoolId;
lp_var_t<DeviceHandlerIF::dh_thermal_state_t> thermalState = lp_var_t<DeviceHandlerIF::dh_thermal_state_t> thermalState =
lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(thermalStatePoolId, sid.objectId, this); lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(sid.objectId, thermalStatePoolId, this);
lp_var_t<DeviceHandlerIF::dh_heater_request_t> heaterRequest = lp_var_t<DeviceHandlerIF::dh_heater_request_t> heaterRequest =
lp_var_t<DeviceHandlerIF::dh_heater_request_t>(heaterRequestPoolId, sid.objectId, this); lp_var_t<DeviceHandlerIF::dh_heater_request_t>(sid.objectId, heaterRequestPoolId, this);
}; };
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */ #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */

View File

@ -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() {

View File

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

View File

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

View File

@ -74,6 +74,12 @@ class HasFileSystemIF {
return MessageQueueIF::NO_QUEUE; return MessageQueueIF::NO_QUEUE;
} }
// Get the base filename without the full directory path
virtual ReturnValue_t getBaseFilename(FilesystemParams params, char* nameBuf, size_t maxLen,
size_t& baseNameLen) = 0;
virtual bool isDirectory(const char* path) = 0;
virtual bool fileExists(FilesystemParams params) = 0; virtual bool fileExists(FilesystemParams params) = 0;
/** /**

View File

@ -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) {

View File

@ -15,6 +15,7 @@ enum framework_objects : object_id_t {
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008, PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
PUS_SERVICE_9_TIME_MGMT = 0x53000009, PUS_SERVICE_9_TIME_MGMT = 0x53000009,
PUS_SERVICE_11_TC_SCHEDULER = 0x53000011, PUS_SERVICE_11_TC_SCHEDULER = 0x53000011,
PUS_SERVICE_15_TM_STORAGE = 0x53000015,
PUS_SERVICE_17_TEST = 0x53000017, PUS_SERVICE_17_TEST = 0x53000017,
PUS_SERVICE_20_PARAMETERS = 0x53000020, PUS_SERVICE_20_PARAMETERS = 0x53000020,
PUS_SERVICE_200_MODE_MGMT = 0x53000200, PUS_SERVICE_200_MODE_MGMT = 0x53000200,

View File

@ -41,6 +41,7 @@ int TcpIpBase::closeSocket(socket_t socket) {
#elif defined(PLATFORM_UNIX) #elif defined(PLATFORM_UNIX)
return close(socket); return close(socket);
#endif #endif
return -1;
} }
int TcpIpBase::getLastSocketError() { int TcpIpBase::getLastSocketError() {
@ -49,4 +50,5 @@ int TcpIpBase::getLastSocketError() {
#elif defined(PLATFORM_UNIX) #elif defined(PLATFORM_UNIX)
return errno; return errno;
#endif #endif
return 0;
} }

View File

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

View File

@ -38,7 +38,7 @@ class TcpTmTcBridge : public TmTcBridge {
* @param tmStoreId TM store object ID. It is recommended to the default object ID * @param 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();

View File

@ -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 {
@ -126,10 +126,7 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL); tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL);
} }
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent << " bytes were sent" << std::endl;
<< " bytes were"
" sent."
<< std::endl;
#endif #endif
return returnvalue::OK; return returnvalue::OK;
} }

View File

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

View File

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

View File

@ -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,11 +92,16 @@ 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.

View File

@ -1,5 +1,7 @@
#include "DummyPowerSwitcher.h" #include "DummyPowerSwitcher.h"
#include <utility>
DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches,
size_t numberOfFuses, bool registerGlobally, size_t numberOfFuses, bool registerGlobally,
uint32_t switchDelayMs) uint32_t switchDelayMs)
@ -9,11 +11,11 @@ DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwit
switchDelayMs(switchDelayMs) {} switchDelayMs(switchDelayMs) {}
void DummyPowerSwitcher::setInitialSwitcherList(std::vector<ReturnValue_t> switcherList) { void DummyPowerSwitcher::setInitialSwitcherList(std::vector<ReturnValue_t> switcherList) {
this->switcherList = switcherList; this->switcherList = std::move(switcherList);
} }
void DummyPowerSwitcher::setInitialFusesList(std::vector<ReturnValue_t> fuseList) { void DummyPowerSwitcher::setInitialFusesList(std::vector<ReturnValue_t> fuseList) {
this->fuseList = fuseList; this->fuseList = std::move(fuseList);
} }
ReturnValue_t DummyPowerSwitcher::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) { ReturnValue_t DummyPowerSwitcher::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {

View File

@ -19,7 +19,7 @@ ReturnValue_t CService200ModeCommanding::isValidSubservice(uint8_t subservice) {
switch (subservice) { switch (subservice) {
case (Subservice::COMMAND_MODE_COMMAND): case (Subservice::COMMAND_MODE_COMMAND):
case (Subservice::COMMAND_MODE_READ): case (Subservice::COMMAND_MODE_READ):
case (Subservice::COMMAND_MODE_ANNCOUNCE): case (Subservice::COMMAND_MODE_ANNOUNCE):
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY): case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
return returnvalue::OK; return returnvalue::OK;
default: default:
@ -54,6 +54,7 @@ ReturnValue_t CService200ModeCommanding::checkInterfaceAndAcquireMessageQueue(
ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice, ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
const uint8_t *tcData, size_t tcDataLen, const uint8_t *tcData, size_t tcDataLen,
uint32_t *state, object_id_t objectId) { uint32_t *state, object_id_t objectId) {
bool recursive = false;
switch (subservice) { switch (subservice) {
case (Subservice::COMMAND_MODE_COMMAND): { case (Subservice::COMMAND_MODE_COMMAND): {
ModePacket modeCommandPacket; ModePacket modeCommandPacket;
@ -67,22 +68,17 @@ ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message,
modeCommandPacket.getMode(), modeCommandPacket.getSubmode()); modeCommandPacket.getMode(), modeCommandPacket.getSubmode());
return returnvalue::OK; return returnvalue::OK;
} }
case (Subservice::COMMAND_MODE_ANNCOUNCE): case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY): { recursive = true;
bool recursive = true; [[fallthrough]];
if (subservice == Subservice::COMMAND_MODE_ANNCOUNCE) { case (Subservice::COMMAND_MODE_ANNOUNCE):
recursive = false;
}
ModeMessage::setModeAnnounceMessage(*message, recursive); ModeMessage::setModeAnnounceMessage(*message, recursive);
return EXECUTION_COMPLETE; return EXECUTION_COMPLETE;
} case (Subservice::COMMAND_MODE_READ):
case (Subservice::COMMAND_MODE_READ): {
ModeMessage::setModeReadMessage(*message); ModeMessage::setModeReadMessage(*message);
return returnvalue::OK; return returnvalue::OK;
} default:
default: {
return CommandingServiceBase::INVALID_SUBSERVICE; return CommandingServiceBase::INVALID_SUBSERVICE;
}
} }
} }

View File

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

View File

@ -68,6 +68,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) {
@ -79,7 +82,7 @@ ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message,
} }
case (Subservice::COMMAND_ANNOUNCE_HEALTH): { case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE); HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
break; return CommandingServiceBase::EXECUTION_COMPLETE;
} }
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): { case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
ReturnValue_t result = iterateHealthTable(true); ReturnValue_t result = iterateHealthTable(true);

View File

@ -160,7 +160,7 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivi
// (See requirement for Time margin) // (See requirement for Time margin)
timeval tNow = {}; timeval tNow = {};
Clock::getClock_timeval(&tNow); Clock::getClock_timeval(&tNow);
if (timestamp - tNow.tv_sec <= RELEASE_TIME_MARGIN_SECONDS) { if (timestamp < static_cast<uint32_t>(tNow.tv_sec + RELEASE_TIME_MARGIN_SECONDS)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service11TelecommandScheduling::doInsertActivity: Release time too close to " sif::warning << "Service11TelecommandScheduling::doInsertActivity: Release time too close to "
"current time" "current time"

View File

@ -10,7 +10,7 @@ PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPo
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;
} }

View File

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

View File

@ -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,13 +35,21 @@ 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 != submodeToCheckAgainst) { if ((childIter->second.submode | mask) != mask) {
return returnvalue::FAILED; return returnvalue::FAILED;
}
} else {
if (childIter->second.submode != submodeToCheckAgainst) {
return returnvalue::FAILED;
}
} }
} }
return returnvalue::OK; return returnvalue::OK;
@ -117,6 +126,20 @@ ReturnValue_t SubsystemBase::updateChildMode(MessageQueueId_t queue, Mode_t mode
return CHILD_NOT_FOUND; return CHILD_NOT_FOUND;
} }
ReturnValue_t SubsystemBase::updateChildModeByObjId(object_id_t objectId, Mode_t mode,
Submode_t submode) {
std::map<object_id_t, ChildInfo>::iterator iter;
for (iter = childrenMap.begin(); iter != childrenMap.end(); iter++) {
if (iter->first == objectId) {
iter->second.mode = mode;
iter->second.submode = submode;
return returnvalue::OK;
}
}
return CHILD_NOT_FOUND;
}
ReturnValue_t SubsystemBase::updateChildChangedHealth(MessageQueueId_t queue, bool changedHealth) { ReturnValue_t SubsystemBase::updateChildChangedHealth(MessageQueueId_t queue, bool changedHealth) {
for (auto iter = childrenMap.begin(); iter != childrenMap.end(); iter++) { for (auto iter = childrenMap.begin(); iter != childrenMap.end(); iter++) {
if (iter->second.commandQueue == queue) { if (iter->second.commandQueue == queue) {

View File

@ -115,6 +115,7 @@ class SubsystemBase : public SystemObject,
Submode_t targetSubmode = SUBMODE_NONE); Submode_t targetSubmode = SUBMODE_NONE);
ReturnValue_t updateChildMode(MessageQueueId_t queue, Mode_t mode, Submode_t submode); ReturnValue_t updateChildMode(MessageQueueId_t queue, Mode_t mode, Submode_t submode);
ReturnValue_t updateChildModeByObjId(object_id_t objectId, Mode_t mode, Submode_t submode);
ReturnValue_t updateChildChangedHealth(MessageQueueId_t queue, bool changedHealth = true); ReturnValue_t updateChildChangedHealth(MessageQueueId_t queue, bool changedHealth = true);

View File

@ -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);
return result;
} }
virtual size_t getSerializedSize() const { ModeListEntry& operator=(const ModeListEntry& other) {
return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4); this->value1.entry = other.value1.entry;
this->value2.entry = other.value2.entry;
this->value3.entry = other.value3.entry;
this->value4.entry = other.value4.entry;
this->value5.entry = other.value5.entry;
return *this;
} }
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, void setLinks() {
Endianness streamEndianness) { setStart(&value1);
ReturnValue_t result; value1.setNext(&value2);
value2.setNext(&value3);
result = SerializeAdapter::deSerialize(&value1, buffer, size, streamEndianness); value3.setNext(&value4);
value4.setNext(&value5);
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; bool submodesAllowed(uint8_t* mask) const {
} else { bool submodesAllowed = (value4.entry & mode::SpecialSubmodeFlags::ALLOWED_MASK) ==
value4 = 0; mode::SpecialSubmodeFlags::ALLOWED_MASK;
if (submodesAllowed and mask != nullptr) {
*mask = value5.entry;
} }
return submodesAllowed;
} }
bool operator==(ModeListEntry other) { /**
return ((value1 == other.value1) && (value2 == other.value2) && (value3 == other.value3)); * Enable the inheritance of submodes. This is relevant for both the execution
* of mode tables and for mode checking.
*/
void enableInheritSubmode() { value4.entry |= mode::SpecialSubmodeFlags::INHERIT; }
/**
* Disable the inheritance of submodes. This is relevant for both the execution
* of mode tables and for mode checking.
*/
void disableInheritSubmode() { value4.entry &= ~mode::SpecialSubmodeFlags::INHERIT; }
/**
* Specialization of @enableSubmodeAllowed which allows all submodes.
*/
void allowAllSubmodes() { enableSubmodeAllowed(ALL_SUBMODES_ALLOWED_MASK); }
/**
* Enable an allowed submode mask for mode checks. Any submode which contains bits
* outside of the mask will be declined.
*
* For example, for a mask of 0b11, only the modes 0b00, 0b01 and 0b11 will be accepted.
*/
void enableSubmodeAllowed(uint8_t mask) {
value4.entry |= mode::SpecialSubmodeFlags::ALLOWED_MASK;
value5.entry = mask;
}
/**
* Enforce the equality of submodes for mode checks. This is the default.
*/
void disableSubmodeAllowed() {
value4.entry &= ~mode::SpecialSubmodeFlags::ALLOWED_MASK;
value5.entry = 0;
} }
}; };

View File

@ -15,10 +15,10 @@ ReturnValue_t FixedTimeslotTaskBase::addSlot(object_id_t execId, ExecutableObjec
uint32_t slotTimeMs, int8_t executionStep) { uint32_t slotTimeMs, int8_t executionStep) {
if (execObj == nullptr) { if (execObj == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Component 0x" << std::hex << std::setw(8) << std::setfill('0') << execObj sif::error << "Component 0x" << std::hex << std::setw(8) << std::setfill('0') << execId
<< std::setfill(' ') << " not found, not adding it to PST" << std::dec << std::endl; << std::setfill(' ') << " not found, not adding it to PST" << std::dec << std::endl;
#else #else
sif::printError("Component 0x%08x not found, not adding it to PST\n"); sif::printError("Component 0x%08x not found, not adding it to PST\n", execId);
#endif #endif
return returnvalue::FAILED; return returnvalue::FAILED;
} }

View File

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

View File

@ -246,6 +246,20 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
return UNSUPPORTED_TIME_FORMAT; return UNSUPPORTED_TIME_FORMAT;
} }
ReturnValue_t CCSDSTime::convertToAsciiWithSecs(int8_t* to, const Clock::TimeOfDay_t* from,
uint8_t length) {
if (from == nullptr or to == nullptr) {
return returnvalue::FAILED;
}
int count = snprintf(reinterpret_cast<char*>(to), length,
"%4" SCNu32 "-%2" SCNu32 "-%2" SCNu32 "T%2" SCNu32 ":%2" SCNu32 ":%2" SCNu32,
from->year, from->month, from->day, from->hour, from->minute, from->second);
if (count >= length) {
return returnvalue::FAILED;
}
return returnvalue::OK;
}
ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) { ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) {
const Ccs_mseconds* time_struct = reinterpret_cast<const Ccs_mseconds*>(time); const Ccs_mseconds* time_struct = reinterpret_cast<const Ccs_mseconds*>(time);

View File

@ -207,7 +207,8 @@ class CCSDSTime {
static ReturnValue_t convertFromASCII(Clock::TimeOfDay_t *to, uint8_t const *from, static ReturnValue_t convertFromASCII(Clock::TimeOfDay_t *to, uint8_t const *from,
uint8_t length); uint8_t length);
static ReturnValue_t convertToAsciiWithSecs(int8_t *to, const Clock::TimeOfDay_t *from,
uint8_t length);
static uint32_t subsecondsToMicroseconds(uint16_t subseconds); static uint32_t subsecondsToMicroseconds(uint16_t subseconds);
private: private:

View File

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

View File

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

View File

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

View File

@ -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(&currentTime); ReturnValue_t Countdown::setTimeoutTv(timeval tv) {
timeout = tv;
return Clock::getClockMonotonic(&startTime);
}
uint32_t Countdown::getTimeoutMs() const { return timeout.tv_sec * 1000 + timeout.tv_usec / 1000; }
timeval Countdown::getTimeout() const { return timeout; }
timeval Countdown::getCurrentTime() const {
timeval currentTime{};
Clock::getClockMonotonic(&currentTime);
return currentTime; return currentTime;
} }

View File

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

View File

@ -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::getUptime(&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::getUptime(&endTime); Clock::getClockMonotonic(&endTime);
elapsedTime = endTime - startTime; elapsedTime = endTime - startTime;
} }

View File

@ -6,47 +6,12 @@
#include "fsfw/returnvalues/returnvalue.h" #include "fsfw/returnvalues/returnvalue.h"
#include "tmStorageConf.h" #include "tmStorageConf.h"
class TmPacketMinimal; class PusTmReader;
class SpacePacketBase; class SpacePacketReader;
class TmStoreBackendIF; class TmStoreBackendIF;
class TmStoreFrontendIF { class TmStoreFrontendIF {
public: public:
virtual TmStoreBackendIF* getBackend() const = 0;
/**
* What do I need to implement here?
* This is propably used by PUS Service 15 so we should propably check for messages..
* Provide base implementation?
* @param opCode
* @return
*/
virtual ReturnValue_t performOperation(uint8_t opCode) = 0;
/**
* Callback from the back-end to indicate a certain packet was received.
* front-end takes care of discarding/downloading the packet.
* @param packet Pointer to the newly received Space Packet.
* @param address Start address of the packet found
* @param isLastPacket Indicates if no more packets can be fetched.
* @return If more packets shall be fetched, returnvalue::OK must be returned.
* Any other code stops fetching packets.
*/
virtual ReturnValue_t packetRetrieved(TmPacketMinimal* packet, uint32_t address) = 0;
virtual void noMorePacketsInStore() = 0;
virtual void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0,
uint32_t parameter2 = 0) = 0;
/**
* To get the queue where commands shall be sent.
* @return Id of command queue.
*/
virtual MessageQueueId_t getCommandQueue() const = 0;
virtual ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end) = 0;
virtual ReturnValue_t deletePackets(ApidSsc upTo) = 0;
virtual ReturnValue_t checkPacket(SpacePacketBase* tmPacket) = 0;
virtual bool isEnabled() const = 0;
virtual void setEnabled(bool enabled) = 0;
virtual void resetDownlinkedPacketCount() = 0;
virtual ReturnValue_t setDumpTarget(object_id_t dumpTarget) = 0;
static const uint8_t INTERFACE_ID = CLASS_ID::TM_STORE_FRONTEND_IF; static const uint8_t INTERFACE_ID = CLASS_ID::TM_STORE_FRONTEND_IF;
static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1); static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1);
static const ReturnValue_t LAST_PACKET_FOUND = MAKE_RETURN_CODE(2); static const ReturnValue_t LAST_PACKET_FOUND = MAKE_RETURN_CODE(2);
@ -57,7 +22,38 @@ class TmStoreFrontendIF {
static const ReturnValue_t ALL_DELETED = MAKE_RETURN_CODE(7); static const ReturnValue_t ALL_DELETED = MAKE_RETURN_CODE(7);
static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(8); static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(8);
static const ReturnValue_t NOT_READY = MAKE_RETURN_CODE(9); static const ReturnValue_t NOT_READY = MAKE_RETURN_CODE(9);
virtual ~TmStoreFrontendIF() {}
virtual ~TmStoreFrontendIF() = default;
/**
* To get the queue where commands shall be sent.
* @return Id of command queue.
*/
virtual MessageQueueId_t getCommandQueue() const = 0;
virtual TmStoreBackendIF* getBackend() const = 0;
/**
* Callback from the back-end to indicate a certain packet was received.
* front-end takes care of discarding/downloading the packet.
* @param packet Pointer to the newly received Space Packet.
* @param address Start address of the packet found
* @param isLastPacket Indicates if no more packets can be fetched.
* @return If more packets shall be fetched, returnvalue::OK must be returned.
* Any other code stops fetching packets.
*/
virtual ReturnValue_t packetRetrieved(PusTmReader* packet, uint32_t address) = 0;
virtual void noMorePacketsInStore() = 0;
virtual void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0,
uint32_t parameter2 = 0) = 0;
virtual ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end) = 0;
virtual ReturnValue_t deletePackets(ApidSsc upTo) = 0;
virtual ReturnValue_t checkPacket(SpacePacketReader* tmPacket) = 0;
virtual bool isEnabled() const = 0;
virtual void setEnabled(bool enabled) = 0;
virtual void resetDownlinkedPacketCount() = 0;
virtual ReturnValue_t setDumpTarget(object_id_t dumpTarget) = 0;
}; };
#endif /* FSFW_TMTCSERVICES_TMSTOREFRONTENDIF_H_ */ #endif /* FSFW_TMTCSERVICES_TMSTOREFRONTENDIF_H_ */

View File

@ -0,0 +1,15 @@
#ifndef FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_
#define FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_
#include <fsfw/ipc/messageQueueDefinitions.h>
class TmStoreFrontendSimpleIF {
public:
virtual ~TmStoreFrontendSimpleIF() = default;
virtual MessageQueueId_t getCommandQueue() const = 0;
private:
};
#endif /* FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_ */

View File

@ -1,6 +1,10 @@
#ifndef FSFW_TMSTORAGE_TMSTOREPACKETS_H_ #ifndef FSFW_TMSTORAGE_TMSTOREPACKETS_H_
#define FSFW_TMSTORAGE_TMSTOREPACKETS_H_ #define FSFW_TMSTORAGE_TMSTOREPACKETS_H_
#include <fsfw/tmtcpacket/pus/tm/PusTmReader.h>
#include <vector>
#include "fsfw/globalfunctions/timevalOperations.h" #include "fsfw/globalfunctions/timevalOperations.h"
#include "fsfw/serialize/SerialBufferAdapter.h" #include "fsfw/serialize/SerialBufferAdapter.h"
#include "fsfw/serialize/SerialFixedArrayListAdapter.h" #include "fsfw/serialize/SerialFixedArrayListAdapter.h"
@ -24,7 +28,7 @@ class ServiceSubservice : public SerialLinkedListAdapter<SerializeIF> {
class ApidSsc : public SerializeIF { class ApidSsc : public SerializeIF {
public: public:
ApidSsc() : apid(SpacePacketBase::LIMIT_APID), ssc(0) {} ApidSsc() : apid(ccsds::LIMIT_APID), ssc(0) {}
ApidSsc(uint16_t apid, uint16_t ssc) : apid(apid), ssc(ssc) {} ApidSsc(uint16_t apid, uint16_t ssc) : apid(apid), ssc(ssc) {}
uint16_t apid; uint16_t apid;
uint16_t ssc; uint16_t ssc;
@ -62,51 +66,59 @@ class ChangeSelectionDefinition : public SerialLinkedListAdapter<SerializeIF> {
class TmPacketInformation : public SerializeIF { class TmPacketInformation : public SerializeIF {
public: public:
TmPacketInformation(TmPacketMinimal* packet) { setContent(packet); } TmPacketInformation(PusTmReader* packet, size_t timestampLen) : rawTimestamp(timestampLen) {
TmPacketInformation() setContent(packet);
: apid(SpacePacketBase::LIMIT_APID), }
TmPacketInformation(size_t timestampLen)
: apid(ccsds::LIMIT_APID),
sourceSequenceCount(0), sourceSequenceCount(0),
serviceType(0), serviceType(0),
serviceSubtype(0), serviceSubtype(0),
subCounter(0) {} subCounter(0),
rawTimestamp(timestampLen) {}
void reset() { void reset() {
apid = SpacePacketBase::LIMIT_APID; apid = ccsds::LIMIT_APID;
sourceSequenceCount = 0; sourceSequenceCount = 0;
serviceType = 0; serviceType = 0;
serviceSubtype = 0; serviceSubtype = 0;
subCounter = 0; subCounter = 0;
memset(rawTimestamp, 0, sizeof(rawTimestamp)); memset(rawTimestamp.data(), 0, rawTimestamp.size());
} }
void setContent(TmPacketMinimal* packet) { void setContent(PusTmReader* packet) {
apid = packet->getAPID(); apid = packet->getApid();
sourceSequenceCount = packet->getPacketSequenceCount(); sourceSequenceCount = packet->getSequenceCount();
serviceType = packet->getService(); serviceType = packet->getService();
serviceSubtype = packet->getSubService(); serviceSubtype = packet->getSubService();
subCounter = packet->getPacketSubcounter(); subCounter = packet->getMessageTypeCounter();
memset(rawTimestamp, 0, sizeof(rawTimestamp)); memset(rawTimestamp.data(), 0, rawTimestamp.size());
const uint8_t* pField = NULL; // TODO: Fix all of this
uint32_t size = 0; // const uint8_t* pField = NULL;
ReturnValue_t result = packet->getPacketTimeRaw(&pField, &size); // uint32_t size = 0;
if (result != returnvalue::OK) { // auto* timeReader = packet->getTimeReader();
return; // ReturnValue_t result = packet->getPacketTimeRaw(&pField, &size);
} // if (result != returnvalue::OK) {
if (*pField == CCSDSTime::P_FIELD_CDS_SHORT && size <= TimeStamperIF::MISSION_TIMESTAMP_SIZE) { // return;
// Shortcut to avoid converting CDS back and forth. //}
memcpy(rawTimestamp, pField, size); // if (*pField == CCSDSTime::P_FIELD_CDS_SHORT && size <= TimeStamperIF::MISSION_TIMESTAMP_SIZE)
return; // {
} // Shortcut to avoid converting CDS back and forth.
timeval time = {0, 0}; // TODO: Fix
result = packet->getPacketTime(&time); // memcpy(rawTimestamp, pField, size);
if (result != returnvalue::OK) { // return;
return; // }
} // timeval time = {0, 0};
// result = packet->getPacketTime(&time);
CCSDSTime::CDS_short cdsFormat; // if (result != returnvalue::OK) {
result = CCSDSTime::convertToCcsds(&cdsFormat, &time); // return;
if (result != returnvalue::OK) { // }
return; //
} // CCSDSTime::CDS_short cdsFormat;
memcpy(rawTimestamp, &cdsFormat, sizeof(cdsFormat)); // result = CCSDSTime::convertToCcsds(&cdsFormat, &time);
// if (result != returnvalue::OK) {
// return;
// }
// TODO: Fix
// memcpy(rawTimestamp, &cdsFormat, sizeof(cdsFormat));
} }
void setContent(TmPacketInformation* content) { void setContent(TmPacketInformation* content) {
apid = content->apid; apid = content->apid;
@ -114,9 +126,10 @@ class TmPacketInformation : public SerializeIF {
serviceType = content->serviceType; serviceType = content->serviceType;
serviceSubtype = content->serviceSubtype; serviceSubtype = content->serviceSubtype;
subCounter = content->subCounter; subCounter = content->subCounter;
memcpy(rawTimestamp, content->rawTimestamp, sizeof(rawTimestamp)); // TODO: Fix
// memcpy(rawTimestamp, content->rawTimestamp, sizeof(rawTimestamp));
} }
bool isValid() const { return (apid < SpacePacketBase::LIMIT_APID) ? true : false; } bool isValid() const { return (apid < ccsds::LIMIT_APID) ? true : false; }
static void reset(TmPacketInformation* packet) { packet->reset(); } static void reset(TmPacketInformation* packet) { packet->reset(); }
static bool isOlderThan(const TmPacketInformation* packet, const timeval* cmpTime) { static bool isOlderThan(const TmPacketInformation* packet, const timeval* cmpTime) {
@ -216,7 +229,7 @@ class TmPacketInformation : public SerializeIF {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
SerialBufferAdapter<uint8_t> adapter(rawTimestamp, sizeof(rawTimestamp)); SerialBufferAdapter<uint8_t> adapter(rawTimestamp.data(), rawTimestamp.size());
return adapter.serialize(buffer, size, maxSize, streamEndianness); return adapter.serialize(buffer, size, maxSize, streamEndianness);
} }
@ -227,7 +240,7 @@ class TmPacketInformation : public SerializeIF {
size += SerializeAdapter::getSerializedSize(&serviceType); size += SerializeAdapter::getSerializedSize(&serviceType);
size += SerializeAdapter::getSerializedSize(&serviceSubtype); size += SerializeAdapter::getSerializedSize(&serviceSubtype);
size += SerializeAdapter::getSerializedSize(&subCounter); size += SerializeAdapter::getSerializedSize(&subCounter);
SerialBufferAdapter<uint8_t> adapter(rawTimestamp, sizeof(rawTimestamp)); SerialBufferAdapter<uint8_t> adapter(rawTimestamp.data(), rawTimestamp.size());
size += adapter.getSerializedSize(); size += adapter.getSerializedSize();
return size; return size;
}; };
@ -253,7 +266,7 @@ class TmPacketInformation : public SerializeIF {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
SerialBufferAdapter<uint8_t> adapter(rawTimestamp, sizeof(rawTimestamp)); SerialBufferAdapter<uint8_t> adapter(rawTimestamp.data(), rawTimestamp.size());
return adapter.deSerialize(buffer, size, streamEndianness); return adapter.deSerialize(buffer, size, streamEndianness);
} }
@ -263,6 +276,6 @@ class TmPacketInformation : public SerializeIF {
uint8_t serviceType; uint8_t serviceType;
uint8_t serviceSubtype; uint8_t serviceSubtype;
uint8_t subCounter; uint8_t subCounter;
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; std::vector<uint8_t> rawTimestamp;
}; };
#endif /* FSFW_TMSTORAGE_TMSTOREPACKETS_H_ */ #endif /* FSFW_TMSTORAGE_TMSTOREPACKETS_H_ */

View File

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

View File

@ -15,15 +15,14 @@ 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 = 1000; static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500;
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
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;
/** /**

View File

@ -1,6 +1,7 @@
#include "version.h" #include "version.h"
#include <cstdio> #include <cstdio>
#include <cstring>
#include "fsfw/FSFWVersion.h" #include "fsfw/FSFWVersion.h"
@ -20,7 +21,7 @@ fsfw::Version::Version(int major, int minor, int revision, const char* addInfo)
void fsfw::Version::getVersion(char* str, size_t maxLen) const { void fsfw::Version::getVersion(char* str, size_t maxLen) const {
size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision); size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
if (addInfo != nullptr) { if (addInfo != nullptr and std::strcmp(addInfo, "") != 0) {
snprintf(str + len, maxLen - len, "-%s", addInfo); snprintf(str + len, maxLen - len, "-%s", addInfo);
} }
} }
@ -30,7 +31,7 @@ namespace fsfw {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
std::ostream& operator<<(std::ostream& os, const Version& v) { std::ostream& operator<<(std::ostream& os, const Version& v) {
os << v.major << "." << v.minor << "." << v.revision; os << v.major << "." << v.minor << "." << v.revision;
if (v.addInfo != nullptr) { if (v.addInfo != nullptr and std::strcmp(v.addInfo, "") != 0) {
os << "-" << v.addInfo; os << "-" << v.addInfo;
} }
return os; return os;

View File

@ -1,3 +1,5 @@
target_sources( target_sources(
${LIB_FSFW_NAME} PRIVATE GyroL3GD20Handler.cpp MgmRM3100Handler.cpp ${LIB_FSFW_NAME} PRIVATE GyroL3GD20Handler.cpp MgmRM3100Handler.cpp
MgmLIS3MDLHandler.cpp) MgmLIS3MDLHandler.cpp)
add_subdirectory(devicedefinitions)

View File

@ -46,17 +46,17 @@ ReturnValue_t GyroHandlerL3GD20H::buildTransitionDeviceCommand(DeviceCommandId_t
return NOTHING_TO_SEND; return NOTHING_TO_SEND;
} }
case (InternalState::CONFIGURE): { case (InternalState::CONFIGURE): {
*id = L3GD20H::CONFIGURE_CTRL_REGS; *id = l3gd20h::CONFIGURE_CTRL_REGS;
uint8_t command[5]; uint8_t command[5];
command[0] = L3GD20H::CTRL_REG_1_VAL; command[0] = l3gd20h::CTRL_REG_1_VAL;
command[1] = L3GD20H::CTRL_REG_2_VAL; command[1] = l3gd20h::CTRL_REG_2_VAL;
command[2] = L3GD20H::CTRL_REG_3_VAL; command[2] = l3gd20h::CTRL_REG_3_VAL;
command[3] = L3GD20H::CTRL_REG_4_VAL; command[3] = l3gd20h::CTRL_REG_4_VAL;
command[4] = L3GD20H::CTRL_REG_5_VAL; command[4] = l3gd20h::CTRL_REG_5_VAL;
return buildCommandFromCommand(*id, command, 5); return buildCommandFromCommand(*id, command, 5);
} }
case (InternalState::CHECK_REGS): { case (InternalState::CHECK_REGS): {
*id = L3GD20H::READ_REGS; *id = l3gd20h::READ_REGS;
return buildCommandFromCommand(*id, nullptr, 0); return buildCommandFromCommand(*id, nullptr, 0);
} }
default: default:
@ -76,7 +76,7 @@ ReturnValue_t GyroHandlerL3GD20H::buildTransitionDeviceCommand(DeviceCommandId_t
} }
ReturnValue_t GyroHandlerL3GD20H::buildNormalDeviceCommand(DeviceCommandId_t *id) { ReturnValue_t GyroHandlerL3GD20H::buildNormalDeviceCommand(DeviceCommandId_t *id) {
*id = L3GD20H::READ_REGS; *id = l3gd20h::READ_REGS;
return buildCommandFromCommand(*id, nullptr, 0); return buildCommandFromCommand(*id, nullptr, 0);
} }
@ -84,15 +84,15 @@ ReturnValue_t GyroHandlerL3GD20H::buildCommandFromCommand(DeviceCommandId_t devi
const uint8_t *commandData, const uint8_t *commandData,
size_t commandDataLen) { size_t commandDataLen) {
switch (deviceCommand) { switch (deviceCommand) {
case (L3GD20H::READ_REGS): { case (l3gd20h::READ_REGS): {
commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK | L3GD20H::READ_MASK; commandBuffer[0] = l3gd20h::READ_START | l3gd20h::AUTO_INCREMENT_MASK | l3gd20h::READ_MASK;
std::memset(commandBuffer + 1, 0, L3GD20H::READ_LEN); std::memset(commandBuffer + 1, 0, l3gd20h::READ_LEN);
rawPacket = commandBuffer; rawPacket = commandBuffer;
rawPacketLen = L3GD20H::READ_LEN + 1; rawPacketLen = l3gd20h::READ_LEN + 1;
break; break;
} }
case (L3GD20H::CONFIGURE_CTRL_REGS): { case (l3gd20h::CONFIGURE_CTRL_REGS): {
commandBuffer[0] = L3GD20H::CTRL_REG_1 | L3GD20H::AUTO_INCREMENT_MASK; commandBuffer[0] = l3gd20h::CTRL_REG_1 | l3gd20h::AUTO_INCREMENT_MASK;
if (commandData == nullptr or commandDataLen != 5) { if (commandData == nullptr or commandDataLen != 5) {
return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; return DeviceHandlerIF::INVALID_COMMAND_PARAMETER;
} }
@ -103,15 +103,15 @@ ReturnValue_t GyroHandlerL3GD20H::buildCommandFromCommand(DeviceCommandId_t devi
ctrlReg4Value = commandData[3]; ctrlReg4Value = commandData[3];
ctrlReg5Value = commandData[4]; ctrlReg5Value = commandData[4];
bool fsH = ctrlReg4Value & L3GD20H::SET_FS_1; bool fsH = ctrlReg4Value & l3gd20h::SET_FS_1;
bool fsL = ctrlReg4Value & L3GD20H::SET_FS_0; bool fsL = ctrlReg4Value & l3gd20h::SET_FS_0;
if (not fsH and not fsL) { if (not fsH and not fsL) {
sensitivity = L3GD20H::SENSITIVITY_00; sensitivity = l3gd20h::SENSITIVITY_00;
} else if (not fsH and fsL) { } else if (not fsH and fsL) {
sensitivity = L3GD20H::SENSITIVITY_01; sensitivity = l3gd20h::SENSITIVITY_01;
} else { } else {
sensitivity = L3GD20H::SENSITIVITY_11; sensitivity = l3gd20h::SENSITIVITY_11;
} }
commandBuffer[1] = ctrlReg1Value; commandBuffer[1] = ctrlReg1Value;
@ -124,8 +124,8 @@ ReturnValue_t GyroHandlerL3GD20H::buildCommandFromCommand(DeviceCommandId_t devi
rawPacketLen = 6; rawPacketLen = 6;
break; break;
} }
case (L3GD20H::READ_CTRL_REGS): { case (l3gd20h::READ_CTRL_REGS): {
commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK | L3GD20H::READ_MASK; commandBuffer[0] = l3gd20h::READ_START | l3gd20h::AUTO_INCREMENT_MASK | l3gd20h::READ_MASK;
std::memset(commandBuffer + 1, 0, 5); std::memset(commandBuffer + 1, 0, 5);
rawPacket = commandBuffer; rawPacket = commandBuffer;
@ -151,11 +151,11 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id,
const uint8_t *packet) { const uint8_t *packet) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
switch (id) { switch (id) {
case (L3GD20H::CONFIGURE_CTRL_REGS): { case (l3gd20h::CONFIGURE_CTRL_REGS): {
commandExecuted = true; commandExecuted = true;
break; break;
} }
case (L3GD20H::READ_CTRL_REGS): { case (l3gd20h::READ_CTRL_REGS): {
if (packet[1] == ctrlReg1Value and packet[2] == ctrlReg2Value and if (packet[1] == ctrlReg1Value and packet[2] == ctrlReg2Value and
packet[3] == ctrlReg3Value and packet[4] == ctrlReg4Value and packet[3] == ctrlReg3Value and packet[4] == ctrlReg4Value and
packet[5] == ctrlReg5Value) { packet[5] == ctrlReg5Value) {
@ -167,7 +167,7 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id,
} }
break; break;
} }
case (L3GD20H::READ_REGS): { case (l3gd20h::READ_REGS): {
if (packet[1] != ctrlReg1Value and packet[2] != ctrlReg2Value and if (packet[1] != ctrlReg1Value and packet[2] != ctrlReg2Value and
packet[3] != ctrlReg3Value and packet[4] != ctrlReg4Value and packet[3] != ctrlReg3Value and packet[4] != ctrlReg4Value and
packet[5] != ctrlReg5Value) { packet[5] != ctrlReg5Value) {
@ -178,16 +178,16 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id,
} }
} }
statusReg = packet[L3GD20H::STATUS_IDX]; statusReg = packet[l3gd20h::STATUS_IDX];
int16_t angVelocXRaw = packet[L3GD20H::OUT_X_H] << 8 | packet[L3GD20H::OUT_X_L]; int16_t angVelocXRaw = packet[l3gd20h::OUT_X_H] << 8 | packet[l3gd20h::OUT_X_L];
int16_t angVelocYRaw = packet[L3GD20H::OUT_Y_H] << 8 | packet[L3GD20H::OUT_Y_L]; int16_t angVelocYRaw = packet[l3gd20h::OUT_Y_H] << 8 | packet[l3gd20h::OUT_Y_L];
int16_t angVelocZRaw = packet[L3GD20H::OUT_Z_H] << 8 | packet[L3GD20H::OUT_Z_L]; int16_t angVelocZRaw = packet[l3gd20h::OUT_Z_H] << 8 | packet[l3gd20h::OUT_Z_L];
float angVelocX = angVelocXRaw * sensitivity; float angVelocX = angVelocXRaw * sensitivity;
float angVelocY = angVelocYRaw * sensitivity; float angVelocY = angVelocYRaw * sensitivity;
float angVelocZ = angVelocZRaw * sensitivity; float angVelocZ = angVelocZRaw * sensitivity;
int8_t temperaturOffset = (-1) * packet[L3GD20H::TEMPERATURE_IDX]; int8_t temperaturOffset = (-1) * packet[l3gd20h::TEMPERATURE_IDX];
float temperature = 25.0 + temperaturOffset; float temperature = 25.0 + temperaturOffset;
if (periodicPrintout) { if (periodicPrintout) {
if (debugDivider.checkAndIncrement()) { if (debugDivider.checkAndIncrement()) {
@ -248,19 +248,19 @@ void GyroHandlerL3GD20H::setToGoToNormalMode(bool enable) { this->goNormalModeIm
ReturnValue_t GyroHandlerL3GD20H::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, ReturnValue_t GyroHandlerL3GD20H::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) { LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_X, new PoolEntry<float>({0.0})); localDataPoolMap.emplace(l3gd20h::ANG_VELOC_X, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, new PoolEntry<float>({0.0})); localDataPoolMap.emplace(l3gd20h::ANG_VELOC_Y, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, new PoolEntry<float>({0.0})); localDataPoolMap.emplace(l3gd20h::ANG_VELOC_Z, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(L3GD20H::TEMPERATURE, new PoolEntry<float>({0.0})); localDataPoolMap.emplace(l3gd20h::TEMPERATURE, new PoolEntry<float>({0.0}));
poolManager.subscribeForRegularPeriodicPacket( poolManager.subscribeForRegularPeriodicPacket(
subdp::RegularHkPeriodicParams(dataset.getSid(), false, 10.0)); subdp::RegularHkPeriodicParams(dataset.getSid(), false, 10.0));
return returnvalue::OK; return returnvalue::OK;
} }
void GyroHandlerL3GD20H::fillCommandAndReplyMap() { void GyroHandlerL3GD20H::fillCommandAndReplyMap() {
insertInCommandAndReplyMap(L3GD20H::READ_REGS, 1, &dataset); insertInCommandAndReplyMap(l3gd20h::READ_REGS, 1, &dataset);
insertInCommandAndReplyMap(L3GD20H::CONFIGURE_CTRL_REGS, 1); insertInCommandAndReplyMap(l3gd20h::CONFIGURE_CTRL_REGS, 1);
insertInCommandAndReplyMap(L3GD20H::READ_CTRL_REGS, 1); insertInCommandAndReplyMap(l3gd20h::READ_CTRL_REGS, 1);
} }
void GyroHandlerL3GD20H::modeChanged() { internalState = InternalState::NONE; } void GyroHandlerL3GD20H::modeChanged() { internalState = InternalState::NONE; }

View File

@ -3,8 +3,7 @@
#include <fsfw/devicehandlers/DeviceHandlerBase.h> #include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include <fsfw/globalfunctions/PeriodicOperationDivider.h> #include <fsfw/globalfunctions/PeriodicOperationDivider.h>
#include <fsfw_hal/devicehandlers/devicedefinitions/gyroL3gHelpers.h>
#include "devicedefinitions/GyroL3GD20Definitions.h"
/** /**
* @brief Device Handler for the L3GD20H gyroscope sensor * @brief Device Handler for the L3GD20H gyroscope sensor
@ -59,9 +58,9 @@ class GyroHandlerL3GD20H : public DeviceHandlerBase {
uint32_t transitionDelayMs = 0; uint32_t transitionDelayMs = 0;
GyroPrimaryDataset dataset; GyroPrimaryDataset dataset;
float absLimitX = L3GD20H::RANGE_DPS_00; float absLimitX = l3gd20h::RANGE_DPS_00;
float absLimitY = L3GD20H::RANGE_DPS_00; float absLimitY = l3gd20h::RANGE_DPS_00;
float absLimitZ = L3GD20H::RANGE_DPS_00; float absLimitZ = l3gd20h::RANGE_DPS_00;
enum class InternalState { NONE, CONFIGURE, CHECK_REGS, NORMAL }; enum class InternalState { NONE, CONFIGURE, CHECK_REGS, NORMAL };
InternalState internalState = InternalState::NONE; InternalState internalState = InternalState::NONE;
@ -70,16 +69,16 @@ class GyroHandlerL3GD20H : public DeviceHandlerBase {
uint8_t statusReg = 0; uint8_t statusReg = 0;
bool goNormalModeImmediately = false; bool goNormalModeImmediately = false;
uint8_t ctrlReg1Value = L3GD20H::CTRL_REG_1_VAL; uint8_t ctrlReg1Value = l3gd20h::CTRL_REG_1_VAL;
uint8_t ctrlReg2Value = L3GD20H::CTRL_REG_2_VAL; uint8_t ctrlReg2Value = l3gd20h::CTRL_REG_2_VAL;
uint8_t ctrlReg3Value = L3GD20H::CTRL_REG_3_VAL; uint8_t ctrlReg3Value = l3gd20h::CTRL_REG_3_VAL;
uint8_t ctrlReg4Value = L3GD20H::CTRL_REG_4_VAL; uint8_t ctrlReg4Value = l3gd20h::CTRL_REG_4_VAL;
uint8_t ctrlReg5Value = L3GD20H::CTRL_REG_5_VAL; uint8_t ctrlReg5Value = l3gd20h::CTRL_REG_5_VAL;
uint8_t commandBuffer[L3GD20H::READ_LEN + 1]; uint8_t commandBuffer[l3gd20h::READ_LEN + 1];
// Set default value // Set default value
float sensitivity = L3GD20H::SENSITIVITY_00; float sensitivity = l3gd20h::SENSITIVITY_00;
bool periodicPrintout = false; bool periodicPrintout = false;
PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3); PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3);

View File

@ -10,11 +10,11 @@ MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCom
dataset(this), dataset(this),
transitionDelay(transitionDelay) { transitionDelay(transitionDelay) {
// Set to default values right away // Set to default values right away
registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; registers[0] = mgmLis3::CTRL_REG1_DEFAULT;
registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; registers[1] = mgmLis3::CTRL_REG2_DEFAULT;
registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; registers[2] = mgmLis3::CTRL_REG3_DEFAULT;
registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; registers[3] = mgmLis3::CTRL_REG4_DEFAULT;
registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; registers[4] = mgmLis3::CTRL_REG5_DEFAULT;
} }
MgmLIS3MDLHandler::~MgmLIS3MDLHandler() {} MgmLIS3MDLHandler::~MgmLIS3MDLHandler() {}
@ -63,15 +63,15 @@ ReturnValue_t MgmLIS3MDLHandler::buildTransitionDeviceCommand(DeviceCommandId_t
return DeviceHandlerBase::NOTHING_TO_SEND; return DeviceHandlerBase::NOTHING_TO_SEND;
} }
case (InternalState::STATE_FIRST_CONTACT): { case (InternalState::STATE_FIRST_CONTACT): {
*id = MGMLIS3MDL::IDENTIFY_DEVICE; *id = mgmLis3::IDENTIFY_DEVICE;
break; break;
} }
case (InternalState::STATE_SETUP): { case (InternalState::STATE_SETUP): {
*id = MGMLIS3MDL::SETUP_MGM; *id = mgmLis3::SETUP_MGM;
break; break;
} }
case (InternalState::STATE_CHECK_REGISTERS): { case (InternalState::STATE_CHECK_REGISTERS): {
*id = MGMLIS3MDL::READ_CONFIG_AND_DATA; *id = mgmLis3::READ_CONFIG_AND_DATA;
break; break;
} }
default: { default: {
@ -88,28 +88,12 @@ ReturnValue_t MgmLIS3MDLHandler::buildTransitionDeviceCommand(DeviceCommandId_t
return buildCommandFromCommand(*id, NULL, 0); return buildCommandFromCommand(*id, NULL, 0);
} }
uint8_t MgmLIS3MDLHandler::readCommand(uint8_t command, bool continuousCom) {
command |= (1 << MGMLIS3MDL::RW_BIT);
if (continuousCom == true) {
command |= (1 << MGMLIS3MDL::MS_BIT);
}
return command;
}
uint8_t MgmLIS3MDLHandler::writeCommand(uint8_t command, bool continuousCom) {
command &= ~(1 << MGMLIS3MDL::RW_BIT);
if (continuousCom == true) {
command |= (1 << MGMLIS3MDL::MS_BIT);
}
return command;
}
void MgmLIS3MDLHandler::setupMgm() { void MgmLIS3MDLHandler::setupMgm() {
registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; registers[0] = mgmLis3::CTRL_REG1_DEFAULT;
registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; registers[1] = mgmLis3::CTRL_REG2_DEFAULT;
registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; registers[2] = mgmLis3::CTRL_REG3_DEFAULT;
registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; registers[3] = mgmLis3::CTRL_REG4_DEFAULT;
registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; registers[4] = mgmLis3::CTRL_REG5_DEFAULT;
prepareCtrlRegisterWrite(); prepareCtrlRegisterWrite();
} }
@ -117,11 +101,11 @@ void MgmLIS3MDLHandler::setupMgm() {
ReturnValue_t MgmLIS3MDLHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) { ReturnValue_t MgmLIS3MDLHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) {
// Data/config register will be read in an alternating manner. // Data/config register will be read in an alternating manner.
if (communicationStep == CommunicationStep::DATA) { if (communicationStep == CommunicationStep::DATA) {
*id = MGMLIS3MDL::READ_CONFIG_AND_DATA; *id = mgmLis3::READ_CONFIG_AND_DATA;
communicationStep = CommunicationStep::TEMPERATURE; communicationStep = CommunicationStep::TEMPERATURE;
return buildCommandFromCommand(*id, NULL, 0); return buildCommandFromCommand(*id, NULL, 0);
} else { } else {
*id = MGMLIS3MDL::READ_TEMPERATURE; *id = mgmLis3::READ_TEMPERATURE;
communicationStep = CommunicationStep::DATA; communicationStep = CommunicationStep::DATA;
return buildCommandFromCommand(*id, NULL, 0); return buildCommandFromCommand(*id, NULL, 0);
} }
@ -131,33 +115,33 @@ ReturnValue_t MgmLIS3MDLHandler::buildCommandFromCommand(DeviceCommandId_t devic
const uint8_t *commandData, const uint8_t *commandData,
size_t commandDataLen) { size_t commandDataLen) {
switch (deviceCommand) { switch (deviceCommand) {
case (MGMLIS3MDL::READ_CONFIG_AND_DATA): { case (mgmLis3::READ_CONFIG_AND_DATA): {
std::memset(commandBuffer, 0, sizeof(commandBuffer)); std::memset(commandBuffer, 0, sizeof(commandBuffer));
commandBuffer[0] = readCommand(MGMLIS3MDL::CTRL_REG1, true); commandBuffer[0] = mgmLis3::readCommand(mgmLis3::CTRL_REG1, true);
rawPacket = commandBuffer; rawPacket = commandBuffer;
rawPacketLen = MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1; rawPacketLen = mgmLis3::NR_OF_DATA_AND_CFG_REGISTERS + 1;
return returnvalue::OK; return returnvalue::OK;
} }
case (MGMLIS3MDL::READ_TEMPERATURE): { case (mgmLis3::READ_TEMPERATURE): {
std::memset(commandBuffer, 0, 3); std::memset(commandBuffer, 0, 3);
commandBuffer[0] = readCommand(MGMLIS3MDL::TEMP_LOWBYTE, true); commandBuffer[0] = mgmLis3::readCommand(mgmLis3::TEMP_LOWBYTE, true);
rawPacket = commandBuffer; rawPacket = commandBuffer;
rawPacketLen = 3; rawPacketLen = 3;
return returnvalue::OK; return returnvalue::OK;
} }
case (MGMLIS3MDL::IDENTIFY_DEVICE): { case (mgmLis3::IDENTIFY_DEVICE): {
return identifyDevice(); return identifyDevice();
} }
case (MGMLIS3MDL::TEMP_SENSOR_ENABLE): { case (mgmLis3::TEMP_SENSOR_ENABLE): {
return enableTemperatureSensor(commandData, commandDataLen); return enableTemperatureSensor(commandData, commandDataLen);
} }
case (MGMLIS3MDL::SETUP_MGM): { case (mgmLis3::SETUP_MGM): {
setupMgm(); setupMgm();
return returnvalue::OK; return returnvalue::OK;
} }
case (MGMLIS3MDL::ACCURACY_OP_MODE_SET): { case (mgmLis3::ACCURACY_OP_MODE_SET): {
return setOperatingMode(commandData, commandDataLen); return setOperatingMode(commandData, commandDataLen);
} }
default: default:
@ -168,7 +152,7 @@ ReturnValue_t MgmLIS3MDLHandler::buildCommandFromCommand(DeviceCommandId_t devic
ReturnValue_t MgmLIS3MDLHandler::identifyDevice() { ReturnValue_t MgmLIS3MDLHandler::identifyDevice() {
uint32_t size = 2; uint32_t size = 2;
commandBuffer[0] = readCommand(MGMLIS3MDL::IDENTIFY_DEVICE_REG_ADDR); commandBuffer[0] = mgmLis3::readCommand(mgmLis3::IDENTIFY_DEVICE_REG_ADDR);
commandBuffer[1] = 0x00; commandBuffer[1] = 0x00;
rawPacket = commandBuffer; rawPacket = commandBuffer;
@ -180,9 +164,9 @@ ReturnValue_t MgmLIS3MDLHandler::identifyDevice() {
ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, size_t len, ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, size_t len,
DeviceCommandId_t *foundId, size_t *foundLen) { DeviceCommandId_t *foundId, size_t *foundLen) {
*foundLen = len; *foundLen = len;
if (len == MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1) { if (len == mgmLis3::NR_OF_DATA_AND_CFG_REGISTERS + 1) {
*foundLen = len; *foundLen = len;
*foundId = MGMLIS3MDL::READ_CONFIG_AND_DATA; *foundId = mgmLis3::READ_CONFIG_AND_DATA;
// Check validity by checking config registers // Check validity by checking config registers
if (start[1] != registers[0] or start[2] != registers[1] or start[3] != registers[2] or if (start[1] != registers[0] or start[2] != registers[1] or start[3] != registers[2] or
start[4] != registers[3] or start[5] != registers[4]) { start[4] != registers[3] or start[5] != registers[4]) {
@ -199,17 +183,17 @@ ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, size_t len,
commandExecuted = true; commandExecuted = true;
} }
} else if (len == MGMLIS3MDL::TEMPERATURE_REPLY_LEN) { } else if (len == mgmLis3::TEMPERATURE_REPLY_LEN) {
*foundLen = len; *foundLen = len;
*foundId = MGMLIS3MDL::READ_TEMPERATURE; *foundId = mgmLis3::READ_TEMPERATURE;
} else if (len == MGMLIS3MDL::SETUP_REPLY_LEN) { } else if (len == mgmLis3::SETUP_REPLY_LEN) {
*foundLen = len; *foundLen = len;
*foundId = MGMLIS3MDL::SETUP_MGM; *foundId = mgmLis3::SETUP_MGM;
} else if (len == SINGLE_COMMAND_ANSWER_LEN) { } else if (len == SINGLE_COMMAND_ANSWER_LEN) {
*foundLen = len; *foundLen = len;
*foundId = getPendingCommand(); *foundId = getPendingCommand();
if (*foundId == MGMLIS3MDL::IDENTIFY_DEVICE) { if (*foundId == mgmLis3::IDENTIFY_DEVICE) {
if (start[1] != MGMLIS3MDL::DEVICE_ID) { if (start[1] != mgmLis3::DEVICE_ID) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "MGMHandlerLIS3MDL::scanForReply: " sif::warning << "MGMHandlerLIS3MDL::scanForReply: "
@ -241,30 +225,31 @@ ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, size_t len,
} }
ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) {
switch (id) { switch (id) {
case MGMLIS3MDL::IDENTIFY_DEVICE: { case mgmLis3::IDENTIFY_DEVICE: {
break; break;
} }
case MGMLIS3MDL::SETUP_MGM: { case mgmLis3::SETUP_MGM: {
break; break;
} }
case MGMLIS3MDL::READ_CONFIG_AND_DATA: { case mgmLis3::READ_CONFIG_AND_DATA: {
using namespace mgmLis3;
// TODO: Store configuration in new local datasets. // TODO: Store configuration in new local datasets.
float sensitivityFactor = getSensitivityFactor(getSensitivity(registers[2])); float sensitivityFactor = getSensitivityFactor(getSensitivity(registers[2]));
int16_t mgmMeasurementRawX = int16_t mgmMeasurementRawX =
packet[MGMLIS3MDL::X_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::X_LOWBYTE_IDX]; packet[mgmLis3::X_HIGHBYTE_IDX] << 8 | packet[mgmLis3::X_LOWBYTE_IDX];
int16_t mgmMeasurementRawY = int16_t mgmMeasurementRawY =
packet[MGMLIS3MDL::Y_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Y_LOWBYTE_IDX]; packet[mgmLis3::Y_HIGHBYTE_IDX] << 8 | packet[mgmLis3::Y_LOWBYTE_IDX];
int16_t mgmMeasurementRawZ = int16_t mgmMeasurementRawZ =
packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Z_LOWBYTE_IDX]; packet[mgmLis3::Z_HIGHBYTE_IDX] << 8 | packet[mgmLis3::Z_LOWBYTE_IDX];
// Target value in microtesla // Target value in microtesla
float mgmX = static_cast<float>(mgmMeasurementRawX) * sensitivityFactor * float mgmX = static_cast<float>(mgmMeasurementRawX) * sensitivityFactor *
MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; mgmLis3::GAUSS_TO_MICROTESLA_FACTOR;
float mgmY = static_cast<float>(mgmMeasurementRawY) * sensitivityFactor * float mgmY = static_cast<float>(mgmMeasurementRawY) * sensitivityFactor *
MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; mgmLis3::GAUSS_TO_MICROTESLA_FACTOR;
float mgmZ = static_cast<float>(mgmMeasurementRawZ) * sensitivityFactor * float mgmZ = static_cast<float>(mgmMeasurementRawZ) * sensitivityFactor *
MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; mgmLis3::GAUSS_TO_MICROTESLA_FACTOR;
if (periodicPrintout) { if (periodicPrintout) {
if (debugDivider.checkAndIncrement()) { if (debugDivider.checkAndIncrement()) {
@ -306,7 +291,7 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
break; break;
} }
case MGMLIS3MDL::READ_TEMPERATURE: { case mgmLis3::READ_TEMPERATURE: {
int16_t tempValueRaw = packet[2] << 8 | packet[1]; int16_t tempValueRaw = packet[2] << 8 | packet[1];
float tempValue = 25.0 + ((static_cast<float>(tempValueRaw)) / 8.0); float tempValue = 25.0 + ((static_cast<float>(tempValueRaw)) / 8.0);
if (periodicPrintout) { if (periodicPrintout) {
@ -334,41 +319,6 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
return returnvalue::OK; return returnvalue::OK;
} }
MGMLIS3MDL::Sensitivies MgmLIS3MDLHandler::getSensitivity(uint8_t ctrlRegister2) {
bool fs0Set = ctrlRegister2 & (1 << MGMLIS3MDL::FSO); // Checks if FS0 bit is set
bool fs1Set = ctrlRegister2 & (1 << MGMLIS3MDL::FS1); // Checks if FS1 bit is set
if (fs0Set && fs1Set)
return MGMLIS3MDL::Sensitivies::GAUSS_16;
else if (!fs0Set && fs1Set)
return MGMLIS3MDL::Sensitivies::GAUSS_12;
else if (fs0Set && !fs1Set)
return MGMLIS3MDL::Sensitivies::GAUSS_8;
else
return MGMLIS3MDL::Sensitivies::GAUSS_4;
}
float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) {
switch (sens) {
case (MGMLIS3MDL::GAUSS_4): {
return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_4_SENS;
}
case (MGMLIS3MDL::GAUSS_8): {
return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_8_SENS;
}
case (MGMLIS3MDL::GAUSS_12): {
return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_12_SENS;
}
case (MGMLIS3MDL::GAUSS_16): {
return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_16_SENS;
}
default: {
// Should never happen
return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_4_SENS;
}
}
}
ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor(const uint8_t *commandData, ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor(const uint8_t *commandData,
size_t commandDataLen) { size_t commandDataLen) {
if (commandData == nullptr) { if (commandData == nullptr) {
@ -376,16 +326,16 @@ ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor(const uint8_t *commandD
} }
triggerEvent(CHANGE_OF_SETUP_PARAMETER); triggerEvent(CHANGE_OF_SETUP_PARAMETER);
uint32_t size = 2; uint32_t size = 2;
commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1); commandBuffer[0] = mgmLis3::writeCommand(mgmLis3::CTRL_REG1);
if (commandDataLen > 1) { if (commandDataLen > 1) {
return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS;
} }
switch (commandData[0]) { switch (commandData[0]) {
case (MGMLIS3MDL::ON): { case (mgmLis3::ON): {
commandBuffer[1] = registers[0] | (1 << 7); commandBuffer[1] = registers[0] | (1 << 7);
break; break;
} }
case (MGMLIS3MDL::OFF): { case (mgmLis3::OFF): {
commandBuffer[1] = registers[0] & ~(1 << 7); commandBuffer[1] = registers[0] & ~(1 << 7);
break; break;
} }
@ -408,23 +358,23 @@ ReturnValue_t MgmLIS3MDLHandler::setOperatingMode(const uint8_t *commandData,
} }
switch (commandData[0]) { switch (commandData[0]) {
case MGMLIS3MDL::LOW: case mgmLis3::LOW:
registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) & (~(1 << MGMLIS3MDL::OM0)); registers[0] = (registers[0] & (~(1 << mgmLis3::OM1))) & (~(1 << mgmLis3::OM0));
registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) & (~(1 << MGMLIS3MDL::OMZ0)); registers[3] = (registers[3] & (~(1 << mgmLis3::OMZ1))) & (~(1 << mgmLis3::OMZ0));
break; break;
case MGMLIS3MDL::MEDIUM: case mgmLis3::MEDIUM:
registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) | (1 << MGMLIS3MDL::OM0); registers[0] = (registers[0] & (~(1 << mgmLis3::OM1))) | (1 << mgmLis3::OM0);
registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) | (1 << MGMLIS3MDL::OMZ0); registers[3] = (registers[3] & (~(1 << mgmLis3::OMZ1))) | (1 << mgmLis3::OMZ0);
break; break;
case MGMLIS3MDL::HIGH: case mgmLis3::HIGH:
registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) & (~(1 << MGMLIS3MDL::OM0)); registers[0] = (registers[0] | (1 << mgmLis3::OM1)) & (~(1 << mgmLis3::OM0));
registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) & (~(1 << MGMLIS3MDL::OMZ0)); registers[3] = (registers[3] | (1 << mgmLis3::OMZ1)) & (~(1 << mgmLis3::OMZ0));
break; break;
case MGMLIS3MDL::ULTRA: case mgmLis3::ULTRA:
registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) | (1 << MGMLIS3MDL::OM0); registers[0] = (registers[0] | (1 << mgmLis3::OM1)) | (1 << mgmLis3::OM0);
registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) | (1 << MGMLIS3MDL::OMZ0); registers[3] = (registers[3] | (1 << mgmLis3::OMZ1)) | (1 << mgmLis3::OMZ0);
break; break;
default: default:
break; break;
@ -434,24 +384,24 @@ ReturnValue_t MgmLIS3MDLHandler::setOperatingMode(const uint8_t *commandData,
} }
void MgmLIS3MDLHandler::fillCommandAndReplyMap() { void MgmLIS3MDLHandler::fillCommandAndReplyMap() {
insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1, &dataset); insertInCommandAndReplyMap(mgmLis3::READ_CONFIG_AND_DATA, 1, &dataset);
insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); insertInCommandAndReplyMap(mgmLis3::READ_TEMPERATURE, 1);
insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); insertInCommandAndReplyMap(mgmLis3::SETUP_MGM, 1);
insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); insertInCommandAndReplyMap(mgmLis3::IDENTIFY_DEVICE, 1);
insertInCommandAndReplyMap(MGMLIS3MDL::TEMP_SENSOR_ENABLE, 1); insertInCommandAndReplyMap(mgmLis3::TEMP_SENSOR_ENABLE, 1);
insertInCommandAndReplyMap(MGMLIS3MDL::ACCURACY_OP_MODE_SET, 1); insertInCommandAndReplyMap(mgmLis3::ACCURACY_OP_MODE_SET, 1);
} }
void MgmLIS3MDLHandler::setToGoToNormalMode(bool enable) { this->goToNormalMode = enable; } void MgmLIS3MDLHandler::setToGoToNormalMode(bool enable) { this->goToNormalMode = enable; }
ReturnValue_t MgmLIS3MDLHandler::prepareCtrlRegisterWrite() { ReturnValue_t MgmLIS3MDLHandler::prepareCtrlRegisterWrite() {
commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true); commandBuffer[0] = mgmLis3::writeCommand(mgmLis3::CTRL_REG1, true);
for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { for (size_t i = 0; i < mgmLis3::NR_OF_CTRL_REGISTERS; i++) {
commandBuffer[i + 1] = registers[i]; commandBuffer[i + 1] = registers[i];
} }
rawPacket = commandBuffer; rawPacket = commandBuffer;
rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; rawPacketLen = mgmLis3::NR_OF_CTRL_REGISTERS + 1;
// We dont have to check if this is working because we just did i // We dont have to check if this is working because we just did i
return returnvalue::OK; return returnvalue::OK;
@ -467,8 +417,8 @@ void MgmLIS3MDLHandler::modeChanged(void) { internalState = InternalState::STATE
ReturnValue_t MgmLIS3MDLHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, ReturnValue_t MgmLIS3MDLHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) { LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTHS, &mgmXYZ); localDataPoolMap.emplace(mgmLis3::FIELD_STRENGTHS, &mgmXYZ);
localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, &temperature); localDataPoolMap.emplace(mgmLis3::TEMPERATURE_CELCIUS, &temperature);
poolManager.subscribeForRegularPeriodicPacket({dataset.getSid(), false, 10.0}); poolManager.subscribeForRegularPeriodicPacket({dataset.getSid(), false, 10.0});
return returnvalue::OK; return returnvalue::OK;
} }

View File

@ -1,7 +1,8 @@
#ifndef MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ #ifndef MISSION_DEVICES_MGMLIS3MDLHANDLER_H_
#define MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ #define MISSION_DEVICES_MGMLIS3MDLHANDLER_H_
#include "devicedefinitions/MgmLIS3HandlerDefs.h" #include <fsfw_hal/devicehandlers/devicedefinitions/mgmLis3Helpers.h>
#include "fsfw/devicehandlers/DeviceHandlerBase.h" #include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "fsfw/globalfunctions/PeriodicOperationDivider.h" #include "fsfw/globalfunctions/PeriodicOperationDivider.h"
@ -66,7 +67,7 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase {
LocalDataPoolManager &poolManager) override; LocalDataPoolManager &poolManager) override;
private: private:
MGMLIS3MDL::MgmPrimaryDataset dataset; mgmLis3::MgmPrimaryDataset dataset;
// Length a single command SPI answer // Length a single command SPI answer
static const uint8_t SINGLE_COMMAND_ANSWER_LEN = 2; static const uint8_t SINGLE_COMMAND_ANSWER_LEN = 2;
@ -74,7 +75,7 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase {
// Single SPI command has 2 bytes, first for adress, second for content // Single SPI command has 2 bytes, first for adress, second for content
size_t singleComandSize = 2; size_t singleComandSize = 2;
// Has the size for all adresses of the lis3mdl + the continous write bit // Has the size for all adresses of the lis3mdl + the continous write bit
uint8_t commandBuffer[MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1]; uint8_t commandBuffer[mgmLis3::NR_OF_DATA_AND_CFG_REGISTERS + 1];
float absLimitX = 100; float absLimitX = 100;
float absLimitY = 100; float absLimitY = 100;
@ -85,7 +86,7 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase {
* registers when we want to change something. * registers when we want to change something.
* --> everytime we change set a register we have to save it * --> everytime we change set a register we have to save it
*/ */
uint8_t registers[MGMLIS3MDL::NR_OF_CTRL_REGISTERS]; uint8_t registers[mgmLis3::NR_OF_CTRL_REGISTERS];
uint8_t statusRegister = 0; uint8_t statusRegister = 0;
bool goToNormalMode = false; bool goToNormalMode = false;
@ -107,35 +108,6 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase {
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Device specific commands and variables */ /* Device specific commands and variables */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/**
* Sets the read bit for the command
* @param single command to set the read-bit at
* @param boolean to select a continuous read bit, default = false
*/
uint8_t readCommand(uint8_t command, bool continuousCom = false);
/**
* Sets the write bit for the command
* @param single command to set the write-bit at
* @param boolean to select a continuous write bit, default = false
*/
uint8_t writeCommand(uint8_t command, bool continuousCom = false);
/**
* This Method gets the full scale for the measurement range
* e.g.: +- 4 gauss. See p.25 datasheet.
* @return The ReturnValue does not contain the sign of the value
*/
MGMLIS3MDL::Sensitivies getSensitivity(uint8_t ctrlReg2);
/**
* The 16 bit value needs to be multiplied with a sensitivity factor
* which depends on the sensitivity configuration
*
* @param sens Configured sensitivity of the LIS3 device
* @return Multiplication factor to get the sensor value from raw data.
*/
float getSensitivityFactor(MGMLIS3MDL::Sensitivies sens);
/** /**
* This Command detects the device ID * This Command detects the device ID

View File

@ -63,21 +63,21 @@ ReturnValue_t MgmRM3100Handler::buildTransitionDeviceCommand(DeviceCommandId_t *
return NOTHING_TO_SEND; return NOTHING_TO_SEND;
} }
case (InternalState::CONFIGURE_CMM): { case (InternalState::CONFIGURE_CMM): {
*id = RM3100::CONFIGURE_CMM; *id = mgmRm3100::CONFIGURE_CMM;
break; break;
} }
case (InternalState::READ_CMM): { case (InternalState::READ_CMM): {
*id = RM3100::READ_CMM; *id = mgmRm3100::READ_CMM;
break; break;
} }
case (InternalState::STATE_CONFIGURE_TMRC): { case (InternalState::STATE_CONFIGURE_TMRC): {
commandBuffer[0] = RM3100::TMRC_DEFAULT_VALUE; commandBuffer[0] = mgmRm3100::TMRC_DEFAULT_VALUE;
commandLen = 1; commandLen = 1;
*id = RM3100::CONFIGURE_TMRC; *id = mgmRm3100::CONFIGURE_TMRC;
break; break;
} }
case (InternalState::STATE_READ_TMRC): { case (InternalState::STATE_READ_TMRC): {
*id = RM3100::READ_TMRC; *id = mgmRm3100::READ_TMRC;
break; break;
} }
default: default:
@ -103,42 +103,42 @@ ReturnValue_t MgmRM3100Handler::buildCommandFromCommand(DeviceCommandId_t device
const uint8_t *commandData, const uint8_t *commandData,
size_t commandDataLen) { size_t commandDataLen) {
switch (deviceCommand) { switch (deviceCommand) {
case (RM3100::CONFIGURE_CMM): { case (mgmRm3100::CONFIGURE_CMM): {
commandBuffer[0] = RM3100::CMM_REGISTER; commandBuffer[0] = mgmRm3100::CMM_REGISTER;
commandBuffer[1] = RM3100::CMM_VALUE; commandBuffer[1] = mgmRm3100::CMM_VALUE;
rawPacket = commandBuffer; rawPacket = commandBuffer;
rawPacketLen = 2; rawPacketLen = 2;
break; break;
} }
case (RM3100::READ_CMM): { case (mgmRm3100::READ_CMM): {
commandBuffer[0] = RM3100::CMM_REGISTER | RM3100::READ_MASK; commandBuffer[0] = mgmRm3100::CMM_REGISTER | mgmRm3100::READ_MASK;
commandBuffer[1] = 0; commandBuffer[1] = 0;
rawPacket = commandBuffer; rawPacket = commandBuffer;
rawPacketLen = 2; rawPacketLen = 2;
break; break;
} }
case (RM3100::CONFIGURE_TMRC): { case (mgmRm3100::CONFIGURE_TMRC): {
return handleTmrcConfigCommand(deviceCommand, commandData, commandDataLen); return handleTmrcConfigCommand(deviceCommand, commandData, commandDataLen);
} }
case (RM3100::READ_TMRC): { case (mgmRm3100::READ_TMRC): {
commandBuffer[0] = RM3100::TMRC_REGISTER | RM3100::READ_MASK; commandBuffer[0] = mgmRm3100::TMRC_REGISTER | mgmRm3100::READ_MASK;
commandBuffer[1] = 0; commandBuffer[1] = 0;
rawPacket = commandBuffer; rawPacket = commandBuffer;
rawPacketLen = 2; rawPacketLen = 2;
break; break;
} }
case (RM3100::CONFIGURE_CYCLE_COUNT): { case (mgmRm3100::CONFIGURE_CYCLE_COUNT): {
return handleCycleCountConfigCommand(deviceCommand, commandData, commandDataLen); return handleCycleCountConfigCommand(deviceCommand, commandData, commandDataLen);
} }
case (RM3100::READ_CYCLE_COUNT): { case (mgmRm3100::READ_CYCLE_COUNT): {
commandBuffer[0] = RM3100::CYCLE_COUNT_START_REGISTER | RM3100::READ_MASK; commandBuffer[0] = mgmRm3100::CYCLE_COUNT_START_REGISTER | mgmRm3100::READ_MASK;
std::memset(commandBuffer + 1, 0, 6); std::memset(commandBuffer + 1, 0, 6);
rawPacket = commandBuffer; rawPacket = commandBuffer;
rawPacketLen = 7; rawPacketLen = 7;
break; break;
} }
case (RM3100::READ_DATA): { case (mgmRm3100::READ_DATA): {
commandBuffer[0] = RM3100::MEASUREMENT_REG_START | RM3100::READ_MASK; commandBuffer[0] = mgmRm3100::MEASUREMENT_REG_START | mgmRm3100::READ_MASK;
std::memset(commandBuffer + 1, 0, 9); std::memset(commandBuffer + 1, 0, 9);
rawPacketLen = 10; rawPacketLen = 10;
break; break;
@ -150,7 +150,7 @@ ReturnValue_t MgmRM3100Handler::buildCommandFromCommand(DeviceCommandId_t device
} }
ReturnValue_t MgmRM3100Handler::buildNormalDeviceCommand(DeviceCommandId_t *id) { ReturnValue_t MgmRM3100Handler::buildNormalDeviceCommand(DeviceCommandId_t *id) {
*id = RM3100::READ_DATA; *id = mgmRm3100::READ_DATA;
return buildCommandFromCommand(*id, nullptr, 0); return buildCommandFromCommand(*id, nullptr, 0);
} }
@ -165,16 +165,16 @@ ReturnValue_t MgmRM3100Handler::scanForReply(const uint8_t *start, size_t len,
ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
switch (id) { switch (id) {
case (RM3100::CONFIGURE_CMM): case (mgmRm3100::CONFIGURE_CMM):
case (RM3100::CONFIGURE_CYCLE_COUNT): case (mgmRm3100::CONFIGURE_CYCLE_COUNT):
case (RM3100::CONFIGURE_TMRC): { case (mgmRm3100::CONFIGURE_TMRC): {
// We can only check whether write was successful with read operation // We can only check whether write was successful with read operation
if (getMode() == _MODE_START_UP) { if (getMode() == _MODE_START_UP) {
commandExecuted = true; commandExecuted = true;
} }
break; break;
} }
case (RM3100::READ_CMM): { case (mgmRm3100::READ_CMM): {
uint8_t cmmValue = packet[1]; uint8_t cmmValue = packet[1];
// We clear the seventh bit in any case // We clear the seventh bit in any case
// because this one is zero sometimes for some reason // because this one is zero sometimes for some reason
@ -188,7 +188,7 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const
} }
break; break;
} }
case (RM3100::READ_TMRC): { case (mgmRm3100::READ_TMRC): {
if (packet[1] == tmrcRegValue) { if (packet[1] == tmrcRegValue) {
commandExecuted = true; commandExecuted = true;
// Reading TMRC was commanded. Trigger event to inform ground // Reading TMRC was commanded. Trigger event to inform ground
@ -202,7 +202,7 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const
} }
break; break;
} }
case (RM3100::READ_CYCLE_COUNT): { case (mgmRm3100::READ_CYCLE_COUNT): {
uint16_t cycleCountX = packet[1] << 8 | packet[2]; uint16_t cycleCountX = packet[1] << 8 | packet[2];
uint16_t cycleCountY = packet[3] << 8 | packet[4]; uint16_t cycleCountY = packet[3] << 8 | packet[4];
uint16_t cycleCountZ = packet[5] << 8 | packet[6]; uint16_t cycleCountZ = packet[5] << 8 | packet[6];
@ -217,7 +217,7 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const
} }
break; break;
} }
case (RM3100::READ_DATA): { case (mgmRm3100::READ_DATA): {
result = handleDataReadout(packet); result = handleDataReadout(packet);
break; break;
} }
@ -244,7 +244,7 @@ ReturnValue_t MgmRM3100Handler::handleCycleCountConfigCommand(DeviceCommandId_t
return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; return DeviceHandlerIF::INVALID_COMMAND_PARAMETER;
} }
commandBuffer[0] = RM3100::CYCLE_COUNT_VALUE; commandBuffer[0] = mgmRm3100::CYCLE_COUNT_VALUE;
std::memcpy(commandBuffer + 1, &cycleCountRegValueX, 2); std::memcpy(commandBuffer + 1, &cycleCountRegValueX, 2);
std::memcpy(commandBuffer + 3, &cycleCountRegValueY, 2); std::memcpy(commandBuffer + 3, &cycleCountRegValueY, 2);
std::memcpy(commandBuffer + 5, &cycleCountRegValueZ, 2); std::memcpy(commandBuffer + 5, &cycleCountRegValueZ, 2);
@ -255,7 +255,7 @@ ReturnValue_t MgmRM3100Handler::handleCycleCountConfigCommand(DeviceCommandId_t
ReturnValue_t MgmRM3100Handler::handleCycleCommand(bool oneCycleValue, const uint8_t *commandData, ReturnValue_t MgmRM3100Handler::handleCycleCommand(bool oneCycleValue, const uint8_t *commandData,
size_t commandDataLen) { size_t commandDataLen) {
RM3100::CycleCountCommand command(oneCycleValue); mgmRm3100::CycleCountCommand command(oneCycleValue);
ReturnValue_t result = ReturnValue_t result =
command.deSerialize(&commandData, &commandDataLen, SerializeIF::Endianness::BIG); command.deSerialize(&commandData, &commandDataLen, SerializeIF::Endianness::BIG);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
@ -284,7 +284,7 @@ ReturnValue_t MgmRM3100Handler::handleTmrcConfigCommand(DeviceCommandId_t device
return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; return DeviceHandlerIF::INVALID_COMMAND_PARAMETER;
} }
commandBuffer[0] = RM3100::TMRC_REGISTER; commandBuffer[0] = mgmRm3100::TMRC_REGISTER;
commandBuffer[1] = commandData[0]; commandBuffer[1] = commandData[0];
tmrcRegValue = commandData[0]; tmrcRegValue = commandData[0];
rawPacketLen = 2; rawPacketLen = 2;
@ -293,23 +293,23 @@ ReturnValue_t MgmRM3100Handler::handleTmrcConfigCommand(DeviceCommandId_t device
} }
void MgmRM3100Handler::fillCommandAndReplyMap() { void MgmRM3100Handler::fillCommandAndReplyMap() {
insertInCommandAndReplyMap(RM3100::CONFIGURE_CMM, 3); insertInCommandAndReplyMap(mgmRm3100::CONFIGURE_CMM, 3);
insertInCommandAndReplyMap(RM3100::READ_CMM, 3); insertInCommandAndReplyMap(mgmRm3100::READ_CMM, 3);
insertInCommandAndReplyMap(RM3100::CONFIGURE_TMRC, 3); insertInCommandAndReplyMap(mgmRm3100::CONFIGURE_TMRC, 3);
insertInCommandAndReplyMap(RM3100::READ_TMRC, 3); insertInCommandAndReplyMap(mgmRm3100::READ_TMRC, 3);
insertInCommandAndReplyMap(RM3100::CONFIGURE_CYCLE_COUNT, 3); insertInCommandAndReplyMap(mgmRm3100::CONFIGURE_CYCLE_COUNT, 3);
insertInCommandAndReplyMap(RM3100::READ_CYCLE_COUNT, 3); insertInCommandAndReplyMap(mgmRm3100::READ_CYCLE_COUNT, 3);
insertInCommandAndReplyMap(RM3100::READ_DATA, 3, &primaryDataset); insertInCommandAndReplyMap(mgmRm3100::READ_DATA, 3, &primaryDataset);
} }
void MgmRM3100Handler::modeChanged() { internalState = InternalState::NONE; } void MgmRM3100Handler::modeChanged() { internalState = InternalState::NONE; }
ReturnValue_t MgmRM3100Handler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, ReturnValue_t MgmRM3100Handler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) { LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(RM3100::FIELD_STRENGTHS, &mgmXYZ); localDataPoolMap.emplace(mgmRm3100::FIELD_STRENGTHS, &mgmXYZ);
poolManager.subscribeForRegularPeriodicPacket({primaryDataset.getSid(), false, 10.0}); poolManager.subscribeForRegularPeriodicPacket({primaryDataset.getSid(), false, 10.0});
return returnvalue::OK; return returnvalue::OK;
} }

View File

@ -1,7 +1,8 @@
#ifndef MISSION_DEVICES_MGMRM3100HANDLER_H_ #ifndef MISSION_DEVICES_MGMRM3100HANDLER_H_
#define MISSION_DEVICES_MGMRM3100HANDLER_H_ #define MISSION_DEVICES_MGMRM3100HANDLER_H_
#include "devicedefinitions/MgmRM3100HandlerDefs.h" #include <fsfw_hal/devicehandlers/devicedefinitions/mgmRm3100Helpers.h>
#include "fsfw/devicehandlers/DeviceHandlerBase.h" #include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "fsfw/globalfunctions/PeriodicOperationDivider.h" #include "fsfw/globalfunctions/PeriodicOperationDivider.h"
@ -69,19 +70,19 @@ class MgmRM3100Handler : public DeviceHandlerBase {
}; };
InternalState internalState = InternalState::NONE; InternalState internalState = InternalState::NONE;
bool commandExecuted = false; bool commandExecuted = false;
RM3100::Rm3100PrimaryDataset primaryDataset; mgmRm3100::Rm3100PrimaryDataset primaryDataset;
uint8_t commandBuffer[10]; uint8_t commandBuffer[10];
uint8_t commandBufferLen = 0; uint8_t commandBufferLen = 0;
uint8_t cmmRegValue = RM3100::CMM_VALUE; uint8_t cmmRegValue = mgmRm3100::CMM_VALUE;
uint8_t tmrcRegValue = RM3100::TMRC_DEFAULT_VALUE; uint8_t tmrcRegValue = mgmRm3100::TMRC_DEFAULT_VALUE;
uint16_t cycleCountRegValueX = RM3100::CYCLE_COUNT_VALUE; uint16_t cycleCountRegValueX = mgmRm3100::CYCLE_COUNT_VALUE;
uint16_t cycleCountRegValueY = RM3100::CYCLE_COUNT_VALUE; uint16_t cycleCountRegValueY = mgmRm3100::CYCLE_COUNT_VALUE;
uint16_t cycleCountRegValueZ = RM3100::CYCLE_COUNT_VALUE; uint16_t cycleCountRegValueZ = mgmRm3100::CYCLE_COUNT_VALUE;
float scaleFactorX = 1.0 / RM3100::DEFAULT_GAIN; float scaleFactorX = 1.0 / mgmRm3100::DEFAULT_GAIN;
float scaleFactorY = 1.0 / RM3100::DEFAULT_GAIN; float scaleFactorY = 1.0 / mgmRm3100::DEFAULT_GAIN;
float scaleFactorZ = 1.0 / RM3100::DEFAULT_GAIN; float scaleFactorZ = 1.0 / mgmRm3100::DEFAULT_GAIN;
bool goToNormalModeAtStartup = false; bool goToNormalModeAtStartup = false;
uint32_t transitionDelay; uint32_t transitionDelay;

View File

@ -0,0 +1 @@
target_sources(${LIB_FSFW_NAME} PRIVATE gyroL3gHelpers.cpp mgmLis3Helpers.cpp)

View File

@ -0,0 +1,14 @@
#include <fsfw_hal/devicehandlers/devicedefinitions/gyroL3gHelpers.h>
float l3gd20h::ctrlReg4ToSensitivity(uint8_t reg) {
bool fsH = reg & l3gd20h::SET_FS_1;
bool fsL = reg & l3gd20h::SET_FS_0;
if (not fsH and not fsL) {
return l3gd20h::SENSITIVITY_00;
} else if (not fsH and fsL) {
return l3gd20h::SENSITIVITY_01;
} else {
return l3gd20h::SENSITIVITY_11;
}
}

View File

@ -6,7 +6,9 @@
#include <cstdint> #include <cstdint>
namespace L3GD20H { namespace l3gd20h {
float ctrlReg4ToSensitivity(uint8_t reg);
/* Actual size is 15 but we round up a bit */ /* Actual size is 15 but we round up a bit */
static constexpr size_t MAX_BUFFER_SIZE = 16; static constexpr size_t MAX_BUFFER_SIZE = 16;
@ -103,31 +105,33 @@ static constexpr DeviceCommandId_t READ_REGS = 0;
static constexpr DeviceCommandId_t CONFIGURE_CTRL_REGS = 1; static constexpr DeviceCommandId_t CONFIGURE_CTRL_REGS = 1;
static constexpr DeviceCommandId_t READ_CTRL_REGS = 2; static constexpr DeviceCommandId_t READ_CTRL_REGS = 2;
static constexpr DeviceCommandId_t REQUEST = 0x70;
static constexpr DeviceCommandId_t REPLY = 0x77;
static constexpr uint32_t GYRO_DATASET_ID = READ_REGS; static constexpr uint32_t GYRO_DATASET_ID = READ_REGS;
enum GyroPoolIds : lp_id_t { ANG_VELOC_X, ANG_VELOC_Y, ANG_VELOC_Z, TEMPERATURE }; enum GyroPoolIds : lp_id_t { ANG_VELOC_X, ANG_VELOC_Y, ANG_VELOC_Z, TEMPERATURE };
} // namespace L3GD20H } // namespace l3gd20h
class GyroPrimaryDataset : public StaticLocalDataSet<5> { class GyroPrimaryDataset : public StaticLocalDataSet<5> {
public: public:
/** Constructor for data users like controllers */ /** Constructor for data users like controllers */
GyroPrimaryDataset(object_id_t mgmId) GyroPrimaryDataset(object_id_t mgmId)
: StaticLocalDataSet(sid_t(mgmId, L3GD20H::GYRO_DATASET_ID)) { : StaticLocalDataSet(sid_t(mgmId, l3gd20h::GYRO_DATASET_ID)) {
setAllVariablesReadOnly(); setAllVariablesReadOnly();
} }
/* Angular velocities in degrees per second (DPS) */
lp_var_t<float> angVelocX = lp_var_t<float>(sid.objectId, L3GD20H::ANG_VELOC_X, this);
lp_var_t<float> angVelocY = lp_var_t<float>(sid.objectId, L3GD20H::ANG_VELOC_Y, this);
lp_var_t<float> angVelocZ = lp_var_t<float>(sid.objectId, L3GD20H::ANG_VELOC_Z, this);
lp_var_t<float> temperature = lp_var_t<float>(sid.objectId, L3GD20H::TEMPERATURE, this);
private:
friend class GyroHandlerL3GD20H;
/** Constructor for the data creator */ /** Constructor for the data creator */
GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner) GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner)
: StaticLocalDataSet(hkOwner, L3GD20H::GYRO_DATASET_ID) {} : StaticLocalDataSet(hkOwner, l3gd20h::GYRO_DATASET_ID) {}
/* Angular velocities in degrees per second (DPS) */
lp_var_t<float> angVelocX = lp_var_t<float>(sid.objectId, l3gd20h::ANG_VELOC_X, this);
lp_var_t<float> angVelocY = lp_var_t<float>(sid.objectId, l3gd20h::ANG_VELOC_Y, this);
lp_var_t<float> angVelocZ = lp_var_t<float>(sid.objectId, l3gd20h::ANG_VELOC_Z, this);
lp_var_t<float> temperature = lp_var_t<float>(sid.objectId, l3gd20h::TEMPERATURE, this);
private:
}; };
#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ */ #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ */

View File

@ -0,0 +1,52 @@
#include "mgmLis3Helpers.h"
uint8_t mgmLis3::readCommand(uint8_t command, bool continuousCom) {
command |= (1 << mgmLis3::RW_BIT);
if (continuousCom == true) {
command |= (1 << mgmLis3::MS_BIT);
}
return command;
}
uint8_t mgmLis3::writeCommand(uint8_t command, bool continuousCom) {
command &= ~(1 << mgmLis3::RW_BIT);
if (continuousCom == true) {
command |= (1 << mgmLis3::MS_BIT);
}
return command;
}
mgmLis3::Sensitivies mgmLis3::getSensitivity(uint8_t ctrlRegister2) {
bool fs0Set = ctrlRegister2 & (1 << mgmLis3::FSO); // Checks if FS0 bit is set
bool fs1Set = ctrlRegister2 & (1 << mgmLis3::FS1); // Checks if FS1 bit is set
if (fs0Set && fs1Set)
return mgmLis3::Sensitivies::GAUSS_16;
else if (!fs0Set && fs1Set)
return mgmLis3::Sensitivies::GAUSS_12;
else if (fs0Set && !fs1Set)
return mgmLis3::Sensitivies::GAUSS_8;
else
return mgmLis3::Sensitivies::GAUSS_4;
}
float mgmLis3::getSensitivityFactor(mgmLis3::Sensitivies sens) {
switch (sens) {
case (mgmLis3::GAUSS_4): {
return mgmLis3::FIELD_LSB_PER_GAUSS_4_SENS;
}
case (mgmLis3::GAUSS_8): {
return mgmLis3::FIELD_LSB_PER_GAUSS_8_SENS;
}
case (mgmLis3::GAUSS_12): {
return mgmLis3::FIELD_LSB_PER_GAUSS_12_SENS;
}
case (mgmLis3::GAUSS_16): {
return mgmLis3::FIELD_LSB_PER_GAUSS_16_SENS;
}
default: {
// Should never happen
return mgmLis3::FIELD_LSB_PER_GAUSS_4_SENS;
}
}
}

View File

@ -7,13 +7,43 @@
#include <cstdint> #include <cstdint>
namespace MGMLIS3MDL { namespace mgmLis3 {
enum Set { ON, OFF }; enum Set { ON, OFF };
enum OpMode { LOW, MEDIUM, HIGH, ULTRA }; enum OpMode { LOW, MEDIUM, HIGH, ULTRA };
enum Sensitivies : uint8_t { GAUSS_4 = 4, GAUSS_8 = 8, GAUSS_12 = 12, GAUSS_16 = 16 }; enum Sensitivies : uint8_t { GAUSS_4 = 4, GAUSS_8 = 8, GAUSS_12 = 12, GAUSS_16 = 16 };
/**
* Sets the read bit for the command
* @param single command to set the read-bit at
* @param boolean to select a continuous read bit, default = false
*/
uint8_t readCommand(uint8_t command, bool continuousCom = false);
/**
* Sets the write bit for the command
* @param single command to set the write-bit at
* @param boolean to select a continuous write bit, default = false
*/
uint8_t writeCommand(uint8_t command, bool continuousCom = false);
/**
* This Method gets the full scale for the measurement range
* e.g.: +- 4 gauss. See p.25 datasheet.
* @return The ReturnValue does not contain the sign of the value
*/
mgmLis3::Sensitivies getSensitivity(uint8_t ctrlReg2);
/**
* The 16 bit value needs to be multiplied with a sensitivity factor
* which depends on the sensitivity configuration
*
* @param sens Configured sensitivity of the LIS3 device
* @return Multiplication factor to get the sensor value from raw data.
*/
float getSensitivityFactor(mgmLis3::Sensitivies sens);
/* Actually 15, we just round up a bit */ /* Actually 15, we just round up a bit */
static constexpr size_t MAX_BUFFER_SIZE = 16; static constexpr size_t MAX_BUFFER_SIZE = 16;
@ -154,6 +184,6 @@ class MgmPrimaryDataset : public StaticLocalDataSet<4> {
lp_var_t<float> temperature = lp_var_t<float>(sid.objectId, TEMPERATURE_CELCIUS, this); lp_var_t<float> temperature = lp_var_t<float>(sid.objectId, TEMPERATURE_CELCIUS, this);
}; };
} // namespace MGMLIS3MDL } // namespace mgmLis3
#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMLIS3HANDLERDEFS_H_ */ #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMLIS3HANDLERDEFS_H_ */

View File

@ -8,7 +8,7 @@
#include <cstdint> #include <cstdint>
namespace RM3100 { namespace mgmRm3100 {
/* Actually 10, we round up a little bit */ /* Actually 10, we round up a little bit */
static constexpr size_t MAX_BUFFER_SIZE = 12; static constexpr size_t MAX_BUFFER_SIZE = 12;
@ -115,6 +115,6 @@ class Rm3100PrimaryDataset : public StaticLocalDataSet<3> {
lp_vec_t<float, 3> fieldStrengths = lp_vec_t<float, 3>(sid.objectId, FIELD_STRENGTHS, this); lp_vec_t<float, 3> fieldStrengths = lp_vec_t<float, 3>(sid.objectId, FIELD_STRENGTHS, this);
}; };
} // namespace RM3100 } // namespace mgmRm3100
#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ */ #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ */

View File

@ -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,14 +155,31 @@ 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);
return returnvalue::OK; return returnvalue::OK;
} }
bool HostFilesystem::isDirectory(const char *path) { return filesystem::is_directory(path); }
ReturnValue_t HostFilesystem::getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen,
size_t &baseNameLen) {
std::string path(params.path);
std::string baseName = path.substr(path.find_last_of("/\\") + 1);
if (baseName.size() + 1 > maxLen) {
return returnvalue::FAILED;
}
std::memcpy(nameBuf, baseName.c_str(), baseName.size());
nameBuf[baseName.size()] = '\0';
baseNameLen = baseName.size();
return returnvalue::OK;
}

View File

@ -9,6 +9,9 @@ class HostFilesystem : public HasFileSystemIF {
public: public:
HostFilesystem(); HostFilesystem();
ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen,
size_t &baseNameLen) override;
bool isDirectory(const char *path) override;
bool fileExists(FilesystemParams params) override; bool fileExists(FilesystemParams params) override;
ReturnValue_t truncateFile(FilesystemParams params) override; ReturnValue_t truncateFile(FilesystemParams params) override;
ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override; ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override;

View File

@ -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) {

View File

@ -6,14 +6,11 @@
#include "fsfw/FSFW.h" #include "fsfw/FSFW.h"
#include "fsfw/serviceinterface.h" #include "fsfw/serviceinterface.h"
UnixFileGuard::UnixFileGuard(const std::string& device, int* fileDescriptor, int flags, UnixFileGuard::UnixFileGuard(const std::string& device, int& fileDescriptor, int flags,
std::string diagnosticPrefix) std::string diagnosticPrefix)
: fileDescriptor(fileDescriptor) { : fdRef(fileDescriptor) {
if (fileDescriptor == nullptr) { fileDescriptor = open(device.c_str(), flags);
return; if (fileDescriptor < 0) {
}
*fileDescriptor = open(device.c_str(), flags);
if (*fileDescriptor < 0) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << diagnosticPrefix << ": Opening device failed with error code " << errno << ": " sif::warning << diagnosticPrefix << ": Opening device failed with error code " << errno << ": "
@ -27,10 +24,6 @@ UnixFileGuard::UnixFileGuard(const std::string& device, int* fileDescriptor, int
} }
} }
UnixFileGuard::~UnixFileGuard() { UnixFileGuard::~UnixFileGuard() { close(fdRef); }
if (fileDescriptor != nullptr) {
close(*fileDescriptor);
}
}
ReturnValue_t UnixFileGuard::getOpenResult() const { return openStatus; } ReturnValue_t UnixFileGuard::getOpenResult() const { return openStatus; }

View File

@ -15,7 +15,15 @@ class UnixFileGuard {
static constexpr ReturnValue_t OPEN_FILE_FAILED = 1; static constexpr ReturnValue_t OPEN_FILE_FAILED = 1;
UnixFileGuard(const std::string& device, int* fileDescriptor, int flags, /**
* Open a device and assign the given file descriptor variable
* @param device [in] Device name.
* @param fileDescriptor [in/out] Will be assigned by file guard and re-used to
* close the guard.
* @param flags
* @param diagnosticPrefix
*/
UnixFileGuard(const std::string& device, int& fileDescriptor, int flags,
std::string diagnosticPrefix = ""); std::string diagnosticPrefix = "");
virtual ~UnixFileGuard(); virtual ~UnixFileGuard();
@ -23,7 +31,7 @@ class UnixFileGuard {
ReturnValue_t getOpenResult() const; ReturnValue_t getOpenResult() const;
private: private:
int* fileDescriptor = nullptr; int& fdRef;
ReturnValue_t openStatus = returnvalue::OK; ReturnValue_t openStatus = returnvalue::OK;
}; };

View File

@ -66,8 +66,7 @@ ReturnValue_t I2cComIF::initializeInterface(CookieIF* cookie) {
ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) { ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) {
ReturnValue_t result; ReturnValue_t result;
int fd; int fd = 0;
std::string deviceFile;
if (sendData == nullptr) { if (sendData == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -98,12 +97,12 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s
return returnvalue::FAILED; return returnvalue::FAILED;
} }
deviceFile = i2cCookie->getDeviceFile(); const auto& deviceFile = i2cCookie->getDeviceFile();
UnixFileGuard fileHelper(deviceFile, &fd, O_RDWR, "I2cComIF::sendMessage"); UnixFileGuard fileHelper(deviceFile, fd, O_RDWR, "I2cComIF::sendMessage");
if (fileHelper.getOpenResult() != returnvalue::OK) { if (fileHelper.getOpenResult() != returnvalue::OK) {
return fileHelper.getOpenResult(); return fileHelper.getOpenResult();
} }
result = openDevice(deviceFile, i2cAddress, &fd); result = openI2cSlave(deviceFile, i2cAddress, fd);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
@ -113,7 +112,7 @@ 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 " << deviceFile << " with error code "
<< errno << ". Error description: " << strerror(errno) << std::endl; << errno << ". Error description: " << strerror(errno) << std::endl;
#endif #endif
} }
@ -131,8 +130,7 @@ ReturnValue_t I2cComIF::getSendSuccess(CookieIF* cookie) { return returnvalue::O
ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLen) { ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLen) {
ReturnValue_t result; ReturnValue_t result;
int fd; int fd = 0;
std::string deviceFile;
if (requestLen == 0) { if (requestLen == 0) {
return returnvalue::OK; return returnvalue::OK;
@ -157,12 +155,12 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
} }
i2cDeviceMapIter->second.replyLen = 0; i2cDeviceMapIter->second.replyLen = 0;
deviceFile = i2cCookie->getDeviceFile(); auto& deviceFile = i2cCookie->getDeviceFile();
UnixFileGuard fileHelper(deviceFile, &fd, O_RDWR, "I2cComIF::requestReceiveMessage"); UnixFileGuard fileHelper(deviceFile, fd, O_RDWR, "I2cComIF::requestReceiveMessage");
if (fileHelper.getOpenResult() != returnvalue::OK) { if (fileHelper.getOpenResult() != returnvalue::OK) {
return fileHelper.getOpenResult(); return fileHelper.getOpenResult();
} }
result = openDevice(deviceFile, i2cAddress, &fd); result = openI2cSlave(deviceFile, i2cAddress, fd);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
@ -220,9 +218,9 @@ ReturnValue_t I2cComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer,
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t I2cComIF::openDevice(std::string deviceFile, address_t i2cAddress, ReturnValue_t I2cComIF::openI2cSlave(const std::string& deviceFile, address_t i2cAddress,
int* fileDescriptor) { int& fileDescriptor) {
if (ioctl(*fileDescriptor, I2C_SLAVE, i2cAddress) < 0) { if (ioctl(fileDescriptor, I2C_SLAVE, i2cAddress) < 0) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "I2cComIF: Specifying target device failed with error code " << errno << "." sif::warning << "I2cComIF: Specifying target device failed with error code " << errno << "."

View File

@ -49,7 +49,8 @@ class I2cComIF : public DeviceCommunicationIF, public SystemObject {
* @param fileDescriptor Pointer to device descriptor. * @param fileDescriptor Pointer to device descriptor.
* @return returnvalue::OK if successful, otherwise returnvalue::FAILED. * @return returnvalue::OK if successful, otherwise returnvalue::FAILED.
*/ */
ReturnValue_t openDevice(std::string deviceFile, address_t i2cAddress, int *fileDescriptor); ReturnValue_t openI2cSlave(const std::string &deviceFile, address_t i2cAddress,
int &fileDescriptor);
}; };
#endif /* LINUX_I2C_I2COMIF_H_ */ #endif /* LINUX_I2C_I2COMIF_H_ */

View File

@ -1,12 +1,12 @@
#include "fsfw_hal/linux/i2c/I2cCookie.h" #include "fsfw_hal/linux/i2c/I2cCookie.h"
I2cCookie::I2cCookie(address_t i2cAddress_, size_t maxReplyLen_, std::string deviceFile_) I2cCookie::I2cCookie(address_t i2cAddress_, size_t maxReplyLen_, std::string deviceFile_)
: i2cAddress(i2cAddress_), maxReplyLen(maxReplyLen_), deviceFile(deviceFile_) {} : i2cAddress(i2cAddress_), maxReplyLen(maxReplyLen_), deviceFile(std::move(deviceFile_)) {}
address_t I2cCookie::getAddress() const { return i2cAddress; } address_t I2cCookie::getAddress() const { return i2cAddress; }
size_t I2cCookie::getMaxReplyLen() const { return maxReplyLen; } size_t I2cCookie::getMaxReplyLen() const { return maxReplyLen; }
std::string I2cCookie::getDeviceFile() const { return deviceFile; } const std::string& I2cCookie::getDeviceFile() const { return deviceFile; }
I2cCookie::~I2cCookie() {} I2cCookie::~I2cCookie() {}

View File

@ -25,7 +25,7 @@ class I2cCookie : public CookieIF {
address_t getAddress() const; address_t getAddress() const;
size_t getMaxReplyLen() const; size_t getMaxReplyLen() const;
std::string getDeviceFile() const; const std::string& getDeviceFile() const;
uint8_t errorCounter = 0; uint8_t errorCounter = 0;

View File

@ -2,7 +2,6 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <fsfw_hal/linux/serial/SerialComIF.h>
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <fsfw_hal/linux/spi/SpiCookie.h>
#include "fsfw/ipc/MutexIF.h" #include "fsfw/ipc/MutexIF.h"
#include "fsfw/returnvalues/returnvalue.h" #include "fsfw/returnvalues/returnvalue.h"
#include "fsfw_hal/common/gpio/GpioIF.h" #include "fsfw_hal/common/gpio/GpioIF.h"

View File

@ -75,7 +75,7 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
spiCookie->getSpiParameters(spiMode, spiSpeed, &params); spiCookie->getSpiParameters(spiMode, spiSpeed, &params);
int fileDescriptor = 0; int fileDescriptor = 0;
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::initializeInterface"); UnixFileGuard fileHelper(dev, fileDescriptor, O_RDWR, "SpiComIF::initializeInterface");
if (fileHelper.getOpenResult() != returnvalue::OK) { if (fileHelper.getOpenResult() != returnvalue::OK) {
return fileHelper.getOpenResult(); return fileHelper.getOpenResult();
} }
@ -171,7 +171,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
int retval = 0; int retval = 0;
/* Prepare transfer */ /* Prepare transfer */
int fileDescriptor = 0; int fileDescriptor = 0;
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage"); UnixFileGuard fileHelper(dev, fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
if (fileHelper.getOpenResult() != returnvalue::OK) { if (fileHelper.getOpenResult() != returnvalue::OK) {
return OPENING_FILE_FAILED; return OPENING_FILE_FAILED;
} }
@ -179,12 +179,11 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
uint32_t spiSpeed = 0; uint32_t spiSpeed = 0;
spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr);
setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed);
spiCookie->assignWriteBuffer(sendData);
spiCookie->setTransferSize(sendLen);
bool fullDuplex = spiCookie->isFullDuplex(); bool fullDuplex = spiCookie->isFullDuplex();
gpioId_t gpioId = spiCookie->getChipSelectPin(); gpioId_t gpioId = spiCookie->getChipSelectPin();
bool csLockManual = spiCookie->getCsLockManual(); bool csLockManual = spiCookie->getCsLockManual();
spiCookie->setTransferSize(0);
MutexIF::TimeoutType csType; MutexIF::TimeoutType csType;
dur_millis_t csTimeout = 0; dur_millis_t csTimeout = 0;
@ -195,9 +194,13 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code " if (result == MutexIF::MUTEX_TIMEOUT) {
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec sif::error << "SpiComIF::sendMessage: Lock timeout" << std::endl;
<< std::endl; } else {
sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code "
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec
<< std::endl;
}
#else #else
sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result); sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
#endif #endif
@ -214,17 +217,22 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
sif::printWarning("SpiComIF::sendMessage: Pulling low CS pin failed"); sif::printWarning("SpiComIF::sendMessage: Pulling low CS pin failed");
#endif #endif
#endif #endif
csMutex->unlockMutex();
return result; return result;
} }
} else { } else {
updateLinePolarity(fileDescriptor); updateLinePolarity(fileDescriptor);
} }
spiCookie->assignWriteBuffer(sendData);
spiCookie->setTransferSize(sendLen);
/* Execute transfer */ /* Execute transfer */
if (fullDuplex) { if (fullDuplex) {
/* Initiate a full duplex SPI transfer. */ /* Initiate a full duplex SPI transfer. */
retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle()); retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle());
if (retval < 0) { if (retval < 0) {
spiCookie->setTransferSize(0);
utility::handleIoctlError("SpiComIF::sendMessage: ioctl error."); utility::handleIoctlError("SpiComIF::sendMessage: ioctl error.");
result = FULL_DUPLEX_TRANSFER_FAILED; result = FULL_DUPLEX_TRANSFER_FAILED;
} }
@ -234,6 +242,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
} else { } else {
/* We write with a blocking half-duplex transfer here */ /* We write with a blocking half-duplex transfer here */
if (write(fileDescriptor, sendData, sendLen) != static_cast<ssize_t>(sendLen)) { if (write(fileDescriptor, sendData, sendLen) != static_cast<ssize_t>(sendLen)) {
spiCookie->setTransferSize(0);
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << std::endl; sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << std::endl;
@ -276,7 +285,7 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) { ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
int fileDescriptor = 0; int fileDescriptor = 0;
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage"); UnixFileGuard fileHelper(dev, fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
if (fileHelper.getOpenResult() != returnvalue::OK) { if (fileHelper.getOpenResult() != returnvalue::OK) {
return OPENING_FILE_FAILED; return OPENING_FILE_FAILED;
} }

View File

@ -90,8 +90,6 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
* pulled high * pulled high
*/ */
MutexIF* csMutex = nullptr; MutexIF* csMutex = nullptr;
// MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
// uint32_t timeoutMs = DEFAULT_MUTEX_TIMEOUT;
spi_ioc_transfer clockUpdateTransfer = {}; spi_ioc_transfer clockUpdateTransfer = {};
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>; using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;

View File

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

View File

@ -138,3 +138,10 @@ ReturnValue_t FilesystemMock::truncateFile(FilesystemParams params) {
truncateCalledOnFile = params.path; truncateCalledOnFile = params.path;
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t FilesystemMock::getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen,
size_t &baseNameLen) {
return returnvalue::OK;
}
bool FilesystemMock::isDirectory(const char *path) { return false; }

View File

@ -56,6 +56,10 @@ class FilesystemMock : public HasFileSystemIF {
std::string truncateCalledOnFile; std::string truncateCalledOnFile;
ReturnValue_t feedFile(const std::string &filename, std::ifstream &file); ReturnValue_t feedFile(const std::string &filename, std::ifstream &file);
ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen,
size_t &baseNameLen) override;
bool isDirectory(const char *path) override;
bool fileExists(FilesystemParams params) override; bool fileExists(FilesystemParams params) override;
ReturnValue_t truncateFile(FilesystemParams params) override; ReturnValue_t truncateFile(FilesystemParams params) override;

View File

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

View File

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

View File

@ -1,15 +1,18 @@
#include <fsfw/timemanager/Countdown.h> #include <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());
}
} }