Compare commits

..

254 Commits

Author SHA1 Message Date
7ebfcdda60 added Action::clear() 2023-07-28 17:48:47 +02:00
5c25a2777c datapool working 2023-07-26 22:28:18 +02:00
7f80e91a91 removed HasModesIF::getModeDefinitionHelper(), do not think this will last 2023-07-24 16:01:55 +02:00
732419e239 multiple stuff, need to leave 2023-07-21 14:23:55 +02:00
d328f3e190 handling DatasetEntries 2023-07-18 15:07:21 +02:00
4c0d9ae039 switching to non template set, added valid flag handling 2023-07-18 14:43:18 +02:00
753d587b69 valid flags in housekeeping tm 2023-07-18 13:17:34 +02:00
979a7b7d75 TM working 2023-07-14 16:10:21 +02:00
a30146a799 working on TM 2023-07-14 14:11:22 +02:00
ae2823ba2d tm path 2023-07-12 14:19:58 +02:00
3a433915f1 moved action parameters to a generic place to use them for HK TM 2023-07-12 12:52:07 +02:00
d766469f1e working on HK and Dataset TM 2023-07-11 14:57:17 +02:00
33a2fb48e5 WIP Datapool 2023-07-10 17:07:39 +02:00
531d8c45e8 removed hardcoded ip information 2023-07-10 16:17:05 +02:00
14a7dd885b removed debug code and typo 2023-07-06 13:33:59 +02:00
50a4ec97ef working on tm 2023-07-05 23:47:07 +02:00
de93bff561 working on tm 2023-07-05 13:49:03 +02:00
ad4adc7cba breaking everything in preperation of new Datapool 2023-07-03 17:10:16 +02:00
6a76857f5f clearer wording 2023-07-03 10:09:47 +02:00
2044e1cde2 event manager debug prints 2023-06-23 16:22:53 +02:00
b56b54951b missed one GCC13 adaption 2023-06-23 16:22:19 +02:00
1fc50a1562 lots of breaking some patching back together 2023-06-20 15:14:15 +02:00
e831ba11d2 breaking everything, WIP 2023-06-19 17:27:25 +02:00
0da490481e Merge branch 'development' into mohr_introspection 2023-06-02 15:20:00 +02:00
146c3471d0 Merge pull request 'fixes for GCC13' (#750) from mohr/GCC13 into development
Reviewed-on: fsfw/fsfw#750
2023-06-02 13:40:35 +02:00
1816c3f623 Merge pull request 'CFDP bugfix' (#749) from eive/fsfw:cfdp-bugfix-unittest-fixes into development
Reviewed-on: fsfw/fsfw#749
2023-06-02 13:30:54 +02:00
d03d5aa74c fixing host osal for GCC13 2023-06-02 12:02:37 +02:00
26e97ddf89 overload vs override clarification for GCC13; Also, cmake-format 2023-06-02 11:33:20 +02:00
be3a57a795 bump ETL and Catch2 version 2023-06-01 17:54:38 +02:00
318a933b3b Builds, unittests failing 2023-06-01 17:51:55 +02:00
13b97abf0d fixing build failure for master and development branch 2023-06-01 17:06:19 +02:00
e8480cf962 Merge remote-tracking branch 'origin/development' into mohr_introspection 2023-06-01 15:08:03 +02:00
a5e6107001 bug found by unittest 2023-06-01 14:56:05 +02:00
f95c373076 Merge pull request 'TCP/IP server fixes and improvements' (#747) from eive/fsfw:tcpip_server_fixes_improvements into development
Reviewed-on: fsfw/fsfw#747
2023-05-25 16:04:28 +02:00
e03731bcf8 Merge pull request 'event manager improvements' (#741) from eive/fsfw:event_manager_improvements into development
Reviewed-on: fsfw/fsfw#741
2023-05-25 15:46:42 +02:00
9fe8579377 CFDP bugfix 2023-05-25 15:11:56 +02:00
2714e588d7 improvements 2023-05-25 15:01:53 +02:00
e905288adc Merge remote-tracking branch 'upstream/development' into tcpip_server_fixes_improvements 2023-05-25 15:00:42 +02:00
3805ea50a7 remove unused constant 2023-05-25 14:58:18 +02:00
699bd694cd Merge branch 'development' into event_manager_improvements 2023-05-25 14:44:22 +02:00
4518fec65c CHANGELOG 2023-05-08 15:25:47 +02:00
dac1aacab2 Merge pull request 'Update Power Switch IF' (#743) from eive/fsfw:update_power_switch_if into development
Reviewed-on: fsfw/fsfw#743
2023-05-08 15:00:47 +02:00
0042f92fdf Merge pull request 'bump ETL version' (#748) from KSat/fsfw:bump_etl_dep into development
Reviewed-on: fsfw/fsfw#748
2023-05-08 14:53:02 +02:00
656faf8169 Merge remote-tracking branch 'upstream/development' into update_power_switch_if 2023-05-08 14:44:27 +02:00
f84431e965 Merge pull request 'bugfix and changelog for Linux getUptime' (#745) from eive/fsfw:important_bugfix_linux_get_uptime into development
Reviewed-on: fsfw/fsfw#745
2023-05-08 14:29:55 +02:00
0cec9ebb73 Merge pull request 'small tweak for version getter' (#744) from eive/fsfw:small_version_getter_tweak into development
Reviewed-on: fsfw/fsfw#744
2023-05-08 14:13:06 +02:00
a440b7c394 Merge pull request 'add CFDP subsystem ID' (#742) from eive/fsfw:add_cfdp_subsystem_id into development
Reviewed-on: fsfw/fsfw#742
2023-05-08 14:09:04 +02:00
bbfc1b2b34 Merge pull request 'FixedArrayList compile time assert' (#740) from eive/fsfw:container_additional_assert into development
Reviewed-on: fsfw/fsfw#740
2023-05-08 14:04:56 +02:00
025b379e8b bump ETL version 2023-05-04 14:04:55 +02:00
c35a0a8541 TCP/IP server fixes and improvements 2023-03-15 12:40:44 +01:00
0f81d5e458 Merge remote-tracking branch 'upstream/development' into container_additional_assert 2023-03-15 12:34:36 +01:00
e0a072859b Merge remote-tracking branch 'upstream/development' into event_manager_improvements 2023-03-15 12:33:57 +01:00
b50f092939 Merge remote-tracking branch 'upstream/development' into update_power_switch_if 2023-03-15 12:33:08 +01:00
2f90e12179 Merge remote-tracking branch 'upstream/development' into important_bugfix_linux_get_uptime 2023-03-15 12:32:25 +01:00
8b77fac099 Merge pull request 'health service fixes and changelog' (#746) from eive/fsfw:health_service_fixes into development
Reviewed-on: fsfw/fsfw#746
2023-03-15 12:29:31 +01:00
47503824d7 health service fixes and changelog 2023-03-15 12:27:39 +01:00
5e3f5c4121 fuse update 2023-03-15 12:25:39 +01:00
1f36c082ef bugfix and changelog for Linux getUptime 2023-03-15 12:21:50 +01:00
aa84e93603 small tweak for version getter 2023-03-15 12:17:36 +01:00
8f63a0e747 changelog 2023-03-15 12:15:21 +01:00
6fc8f756a7 update power switch IF 2023-03-15 12:13:55 +01:00
067cb7d0f8 update catch factory 2023-03-15 12:11:22 +01:00
d98ed40e3d add CFDP subsystem ID 2023-03-15 12:09:30 +01:00
2c17af4ef8 changelog 2023-03-15 12:06:13 +01:00
110fb43b9c event manager improvements 2023-03-15 12:05:22 +01:00
b057250bfb changelog 2023-03-15 11:53:12 +01:00
066dd0d397 changelog 2023-03-15 11:52:20 +01:00
f735c2e9d4 assert size larger than 0 2023-03-15 11:51:51 +01:00
dc7afc5415 Version bump, CHANGELOG update, format 2023-02-23 13:38:24 +01:00
9bf3ff95b7 Merge pull request 'Add Health Service Announce All Health Info' (#725) from eive/fsfw:add_health_service_announce_all into development
Reviewed-on: fsfw/fsfw#725
2023-02-23 13:13:56 +01:00
61562b18ab Merge branch 'development' into add_health_service_announce_all 2023-02-23 12:56:12 +01:00
d76d97a36b changed health table parameter to objectId 2023-02-23 12:44:42 +01:00
76b377c4c0 Merge pull request 'Mode Service: Add allowed subservice' (#739) from eive/fsfw:small_mode_service_fix into development
Reviewed-on: fsfw/fsfw#739
2023-02-20 13:40:53 +01:00
3562bf11b9 CHANGELOG update 2023-02-10 11:06:46 +01:00
fffb2b61e5 release check helper 2023-02-10 11:06:30 +01:00
94e5f62331 add allowed subservice 2023-02-09 18:30:08 +01:00
0a9c563bbc format 2023-02-09 15:58:48 +01:00
fa7675897d Merge pull request 'Mode Service Bugfixes' (#736) from eive/fsfw:mode_service_fixes into development
Reviewed-on: fsfw/fsfw#736
2023-02-09 15:56:26 +01:00
3a2393885f more style 2023-02-09 15:44:39 +01:00
c752b6d143 Merge pull request 'Generic TMTC Bridge Update' (#734) from eive/fsfw:tmtcbridge_tweaks into development
Reviewed-on: fsfw/fsfw#734
2023-02-09 15:37:35 +01:00
b676040c7c Merge pull request 'CMakeLists file updates' (#731) from eive/fsfw:cmakelists_update into development
Reviewed-on: fsfw/fsfw#731
2023-02-09 15:29:46 +01:00
010509efb4 removed unneeded find_package parameter for etl 2023-02-09 13:50:16 +01:00
dfb1633f00 Merge branch 'development' into mode_service_fixes 2023-02-09 13:46:19 +01:00
5f7172e130 Merge pull request 'TCP/IP TMTC bridge memory leak fixes' (#737) from eive/fsfw:possible_tcpip_bridge_fixes into development
Reviewed-on: fsfw/fsfw#737
2023-02-09 12:15:45 +01:00
0c6465cd95 Merge pull request 'time stamper empty ctor' (#730) from eive/fsfw:empty_cds_short_ctor into development
Reviewed-on: fsfw/fsfw#730
2023-02-09 11:45:49 +01:00
f94987c46d Merge pull request 'RM3100 important bugfix' (#733) from eive/fsfw:rm3100_fixes into development
Reviewed-on: fsfw/fsfw#733
2023-02-09 11:41:53 +01:00
1809ce359b Merge pull request 'comment tweak to event parser can read everything' (#732) from eive/fsfw:health_if_update into development
Reviewed-on: fsfw/fsfw#732
2023-02-09 11:39:53 +01:00
8c712441ab Making fetch Catch2 quiet as well. 2023-02-09 11:34:58 +01:00
f1b0ca7cff add PR link 2023-02-08 21:26:37 +01:00
000df85556 bump changelog 2023-02-08 21:24:00 +01:00
1fffcc2229 possiible leak fixes 2023-02-08 21:23:21 +01:00
a419806a05 Merge remote-tracking branch 'upstream/development' into mode_service_fixes 2023-02-08 09:33:13 +01:00
6445debfa1 bump changelog 2023-02-08 09:24:55 +01:00
8014e4adf9 mode service fixes 2023-02-08 09:23:48 +01:00
134d908f26 that stuff is not in upstream yet.. 2023-02-07 12:52:18 +01:00
40a9e12416 1000 is a bit much 2023-02-07 12:47:40 +01:00
f39054edd4 introduce warning switch 2023-02-07 12:45:29 +01:00
5adf89b911 changelog update 2023-02-07 12:41:42 +01:00
c2e6a22dec important bugfix for RM3100 2023-02-07 12:39:43 +01:00
c8e065a713 comment tweak to event parser can read everything 2023-02-07 12:36:42 +01:00
3ed49dbae3 Merge remote-tracking branch 'upstream/development' into empty_cds_short_ctor 2023-02-07 12:24:02 +01:00
4cf52d5dfe Merge pull request 'Time Service 9 update' (#726) from eive/fsfw:updates_fixes_pus_time_service into development
Reviewed-on: fsfw/fsfw#726
2023-02-07 12:19:45 +01:00
539d7aac9e suppress error if ETL is not found 2023-02-07 12:17:03 +01:00
0a23f2c85a correction for printout, add prefix 2023-02-07 12:15:44 +01:00
46230e6c6d Merge remote-tracking branch 'upstream/development' into updates_fixes_pus_time_service 2023-02-07 12:11:29 +01:00
b22d439300 bump changelog 2023-02-07 12:10:11 +01:00
7e7b3bbbc9 time stamper empty ctor 2023-02-07 12:07:41 +01:00
5b92247fbd Merge branch 'development' into add_health_service_announce_all 2023-02-06 16:31:05 +01:00
e2b66df72e Merge pull request 'various fixes related to linux Unittests and memory leaks' (#715) from eive/fsfw:unittest_fix_semaphore into development
Reviewed-on: fsfw/fsfw#715
2023-02-06 16:30:37 +01:00
d9da55fdab Merge branch 'development' into add_health_service_announce_all 2023-02-06 15:03:52 +01:00
7b828f233a Merge pull request 'I2C Linux: remove duplicate printout' (#718) from eive/fsfw:i2c_remove_duplicate_printout into development
Reviewed-on: fsfw/fsfw#718
2023-02-06 14:54:58 +01:00
c3d1000cd5 Merge branch 'development' into unittest_fix_semaphore 2023-02-06 14:46:45 +01:00
8e0e57714d Merge pull request 'allow using SO_REUSEADDR and SO_REUSEPORT on TCP server' (#722) from eive/fsfw:tcp_server_reuseaddr_reusesocket into development
Reviewed-on: fsfw/fsfw#722
2023-02-06 14:45:40 +01:00
066f7a6f9b remove unreachable code 2023-02-06 14:41:14 +01:00
cc9e54ea6b Merge pull request 'improve srv20 error messages' (#723) from eive/fsfw:srv20_error_msgs into development
Reviewed-on: fsfw/fsfw#723
2023-02-06 14:37:26 +01:00
31465a4e0f Merge pull request 'MGM: small tweak, gain factor was always them same' (#724) from eive/fsfw:mgm_handler_small_fix into development
Reviewed-on: fsfw/fsfw#724
2023-02-06 14:36:34 +01:00
c0e5d1eb99 Merge branch 'development' into tcp_server_reuseaddr_reusesocket 2023-02-06 14:34:52 +01:00
3bc5d4a2e0 Merge remote-tracking branch 'upstream/development' into mgm_handler_small_fix 2023-02-06 14:25:33 +01:00
b1e9dd9e4a Merge remote-tracking branch 'upstream/development' into updates_fixes_pus_time_service 2023-02-06 14:24:38 +01:00
ab86599db3 Merge pull request 'Bugfix DHB setNormalDatapoolEntriesInvalid' (#728) from eive/fsfw:bugfix_dhb_set_datapool_entries_invalid into development
Reviewed-on: fsfw/fsfw#728
2023-02-06 14:20:34 +01:00
034eb34c2e small tweak 2023-02-03 16:05:50 +01:00
4374c7c4f4 changelog 2023-02-03 16:01:56 +01:00
5343844be5 bugfix in setNormalDataPoolEntriesInvalid
Do not forget to call read and write to actually update the
validity state
2023-02-03 16:00:55 +01:00
e300490b93 Merge pull request 'Bugfix PUS packet creators Sequence flags' (#727) from eive/fsfw:bugfix_pus_packets_seq_flags into development
Reviewed-on: fsfw/fsfw#727
2023-02-02 17:22:29 +01:00
0f811777a7 changelog update 2023-02-01 20:49:53 +01:00
e93137939e set sequence flags for PUS TMTC to unsegmented 2023-02-01 20:48:26 +01:00
c1f42618db small but important bugfix for health service 2023-02-01 19:59:32 +01:00
1f88c006d9 update changelog 2023-02-01 18:42:09 +01:00
7e94baceef service 9 update
- fix time info event
- add time dump subservice
2023-02-01 18:39:23 +01:00
61df451dd8 update changelog 2023-02-01 17:41:47 +01:00
29ea89044e beatufil 2023-02-01 17:35:49 +01:00
e487f5be87 proper announce all impl 2023-02-01 17:35:32 +01:00
9b05e8f274 re-order fields in TcpConfig 2023-01-30 14:24:48 +01:00
eb223dae88 bump changelog 2023-01-30 14:20:28 +01:00
3656662d88 small tweak, gain factory was always them same 2023-01-30 14:18:03 +01:00
fe71978467 improve srv20 error messages 2023-01-30 14:15:37 +01:00
b646717a76 bump changelog 2023-01-30 14:11:00 +01:00
99d8c845f2 allow using SO_REUSEADDR and SO_REUSEPORT on TCP server 2023-01-30 14:07:41 +01:00
0e7c6b117f Merge pull request 'Service 11 TC Scheduler Robustness Improvements' (#720) from service_11_bugfixes into development
Reviewed-on: fsfw/fsfw#720
2023-01-13 13:33:19 +01:00
d16c5024dc small include improvement 2023-01-13 11:15:36 +01:00
a4531e4ced typo 2023-01-13 10:59:39 +01:00
97c629ad84 update changelog 2023-01-13 10:53:36 +01:00
bf12f284fa add size and crc check for contained TC 2023-01-13 10:53:04 +01:00
ba62c28b64 adding linux ci and fixing problems 2023-01-12 15:40:52 +01:00
7adb47aecb remove duplicate printout 2023-01-11 08:45:37 +01:00
8589f4d63a Merge pull request 'updates for source sequence counter' (#714) from eive/fsfw:source_seq_counter_update into development
Reviewed-on: fsfw/fsfw#714
2022-12-19 15:00:28 +01:00
ca80589233 make get const 2022-12-19 14:58:08 +01:00
f2ebaed092 Merge pull request 'vec getter, reset for content' (#716) from eive/fsfw:get_cmd_exec_read_buf into development
Reviewed-on: fsfw/fsfw#716
2022-12-19 14:56:11 +01:00
f0b89e98df Merge pull request 'printout handling improvements' (#717) from eive/fsfw:i2c_printout_improvements into development
Reviewed-on: fsfw/fsfw#717
2022-12-19 14:45:04 +01:00
5557d95994 Merge branch 'development' into i2c_printout_improvements 2022-12-05 14:20:58 +01:00
fc24c9b5d8 Merge branch 'development' into get_cmd_exec_read_buf 2022-12-05 14:20:52 +01:00
7ef69c839c Merge pull request 'small fix to allow teardown handling' (#713) from eive/fsfw:mueller/shutdown_for_failed_to_on_transition into development
Reviewed-on: fsfw/fsfw#713
2022-11-28 14:30:15 +01:00
9b798d798e Merge pull request 'DLE parser' (#711) from eive/fsfw:mueller/dle_parser into development
Reviewed-on: fsfw/fsfw#711
2022-11-28 14:13:18 +01:00
b13453f46b vec getter, reset for content 2022-11-28 08:43:54 +01:00
d0e322d7e2 printout handling improvements 2022-11-28 08:42:08 +01:00
ecde164f68 updates for source sequence counter 2022-11-28 08:30:45 +01:00
50930b41ba Merge remote-tracking branch 'upstream/development' into mueller/dle_parser 2022-11-28 08:27:24 +01:00
d6ee2ed400 Merge pull request 'AcceptsTelemetryIF tweaks' (#712) from eive/fsfw:mueller/accepts_tm_if_adaptions into development
Reviewed-on: fsfw/fsfw#712
2022-11-21 16:30:43 +01:00
f2150ff9c2 Merge pull request 'only delete table entry if not nullptr' (#710) from eive/fsfw:mueller/health_helper_bugfix into development
Reviewed-on: fsfw/fsfw#710
2022-11-21 16:24:13 +01:00
1b9c98f3fe Merge pull request 'uio able to resolve symlinks now' (#709) from eive/fsfw:mueller/uio_mapper_handle_symlinks into development
Reviewed-on: fsfw/fsfw#709
2022-11-21 16:14:36 +01:00
742152b28e Merge branch 'development' into mueller/accepts_tm_if_adaptions 2022-11-21 15:29:35 +01:00
bf4ca56658 Merge branch 'development' into mueller/shutdown_for_failed_to_on_transition 2022-11-21 15:29:11 +01:00
16ffa00155 Merge branch 'development' into mueller/dle_parser 2022-11-21 15:28:34 +01:00
14c681c93a Merge branch 'development' into mueller/uio_mapper_handle_symlinks 2022-11-21 15:27:06 +01:00
0958c3a00e Merge branch 'development' into mueller/health_helper_bugfix 2022-11-21 15:24:51 +01:00
d699d16307 Merge pull request 'SP reader getPacketData is const now' (#708) from eive/fsfw:mueller/sp_reader_const_get_data into development
Reviewed-on: fsfw/fsfw#708
2022-11-21 15:23:39 +01:00
3b0fed733f Merge branch 'development' into mueller/uio_mapper_handle_symlinks 2022-11-21 15:23:15 +01:00
23d3812fe3 this is actually important 2022-11-21 15:22:25 +01:00
dec7db3ae2 Merge remote-tracking branch 'upstream/development' into mueller/accepts_tm_if_adaptions 2022-11-21 15:00:06 +01:00
65a5abab49 move free call 2022-11-21 14:56:08 +01:00
0129783e34 Merge branch 'development' into mueller/sp_reader_const_get_data 2022-11-21 14:50:44 +01:00
cabe0868ec Merge pull request 'move container returnvalues to namespace' (#707) from eive/fsfw:mueller/update_containers_retval into development
Reviewed-on: fsfw/fsfw#707
2022-11-21 14:49:44 +01:00
f05295bada small fix to allow teardown handling 2022-11-17 15:16:29 +01:00
b85ca64690 update changelog 2022-11-15 11:48:28 +01:00
3bc3da5a8d update changelog 2022-11-15 11:47:26 +01:00
f8c07ec9cf update changelog 2022-11-15 11:46:43 +01:00
8199b8f359 bump changelog 2022-11-15 11:45:39 +01:00
cbc8dbcdd4 update changelog 2022-11-15 11:44:45 +01:00
d31a5306f0 fix mock 2022-11-15 11:41:03 +01:00
a236a5ec50 adaptions for AcceptsTelemetryIF 2022-11-15 11:40:26 +01:00
03620970e2 function to get queue is const now 2022-11-15 11:38:32 +01:00
8fe8d810e9 only delete table if not nullptr 2022-11-15 11:27:31 +01:00
9483c2809d DLE parser 2022-11-15 11:26:53 +01:00
fe3d6bd432 uio able to resolve symlinks now 2022-11-15 10:56:46 +01:00
2a842666d5 SP reader getPacketData is const now 2022-11-15 10:46:46 +01:00
c013fcc1f5 move container retvals to namespace 2022-11-15 10:01:37 +01:00
1b8fc2af19 Merge pull request 'CFDP Update' (#682) from mueller/cfdp-update-without-handlers into development
Reviewed-on: fsfw/fsfw#682
2022-11-14 15:04:43 +01:00
72d7c43445 updates for storage manager mock 2022-11-14 14:57:37 +01:00
ab9b6c8c89 Merge remote-tracking branch 'origin/development' into mueller/cfdp-update-without-handlers 2022-11-14 14:51:33 +01:00
69d338f9bb Merge pull request 'Local Pool Update Remove Add Data Ignore Fault Argument' (#701) from eive/fsfw:mueller/local-pool-update-remove-ignore-fault-arg into development
Reviewed-on: fsfw/fsfw#701
2022-11-14 14:49:34 +01:00
68223869d5 Merge branch 'development' into mueller/local-pool-update-remove-ignore-fault-arg 2022-11-14 14:47:07 +01:00
93fda71989 Merge pull request 'refactoring of serial drivers for linux' (#705) from eive/fsfw:mueller/refactor_serial_linux into development
Reviewed-on: fsfw/fsfw#705
2022-11-14 14:39:41 +01:00
7b0db08962 Merge branch 'development' into mueller/refactor_serial_linux 2022-11-14 14:36:31 +01:00
0956fbc740 Merge pull request 'fix compiler warning for fixed array list copy ctor' (#704) from eive/fsfw:mueller/fixed_array_list_copy_ctor into development
Reviewed-on: fsfw/fsfw#704
2022-11-14 14:28:46 +01:00
b48e0fdc0d Merge remote-tracking branch 'origin/development' into mueller/cfdp-update-without-handlers 2022-11-14 14:25:36 +01:00
1d084ee22f Merge branch 'development' into mueller/fixed_array_list_copy_ctor 2022-11-14 14:21:04 +01:00
1bea2344f6 remove using declaraction 2022-11-14 14:21:00 +01:00
d7e16a67a7 Merge pull request 'Windows Tweaks' (#691) from eive/fsfw:windows-tweaks-upstream into development
Reviewed-on: fsfw/fsfw#691
2022-11-14 14:18:47 +01:00
6021d897b8 Merge branch 'development' into windows-tweaks-upstream 2022-11-14 14:13:57 +01:00
83a6f0b5f8 reenable setup function call 2022-11-14 14:12:26 +01:00
a9c6c088f2 remove leftover debugging code 2022-11-14 14:08:38 +01:00
b6a3c206cc smaller include tweaks 2022-11-11 11:34:58 +01:00
5b352978c5 rename cookie class 2022-11-11 11:33:35 +01:00
819a298b19 refactoring of serial drivers for linux 2022-11-10 17:50:21 +01:00
16246d6ece replace other memcpy 2022-11-10 16:18:36 +01:00
5c84f12440 this not crash 2022-11-10 16:15:52 +01:00
83c2c4825c fix compiler error for fixed array list copy ctor 2022-11-10 15:54:03 +01:00
c913fe40bf tweaks 2022-11-09 17:54:08 +01:00
70ec08bf1d Merge pull request 'missing include' (#703) from KSat/fsfw:mueller/time_reader_include into development
Reviewed-on: fsfw/fsfw#703
2022-11-09 16:59:25 +01:00
ef23665d9c Merge branch 'development' into mueller/time_reader_include 2022-11-09 16:39:55 +01:00
eefc122292 Merge pull request 'defaultconfig did not build anymore' (#702) from mohr/fix_defaultconfig into development
Reviewed-on: fsfw/fsfw#702
2022-11-09 14:12:41 +01:00
bee33526a1 missing include 2022-11-09 13:49:40 +01:00
f715b65d6e Merge remote-tracking branch 'upstream/development' into mueller/local-pool-update-remove-ignore-fault-arg 2022-10-28 10:06:04 +02:00
c11af63015 Merge remote-tracking branch 'origin/development' into mueller/cfdp-update-without-handlers 2022-10-28 10:04:21 +02:00
dc1583c932 Merge branch 'development' into windows-tweaks-upstream 2022-10-24 17:10:44 +02:00
81a7de2814 make dtor virtual 2022-10-24 16:39:32 +02:00
d26f230bee builds 2022-10-24 15:43:20 +02:00
4db124c680 ignore fault 2022-10-24 15:41:29 +02:00
2df66c9304 Merge branch 'mueller/local-pool-update' of https://egit.irs.uni-stuttgart.de/fsfw/fsfw into mueller/local-pool-update 2022-10-24 14:39:11 +02:00
54ad6b3016 add some docs 2022-10-24 14:39:05 +02:00
73e313c35b Merge branch 'development' into mueller/local-pool-update 2022-10-24 14:35:24 +02:00
dd2f42d22b Merge branch 'development' into mueller/local-pool-update 2022-10-24 14:34:56 +02:00
652c31a683 missing validity check 2022-10-17 17:25:27 +02:00
bfe120636c this should have the same effect 2022-10-17 15:08:46 +02:00
a8041f220f Merge branch 'development' into mueller/cfdp-update-without-handlers 2022-10-17 14:44:28 +02:00
dd636b186b size check bugfix 2022-10-17 14:30:27 +02:00
3349fc36f8 Merge branch 'development' into windows-tweaks-upstream 2022-10-17 14:20:48 +02:00
df06064df0 Merge branch 'development' into windows-tweaks-upstream 2022-10-10 13:41:09 +02:00
e0c780f21c better comment 2022-09-28 09:59:31 +02:00
876815b1c9 another small windows tweak 2022-09-28 09:59:22 +02:00
b0ecf87580 last windows tweak 2022-09-28 09:59:12 +02:00
68ce8b5b08 tweaks to make windows build again 2022-09-28 09:59:02 +02:00
fe03da6def Merge remote-tracking branch 'origin/development' into mueller/cfdp-update-without-handlers 2022-09-26 15:38:45 +02:00
4f7f8310c9 Merge remote-tracking branch 'origin/development' into mueller/local-pool-update 2022-09-15 11:00:43 +02:00
1c527c4946 copy paste fail #2 2022-09-08 11:41:32 +02:00
4c0f67adf5 missing implementation in subsystembase 2022-08-26 15:03:17 +02:00
450ad1dad4 ControllerBase Modes 2022-08-26 12:07:59 +02:00
1dfb3323f7 default getModehelper for ControllerBase 2022-08-26 11:53:46 +02:00
f5adcd0625 default getModehelper for subsystembase 2022-08-26 10:57:05 +02:00
bc593c938d some more mode introspection 2022-08-26 10:31:45 +02:00
3f8f17a66e copy paste fail 2022-08-25 22:39:21 +02:00
3260a03544 forgot include 2022-08-25 22:37:41 +02:00
3ffdc0d31f Mode introspection 2022-08-25 22:33:33 +02:00
d367baa42c stupid idea 2022-08-24 18:47:25 +02:00
59f8dd1322 preparing DHB::buildCommandFromCommand for retirement 2022-08-24 17:49:16 +02:00
61b4e68f3d parameter tuning 2022-08-24 17:19:45 +02:00
e34664d265 Adding error message to a coding error 2022-08-19 13:47:13 +02:00
20eb232bf5 added access to objectlist and a produce function to ObjectManager 2022-08-19 12:23:14 +02:00
dd281f8a67 Controller base missing a function 2022-07-28 16:32:12 +02:00
f9e9ff320f Small fixes 2022-07-28 14:55:43 +02:00
f56646d2c3 changed action handling slightly 2022-07-20 16:59:42 +02:00
ef18377cef new Actions 2022-06-29 23:36:45 +02:00
0c057c66b1 added introspection 2022-06-28 18:56:52 +02:00
34c50ce3e2 ignore .vscode 2022-06-28 17:44:53 +02:00
305 changed files with 4834 additions and 4402 deletions

3
.gitignore vendored
View File

@ -10,5 +10,8 @@
.settings
.metadata
# VSCode
.vscode
/build*
/cmake-build*

View File

@ -8,10 +8,74 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
# [v6.0.0]
## Fixes
- Important bugfix in CFDP PDU header format: The entity length field and the transaction sequence
number fields stored the actual length of the field instead of the length minus 1 like specified
in the CFDP standard.
- PUS Health Service: Size check for set health command.
Perform operation completion for announce health command.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/746
- Linux OSAL `getUptime` fix: Check validity of `/proc/uptime` file before reading uptime.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/745
- Small tweak for version getter
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/744
## Added
- add CFDP subsystem ID
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
## Changed
- Bump ETL version to 20.35.14
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748
- Renamed `PCDU_2` subsystem ID to `POWER_SWITCH_IF`.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
- Add new `PowerSwitchIF::SWITCH_UNKNOWN` returnvalue.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
- Assert that `FixedArrayList` is larger than 0 at compile time.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740
## Added
- `EventManager`: Add function to print all listeners.
## Changed
- `EventManager`: Queue depth is configurable now
# [v6.0.0] 2023-02-10
## Fixes
- Mode Service: Add allowed subservice
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/739
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
subservice not working properly.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/736
- Memory leak fixes for the TCP/IP TMTC bridge.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737
- `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval
seconds instead of uptime.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/726
- HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously,
only the X scaling factor was used.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724
- HAL MGM3100 Handler: Z value was previously calculated with bytes of the X value.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/733
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
to false correctly because the `read` and `write` calls were missing.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/728
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
of the correct unsegmented flags (0b11) as specified in the standard.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/727
- TC Scheduler Service 11: Add size and CRC check for contained TC.
Bug: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/719
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/720
- Only delete health table entry in `HealthHelper` destructor if
health table was set.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710
- I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator.
Also properly reset the reply size for successfull transfers and erroneous transfers.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
@ -21,22 +85,83 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `TcpTmTcServer.cpp`: The server was actually not able to handle
CCSDS packets which were clumped together. This has been fixed now.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
- `CServiceHealthCommanding`: Add announce all health info implementation
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
- various fixes related to linux Unittests and memory leaks
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/715
- small fix to allow teardown handling
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/713
- fix compiler warning for fixed array list copy ctor
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/704
- missing include
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/703
- defaultconfig did not build anymore
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/702
- hotfix
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/699
- small fix for helper
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/698
- missing retval conv
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/697
- DHB Countdown Bug
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/693
- doc corrections
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/687
- better error printout
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/686
- include correction
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/683
- better warning for missing include paths
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/676
- Service 11 regression
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/670
## Added
- DHB TM handler `handleDeviceTM` renamed to `handleDeviceTm` and now takes
`util::DataWrapper` as the data input argument. This allows more flexibility in the possible
types of telemetry.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/669
- Add `util::DataWrapper` class inside the `util` module. This is a tagged union which allows
to specify raw data either as a classic C-style raw pointer and size or as a `SerializeIF`
pointer.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/668
- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT`
option on the TCP server. CTOR prototype has changed and expects an explicit
TCP configuration struct to be passed.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/722
- `DleParser` helper class to parse DLE encoded packets from a byte stream.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
- `UioMapper` is able to resolve symlinks now.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
- Add new `UnsignedByteField` class
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
- publish documentation for development and master branch
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/681
- Add Linux HAL options
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/663
- Expand SerializeIF
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/656
- PUS Service 11: Additional Safety Check
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/666
- improvements for auto-formatter script
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/665
- provide a weak print char impl
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/674
## Removed
- now that doc server is up, remove markdown files
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/688
- remove bsp specific code
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/679
## Changes
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
`HealthServiceCfg` now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
- Moved some container returnvalues to dedicated header and namespace
so they can be used without template specification.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707
- Remove default secondary header argument for
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
`uint16_t getTmSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)`
@ -69,10 +194,37 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Make functions `const` where it makes sense
- Add `const char* getName const` abstract function
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
interface itself so it can be re-used more easily. Also add new
abstract function `bool hasDataAtId(store_address_t storeId) const`.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
- Generic TMTC Bridge Update
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734
- comment tweak to event parser can read everything
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/732
- CMakeLists file updates
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/731
- improve srv20 error messages
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/723
- I2C Linux: remove duplicate printout
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/718
- printout handling improvements
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/717
- vec getter, reset for content
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/716
- updates for source sequence counter
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/714
- SP reader getPacketData is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/708
- refactoring of serial drivers for linux
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/705
- Local Pool Update Remove Add Data Ignore Fault Argument
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/701
- Switch to new documentation server
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/694
- Windows Tweaks
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/691
- Refactor Local Pool API
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/667
- group MGM data in local pool vectors
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/664
## CFDP
@ -92,7 +244,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
implementation without an extra component
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
# [v5.0.0] 25.07.2022
# [v5.0.0] 2022-07-25
## Changes
@ -225,6 +377,7 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
Easiest solution for now: Keep this option OFF by default.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
inside `fsfw/version.h`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
@ -239,17 +392,6 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
- `Subsystem`: New API to add table and sequence entries
## HAL
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
lot more sense because each ComIF should be responsible for one SPI bus.
- SPI: Move the empty transfer to update the line polarity to separate function. This means
it is not automatically called when calling the setter function for SPI speed and mode.
The user should call this function after locking the CS mutex if multiple SPI devices with
differing speeds and modes are attached to one bus.
- SPI: Getter functions for SPI speed and mode.
- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
## Fixed
- TCP TMTC Server: `MutexGuard` was not created properly in

View File

@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
# Version file handling #
# ##############################################################################
set(FSFW_VERSION_IF_GIT_FAILS 5)
set(FSFW_VERSION_IF_GIT_FAILS 6)
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
set(FSFW_REVISION_IF_GIT_FAILS 0)
@ -72,7 +72,7 @@ set(FSFW_ETL_LIB_MAJOR_VERSION
20
CACHE STRING "ETL library major version requirement")
set(FSFW_ETL_LIB_VERSION
${FSFW_ETL_LIB_MAJOR_VERSION}.28.0
${FSFW_ETL_LIB_MAJOR_VERSION}.36.0
CACHE STRING "ETL library exact version requirement")
set(FSFW_ETL_LINK_TARGET etl::etl)
@ -80,7 +80,7 @@ set(FSFW_CATCH2_LIB_MAJOR_VERSION
3
CACHE STRING "Catch2 library major version requirement")
set(FSFW_CATCH2_LIB_VERSION
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.1.0
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.3.2
CACHE STRING "Catch2 library exact version requirement")
# Keep this off by default for now. See PR:
@ -122,6 +122,7 @@ if(UNIX)
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add Linux peripheral drivers"
OFF)
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Attempt to add Linux GPIOD drivers" OFF)
option(FSFW_HAL_LINUX_ADD_SERIAL_DRIVERS "Add serial drivers" ON)
endif()
# Optional sources
@ -152,12 +153,12 @@ if(FSFW_BUILD_TESTS)
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
)
# 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
if(NOT Catch2_FOUND)
message(
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)
@ -195,13 +196,13 @@ message(
)
# 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
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
message(
STATUS
"${MSG_PREFIX} No ETL installation was found with find_package. Installing and providing "
"etl with FindPackage")
"${MSG_PREFIX} ETL installation not found. Downloading ETL with FetchContent."
)
include(FetchContent)
FetchContent_Declare(

100
automation/Jenkinsfile vendored
View File

@ -1,45 +1,87 @@
pipeline {
environment {
BUILDDIR = 'cmake-build-tests'
BUILDDIR_HOST = 'cmake-build-tests-host'
BUILDDIR_LINUX = 'cmake-build-tests-linux'
DOCDDIR = 'cmake-build-documentation'
}
agent {
docker {
image 'fsfw-ci:d6'
args '--network host'
args '--network host --sysctl fs.mqueue.msg_max=100'
}
}
stages {
stage('Clean') {
steps {
sh 'rm -rf $BUILDDIR'
}
}
stage('Configure') {
steps {
dir(BUILDDIR) {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
stage('Host') {
stages{
stage('Clean') {
steps {
sh 'rm -rf $BUILDDIR_HOST'
}
}
stage('Configure') {
steps {
dir(BUILDDIR_HOST) {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
}
}
}
stage('Build') {
steps {
dir(BUILDDIR_HOST) {
sh 'cmake --build . -j4'
}
}
}
stage('Unittests') {
steps {
dir(BUILDDIR_HOST) {
sh 'cmake --build . -- fsfw-tests_coverage -j4'
}
}
}
stage('Valgrind') {
steps {
dir(BUILDDIR_HOST) {
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
}
}
}
}
}
stage('Build') {
steps {
dir(BUILDDIR) {
sh 'cmake --build . -j4'
stage('Linux') {
stages{
stage('Clean') {
steps {
sh 'rm -rf $BUILDDIR_LINUX'
}
}
}
}
stage('Unittests') {
steps {
dir(BUILDDIR) {
sh 'cmake --build . -- fsfw-tests_coverage -j4'
stage('Configure') {
steps {
dir(BUILDDIR_LINUX) {
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
}
}
}
}
}
stage('Valgrind') {
steps {
dir(BUILDDIR) {
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
stage('Build') {
steps {
dir(BUILDDIR_LINUX) {
sh 'cmake --build . -j4'
}
}
}
stage('Unittests') {
steps {
dir(BUILDDIR_LINUX) {
sh 'cmake --build . -- fsfw-tests_coverage -j4'
}
}
}
stage('Valgrind') {
steps {
dir(BUILDDIR_LINUX) {
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
}
}
}
}
}
@ -55,7 +97,7 @@ pipeline {
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/development'
}
}
dir(BUILDDIR) {
dir(BUILDDIR_LINUX) {
sshagent(credentials: ['documentation-buildfix']) {
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/development'
}
@ -74,7 +116,7 @@ pipeline {
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/master'
}
}
dir(BUILDDIR) {
dir(BUILDDIR_LINUX) {
sshagent(credentials: ['documentation-buildfix']) {
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/master'
}

View File

@ -140,7 +140,7 @@ find_program( GCOV_PATH gcov )
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
find_program( GCOVR_PATH gcovr )
find_program( CPPFILT_PATH NAMES c++filt )
if(NOT GCOV_PATH)

110
scripts/check_release.py Executable file
View File

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

View File

@ -8,4 +8,4 @@ if(FSFW_ADD_HAL)
add_subdirectory(fsfw_hal)
endif()
add_subdirectory(fsfw_tests)
#add_subdirectory(fsfw_tests)

View File

@ -7,7 +7,7 @@ add_subdirectory(cfdp)
add_subdirectory(container)
add_subdirectory(controller)
add_subdirectory(datapool)
add_subdirectory(datapoollocal)
#add_subdirectory(datapoollocal)
add_subdirectory(devicehandlers)
add_subdirectory(events)
add_subdirectory(fdir)
@ -15,20 +15,22 @@ add_subdirectory(globalfunctions)
add_subdirectory(health)
add_subdirectory(housekeeping)
add_subdirectory(internalerror)
add_subdirectory(introspection)
add_subdirectory(ipc)
add_subdirectory(memory)
add_subdirectory(modes)
add_subdirectory(objectmanager)
add_subdirectory(parameters)
add_subdirectory(power)
#add_subdirectory(power)
add_subdirectory(serialize)
add_subdirectory(serviceinterface)
add_subdirectory(storagemanager)
add_subdirectory(subsystem)
add_subdirectory(tasks)
add_subdirectory(tcdistribution)
add_subdirectory(thermal)
#add_subdirectory(thermal)
add_subdirectory(timemanager)
add_subdirectory(tmtc)
add_subdirectory(tmtcpacket)
add_subdirectory(tmtcservices)
add_subdirectory(filesystem)
@ -36,7 +38,7 @@ add_subdirectory(filesystem)
# Optional
if(FSFW_ADD_MONITORING)
add_subdirectory(monitoring)
#add_subdirectory(monitoring)
endif()
if(FSFW_ADD_PUS)
add_subdirectory(pus)

View File

@ -1,6 +1,7 @@
#ifndef FSFW_INC_FSFW_ACTION_H_
#define FSFW_INC_FSFW_ACTION_H_
#include "fsfw/action/Action.h"
#include "fsfw/action/ActionHelper.h"
#include "fsfw/action/ActionMessage.h"
#include "fsfw/action/CommandActionHelper.h"

View File

@ -0,0 +1,70 @@
#include "Action.h"
#include <fsfw/serialize/SerializeAdapter.h>
#include <fsfw/ipc/MessageQueueIF.h>
#undef Action
#ifdef FSFW_INTROSPECTION
Action::Action() {}
void Action::setEnum(EnumIF *theEnum) {
id = theEnum->getValue();
name = theEnum->getDescription();
}
const char *Action::getName() { return name; }
#else
Action::Action(ActionId_t id) : id(id) {}
#endif
ActionId_t Action::getId() { return id; }
void Action::clear() {
tc = store_address_t();
tcOffset = 0;
commandedBy = MessageQueueIF::NO_QUEUE;
}
void Action::registerParameter(ParameterIF *parameter) { parameterList.push_back(parameter); }
std::vector<ParameterIF *> const *Action::getParameters() const { return &parameterList; }
size_t Action::getSerializedSize() const {
size_t size = SerializeAdapter::getSerializedSize(&id);
for (auto parameter : *getParameters()) {
size += parameter->getSerializedSize();
}
return size;
}
ReturnValue_t Action::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(&id, buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
for (auto parameter : *getParameters()) {
result = parameter->serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
}
return result;
}
ReturnValue_t Action::deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) {
ReturnValue_t result = returnvalue::OK;/* TODO not needed as must have been read before to find this
action = SerializeAdapter::deSerialize(&id, buffer, size, streamEndianness);
if (result != returnvalue::OK) {
return result;
}*/
for (auto parameter : *getParameters()) {
result = parameter->deSerialize(buffer, size, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
}
return result;
}

64
src/fsfw/action/Action.h Normal file
View File

@ -0,0 +1,64 @@
#pragma once
#include <fsfw/introspection/HasTmTcParametersIF.h>
#include <fsfw/serialize/SerializeIF.h>
#include <stdint.h>
#include <vector>
#include "ActionMessage.h"
#ifdef FSFW_INTROSPECTION
#include "../introspection/Enum.h"
#endif
// TODO ActionId_t
class Action : public SerializeIF, public HasTmTcParametersIF {
public:
#ifdef FSFW_INTROSPECTION
Action();
void setEnum(EnumIF *id);
const char *getName();
#else
Action(ActionId_t id);
#endif
store_address_t getTc();
size_t getTcOffset();
// if an action is triggered by a TC, this should be set to be able to handle replies
// TODO make deleting it safe
// TODO integrate with internal commands
store_address_t tc;
size_t tcOffset;
MessageQueueId_t commandedBy;
ActionId_t getId();
void clear();
[[nodiscard]] virtual ReturnValue_t handle() = 0;
void registerParameter(ParameterIF *parameter) override;
std::vector<ParameterIF *> const *getParameters() const override;
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
size_t getSerializedSize() const override;
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override;
private:
ActionId_t id;
#ifdef FSFW_INTROSPECTION
const char *name;
#endif
std::vector<ParameterIF *> parameterList;
};

View File

@ -1,3 +1,6 @@
#include <fsfw/serialize/SerializeAdapter.h>
#include <fsfw/tmtc/TmMessage.h>
#include "fsfw/action.h"
#include "fsfw/ipc/MessageQueueSenderIF.h"
#include "fsfw/objectmanager/ObjectManager.h"
@ -10,8 +13,8 @@ ActionHelper::~ActionHelper() = default;
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
ActionId_t currentAction = ActionMessage::getActionId(command);
prepareExecution(command->getSender(), currentAction, ActionMessage::getStoreId(command));
prepareExecution(command->getSender(), ActionMessage::getOffset(command),
ActionMessage::getStoreId(command));
return returnvalue::OK;
} else {
return CommandMessage::UNKNOWN_COMMAND;
@ -23,6 +26,12 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
if (ipcStore == nullptr) {
return returnvalue::FAILED;
}
tmManager = ObjectManager::instance()->get<TmManager>(objects::TM_MANAGER);
if (tmManager == nullptr) {
return returnvalue::FAILED;
}
if (queueToUse_ != nullptr) {
setQueueToUse(queueToUse_);
}
@ -57,28 +66,89 @@ void ActionHelper::finish(bool success, MessageQueueId_t reportTo, ActionId_t co
void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
MessageQueueIF const* ActionHelper::getQueue() const { return queueToUse; }
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, size_t offset,
store_address_t dataAddress) {
const uint8_t* dataPtr = nullptr;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
const uint8_t* tcData = nullptr;
size_t tcDataSize = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &tcData, &tcDataSize);
if (result != returnvalue::OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, result);
// queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
ipcStore->deleteData(dataAddress);
FsfwProtocolHeader header;
const uint8_t* dataPtr = tcData + offset;
size_t size = tcDataSize - offset;
result = header.deSerialize(&dataPtr, &size, SerializeIF::Endianness::NETWORK);
if (header.getInterface() != HasActionsIF::INTERFACE_ID or
header.getFunction() != HasActionsIF::Functions::EXECUTE_ACTION) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, result);
// queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
ActionId_t actionId;
result =
SerializeAdapter::deSerialize(&actionId, &dataPtr, &size, SerializeIF::Endianness::NETWORK);
if (result != returnvalue::OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, result);
// queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
auto actionIter = actionMap.find(actionId);
if (actionIter == actionMap.end()) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::INVALID_ACTION_ID);
// queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
Action* action = actionIter->second;
result = action->deSerialize(&dataPtr, &size, SerializeIF::Endianness::NETWORK);
if ((result != returnvalue::OK) || (size != 0)) { // TODO write unittest for second condition
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::INVALID_PARAMETERS);
// queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
// TODO call action->check()
action->commandedBy = commandedBy;
result = owner->executeAction(action);
// TODO safetify dynamic cast
result = tmManager->sendTmPacket(dynamic_cast<SystemObjectIF*>(owner)->getObjectId(), HasActionsIF::INTERFACE_ID,
HasActionsIF::Functions::EXECUTION_IN_PROGRESS, action,
dataAddress, offset);
if (result != returnvalue::OK) {
sif::error << "replying action failed " << std::hex << result << std::dec << std::endl;
}
// ipcStore->deleteData(dataAddress);
if (result == HasActionsIF::EXECUTION_FINISHED) {
CommandMessage reply;
ActionMessage::setCompletionReply(&reply, actionId, true, result);
queueToUse->sendMessage(commandedBy, &reply);
// queueToUse->sendMessage(commandedBy, &reply);
}
if (result != returnvalue::OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
// queueToUse->sendMessage(commandedBy, &reply);
return;
}
}
@ -163,3 +233,11 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t rep
}
return result;
}
void ActionHelper::registerAction(Action* action) {
// TODO error handling
ActionId_t id = action->getId();
actionMap.emplace(id, action);
}
std::map<ActionId_t, Action*> const* ActionHelper::getActionMap() { return &actionMap; }

View File

@ -1,9 +1,12 @@
#ifndef FSFW_ACTION_ACTIONHELPER_H_
#define FSFW_ACTION_ACTIONHELPER_H_
#include <fsfw/tmtc/TmManager.h>
#include "ActionMessage.h"
#include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/serialize/SerializeIF.h"
/**
* @brief Action Helper is a helper class which handles action messages
*
@ -98,6 +101,16 @@ class ActionHelper {
*/
void setQueueToUse(MessageQueueIF* queue);
/**
* Needed so templateAction can check if actionHelper was
* contructed already to aid in debuggig a nasty coding error.
*/
MessageQueueIF const* getQueue() const;
void registerAction(Action* action);
std::map<ActionId_t, Action*> const* getActionMap();
protected:
//! Increase of value of this per step
static const uint8_t STEP_OFFSET = 1;
@ -106,8 +119,11 @@ class ActionHelper {
//! Queue to be used as response sender, has to be set in ctor or with
//! setQueueToUse
MessageQueueIF* queueToUse;
TmManager* tmManager = nullptr;
//! Pointer to an IPC Store, initialized during construction or
StorageManagerIF* ipcStore = nullptr;
//! Map of all implemented Actions
std::map<ActionId_t, Action*> actionMap;
/**
* Internal function called by handleActionMessage
@ -115,7 +131,7 @@ class ActionHelper {
* @param actionId ID of action to be done
* @param dataAddress Address of additional data in IPC Store
*/
virtual void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
virtual void prepareExecution(MessageQueueId_t commandedBy, size_t offset,
store_address_t dataAddress);
/**
* @brief Default implementation is empty.

View File

@ -6,14 +6,14 @@ ActionMessage::ActionMessage() = default;
ActionMessage::~ActionMessage() = default;
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
void ActionMessage::setCommand(CommandMessage* message, size_t offset,
store_address_t parameters) {
message->setCommand(EXECUTE_ACTION);
message->setParameter(fid);
message->setParameter(offset);
message->setParameter2(parameters.raw);
}
ActionId_t ActionMessage::getActionId(const CommandMessage* message) {
size_t ActionMessage::getOffset(const CommandMessage* message) {
return ActionId_t(message->getParameter());
}

View File

@ -27,9 +27,9 @@ class ActionMessage {
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
virtual ~ActionMessage();
static void setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters);
static void setCommand(CommandMessage* message, size_t offset, store_address_t parameters);
static ActionId_t getActionId(const CommandMessage* message);
static size_t getOffset(const CommandMessage* message);
static store_address_t getStoreId(const CommandMessage* message);
static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step,

View File

@ -1,3 +1,3 @@
target_sources(
${LIB_FSFW_NAME} PRIVATE ActionHelper.cpp ActionMessage.cpp
${LIB_FSFW_NAME} PRIVATE Action.cpp ActionHelper.cpp ActionMessage.cpp
CommandActionHelper.cpp SimpleActionHelper.cpp)

View File

@ -74,24 +74,24 @@ ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
switch (reply->getCommand()) {
case ActionMessage::COMPLETION_SUCCESS:
commandCount--;
owner->completionSuccessfulReceived(ActionMessage::getActionId(reply));
// owner->completionSuccessfulReceived(ActionMessage::getActionId(reply)); TODO
return returnvalue::OK;
case ActionMessage::COMPLETION_FAILED:
commandCount--;
owner->completionFailedReceived(ActionMessage::getActionId(reply),
ActionMessage::getReturnCode(reply));
// owner->completionFailedReceived(ActionMessage::getActionId(reply),
// ActionMessage::getReturnCode(reply));
return returnvalue::OK;
case ActionMessage::STEP_SUCCESS:
owner->stepSuccessfulReceived(ActionMessage::getActionId(reply),
ActionMessage::getStep(reply));
// owner->stepSuccessfulReceived(ActionMessage::getActionId(reply),
// ActionMessage::getStep(reply));
return returnvalue::OK;
case ActionMessage::STEP_FAILED:
commandCount--;
owner->stepFailedReceived(ActionMessage::getActionId(reply), ActionMessage::getStep(reply),
ActionMessage::getReturnCode(reply));
// owner->stepFailedReceived(ActionMessage::getActionId(reply), ActionMessage::getStep(reply),
// ActionMessage::getReturnCode(reply));
return returnvalue::OK;
case ActionMessage::DATA_REPLY:
extractDataForOwner(ActionMessage::getActionId(reply), ActionMessage::getStoreId(reply));
// extractDataForOwner(ActionMessage::getActionId(reply), ActionMessage::getStoreId(reply));
return returnvalue::OK;
default:
return returnvalue::FAILED;

View File

@ -16,8 +16,8 @@ class CommandActionHelper {
public:
explicit CommandActionHelper(CommandsActionsIF* owner);
virtual ~CommandActionHelper();
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
const uint8_t* data = nullptr, uint32_t size = 0);
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
uint32_t size);
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
ReturnValue_t initialize();
ReturnValue_t handleReply(CommandMessage* reply);

View File

@ -1,11 +1,13 @@
#ifndef FSFW_ACTION_HASACTIONSIF_H_
#define FSFW_ACTION_HASACTIONSIF_H_
#include "Action.h"
#include "ActionHelper.h"
#include "ActionMessage.h"
#include "SimpleActionHelper.h"
#include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/returnvalues/returnvalue.h"
#include <fsfw/tmtc/FsfwProtocolHeader.h>
/**
* @brief
@ -40,12 +42,18 @@ class HasActionsIF {
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4);
enum Functions : FsfwProtocolHeader::FunctionType_t { EXECUTE_ACTION, EXECUTION_IN_PROGRESS };
virtual ~HasActionsIF() = default;
/**
* Function to get the MessageQueueId_t of the implementing object
* @return MessageQueueId_t of the object
*
*/
[[nodiscard]] virtual MessageQueueId_t getCommandQueue() const = 0;
virtual ActionHelper* getActionHelper() = 0;
/**
* Execute or initialize the execution of a certain function.
* The ActionHelpers will execute this function and behave differently
@ -55,8 +63,7 @@ class HasActionsIF {
* -@c EXECUTION_FINISHED Finish reply will be generated
* -@c Not returnvalue::OK Step failure reply will be generated
*/
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) = 0;
virtual ReturnValue_t executeAction(Action* action) = 0;
};
#endif /* FSFW_ACTION_HASACTIONSIF_H_ */

View File

@ -1,4 +1,6 @@
#include "fsfw/action.h"
#include <fsfw/serialize/SerializeAdapter.h>
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
: ActionHelper(setOwner, useThisQueue), isExecuting(false) {}
@ -30,25 +32,57 @@ void SimpleActionHelper::resetHelper() {
lastCommander = 0;
}
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress) {
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, size_t offset,
store_address_t dataAddress) {
CommandMessage reply;
if (isExecuting) {
ipcStore->deleteData(dataAddress);
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::IS_BUSY);
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, HasActionsIF::IS_BUSY);
queueToUse->sendMessage(commandedBy, &reply);
}
const uint8_t* dataPtr = nullptr;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != returnvalue::OK) {
ActionMessage::setStepReply(&reply, actionId, 0, result);
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
lastCommander = commandedBy;
lastAction = actionId;
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
dataPtr += offset;
size -=offset;
ActionId_t actionId;
result = SerializeAdapter::deSerialize(&actionId, &dataPtr, &size, SerializeIF::Endianness::NETWORK);
if (result != returnvalue::OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
auto actionIter = actionMap.find(actionId);
if (actionIter == actionMap.end()){
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::INVALID_ACTION_ID);
queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
Action* action = actionIter->second;
result = action->deSerialize(&dataPtr, &size, SerializeIF::Endianness::NETWORK);
if ((result != returnvalue::OK) or (size != 0)) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::INVALID_PARAMETERS);
queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
result = action->handle();
ipcStore->deleteData(dataAddress);
switch (result) {
case returnvalue::OK:

View File

@ -17,8 +17,8 @@ class SimpleActionHelper : public ActionHelper {
ReturnValue_t reportData(SerializeIF* data);
protected:
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress) override;
virtual void prepareExecution(MessageQueueId_t commandedBy, size_t offset,
store_address_t dataAddress) override;
void resetHelper() override;
private:

View File

@ -0,0 +1,29 @@
#pragma once
#include "Action.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
template <class owner_class, class action_type, class ActionEnum>
class TemplateAction : public Action {
public:
#ifdef FSFW_INTROSPECTION
TemplateAction(owner_class *myOwner, ActionEnum id) : Action(), myOwner(myOwner) {
Action::setEnum(&id);
if (myOwner->getActionHelper() == nullptr) {
sif::error
<< "TemplateAction::TemplateAction: Action instances need to be created (ie located) after the actionHelper instance."
<< "Program will segfault now..." << std::endl;
}
myOwner->getActionHelper()->registerAction(this);
}
#else
TemplateAction(owner_class *myOwner, ActionEnum id) : Action((uint32_t)id), myOwner(myOwner) {
myOwner->getActionHelper()->registerAction(this);
}
#endif
ReturnValue_t handle() override { return myOwner->handleAction(dynamic_cast<action_type *>(this)); }
private:
owner_class *myOwner;
};

View File

@ -2,10 +2,7 @@
#define FSFW_CFDP_H
#include "cfdp/definitions.h"
#include "cfdp/handler/CfdpHandler.h"
#include "cfdp/handler/DestHandler.h"
#include "cfdp/handler/FaultHandlerBase.h"
#include "cfdp/helpers.h"
#include "cfdp/tlv/Lv.h"
#include "cfdp/tlv/StringLv.h"
#include "cfdp/tlv/Tlv.h"

View File

@ -51,8 +51,9 @@ class VarLenField : public SerializeIF {
return os;
}
#endif
private:
using SerializeIF::deSerialize; // we overloaded above, so this is needed to uncofuse the
// compiler
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override;

View File

@ -1,3 +1 @@
target_sources(
${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
FaultHandlerBase.cpp UserBase.cpp CfdpHandler.cpp)
target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp)

View File

@ -1,134 +0,0 @@
#include "CfdpHandler.h"
#include "fsfw/cfdp/pdu/AckPduReader.h"
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
using namespace returnvalue;
using namespace cfdp;
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg)
: SystemObject(fsfwParams.objectId),
msgQueue(fsfwParams.msgQueue),
destHandler(
DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler),
cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList,
cfdpCfg.lostSegmentsList),
FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore,
fsfwParams.tmStore)) {
destHandler.setMsgQueue(msgQueue);
}
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const {
return destHandler.getDestHandlerParams().cfg.localId.getValue();
}
[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue.getId(); }
ReturnValue_t CfdpHandler::initialize() {
ReturnValue_t result = destHandler.initialize();
if (result != OK) {
return result;
}
tcStore = destHandler.getTcStore();
tmStore = destHandler.getTmStore();
return SystemObject::initialize();
}
ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) {
// TODO: Receive TC packets and route them to source and dest handler, depending on which is
// correct or more appropriate
ReturnValue_t status;
ReturnValue_t result = OK;
TmTcMessage tmtcMsg;
for (status = msgQueue.receiveMessage(&tmtcMsg); status == returnvalue::OK;
status = msgQueue.receiveMessage(&tmtcMsg)) {
result = handleCfdpPacket(tmtcMsg);
if (result != OK) {
status = result;
}
}
auto& fsmRes = destHandler.performStateMachine();
// TODO: Error handling?
while (fsmRes.callStatus == CallStatus::CALL_AGAIN) {
destHandler.performStateMachine();
// TODO: Error handling?
}
return status;
}
ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
auto accessorPair = tcStore->getData(msg.getStorageId());
if (accessorPair.first != OK) {
return accessorPair.first;
}
PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size());
ReturnValue_t result = reader.parseData();
if (result != returnvalue::OK) {
return INVALID_PDU_FORMAT;
}
// The CFDP distributor should have taken care of ensuring the destination ID is correct
PduType type = reader.getPduType();
// Only the destination handler can process these PDUs
if (type == PduType::FILE_DATA) {
// Disable auto-deletion of packet
accessorPair.second.release();
PacketInfo info(type, msg.getStorageId());
result = destHandler.passPacket(info);
} else {
// Route depending on PDU type and directive type if applicable. It retrieves directive type
// from the raw stream for better performance (with sanity and directive code check).
// The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding
// procedure.
// PDU header only. Invalid supplied data. A directive packet should have a valid data field
// with at least one byte being the directive code
const uint8_t* pduDataField = reader.getPduDataField();
if (pduDataField == nullptr) {
return INVALID_PDU_FORMAT;
}
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
return INVALID_DIRECTIVE_FIELD;
}
auto directive = static_cast<FileDirective>(pduDataField[0]);
auto passToDestHandler = [&]() {
accessorPair.second.release();
PacketInfo info(type, msg.getStorageId(), directive);
result = destHandler.passPacket(info);
};
auto passToSourceHandler = [&]() {
};
if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or
directive == FileDirective::PROMPT) {
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
// the destination handler
passToDestHandler();
} else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or
directive == FileDirective::KEEP_ALIVE) {
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
// the source handler
passToSourceHandler();
} else if (directive == FileDirective::ACK) {
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
// the source handler, for a Finished PDU, it is passed to the destination handler.
FileDirective ackedDirective;
if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) {
return INVALID_ACK_DIRECTIVE_FIELDS;
}
if (ackedDirective == FileDirective::EOF_DIRECTIVE) {
passToSourceHandler();
} else if (ackedDirective == FileDirective::FINISH) {
passToDestHandler();
}
}
}
return result;
}

View File

@ -1,71 +0,0 @@
#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
#include <utility>
#include "fsfw/cfdp/handler/DestHandler.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
struct FsfwHandlerParams {
FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest,
StorageManagerIF& tcStore, StorageManagerIF& tmStore, MessageQueueIF& msgQueue)
: objectId(objectId),
vfs(vfs),
packetDest(packetDest),
tcStore(tcStore),
tmStore(tmStore),
msgQueue(msgQueue) {}
object_id_t objectId{};
HasFileSystemIF& vfs;
AcceptsTelemetryIF& packetDest;
StorageManagerIF& tcStore;
StorageManagerIF& tmStore;
MessageQueueIF& msgQueue;
};
struct CfdpHandlerCfg {
CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg,
cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler,
cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList,
cfdp::RemoteConfigTableIF& remoteCfgProvider)
: id(std::move(localId)),
indicCfg(indicationCfg),
packetInfoList(packetInfo),
lostSegmentsList(lostSegmentsList),
remoteCfgProvider(remoteCfgProvider),
userHandler(userHandler),
faultHandler(userFaultHandler) {}
cfdp::EntityId id;
cfdp::IndicationCfg indicCfg;
cfdp::PacketInfoListBase& packetInfoList;
cfdp::LostSegmentsListBase& lostSegmentsList;
cfdp::RemoteConfigTableIF& remoteCfgProvider;
cfdp::UserBase& userHandler;
cfdp::FaultHandlerBase& faultHandler;
};
class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF {
public:
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg);
[[nodiscard]] const char* getName() const override;
[[nodiscard]] uint32_t getIdentifier() const override;
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t operationCode) override;
private:
MessageQueueIF& msgQueue;
cfdp::DestHandler destHandler;
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
ReturnValue_t handleCfdpPacket(TmTcMessage& msg);
};
#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H

View File

@ -1,490 +0,0 @@
#include "DestHandler.h"
#include <etl/crc32.h>
#include <utility>
#include "fsfw/FSFW.h"
#include "fsfw/cfdp/pdu/EofPduReader.h"
#include "fsfw/cfdp/pdu/FileDataReader.h"
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
#include "fsfw/objectmanager.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
using namespace returnvalue;
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
: tlvVec(params.maxTlvsInOnePdu),
userTlvVec(params.maxTlvsInOnePdu),
dp(std::move(params)),
fp(fsfwParams),
tp(params.maxFilenameLen) {
tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
}
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
ReturnValue_t result;
uint8_t errorIdx = 0;
fsmRes.resetOfIteration();
if (fsmRes.step == TransactionStep::IDLE) {
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
infoIter->directiveType == FileDirective::METADATA) {
result = handleMetadataPdu(*infoIter);
checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
dp.packetListRef.erase(infoIter++);
} else {
infoIter++;
}
}
if (fsmRes.step == TransactionStep::IDLE) {
// To decrease the already high complexity of the software, all packets arriving before
// a metadata PDU are deleted.
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
fp.tcStore->deleteData(infoIter->storeId);
infoIter++;
}
dp.packetListRef.clear();
}
if (fsmRes.step != TransactionStep::IDLE) {
fsmRes.callStatus = CallStatus::CALL_AGAIN;
}
return updateFsmRes(errorIdx);
}
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
if (infoIter->pduType == PduType::FILE_DATA) {
result = handleFileDataPdu(*infoIter);
checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
dp.packetListRef.erase(infoIter++);
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
// TODO: Support for check timer missing
result = handleEofPdu(*infoIter);
checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
dp.packetListRef.erase(infoIter++);
} else {
infoIter++;
}
}
}
if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) {
result = handleTransferCompletion();
checkAndHandleError(result, errorIdx);
}
if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) {
result = sendFinishedPdu();
checkAndHandleError(result, errorIdx);
finish();
}
return updateFsmRes(errorIdx);
}
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
// TODO: Will be implemented at a later stage
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl;
#endif
}
return updateFsmRes(errorIdx);
}
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
if (dp.packetListRef.full()) {
return FAILED;
}
dp.packetListRef.push_back(packet);
return OK;
}
ReturnValue_t cfdp::DestHandler::initialize() {
if (fp.tmStore == nullptr) {
fp.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
if (fp.tmStore == nullptr) {
return FAILED;
}
}
if (fp.tcStore == nullptr) {
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (fp.tcStore == nullptr) {
return FAILED;
}
}
if (fp.msgQueue == nullptr) {
return FAILED;
}
return OK;
}
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
// Process metadata PDU
auto constAccessorPair = fp.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
}
cfdp::StringLv sourceFileName;
cfdp::StringLv destFileName;
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
metadataInfo);
ReturnValue_t result = reader.parseData();
// TODO: The standard does not really specify what happens if this kind of error happens
// I think it might be a good idea to cache some sort of error code, which
// is translated into a warning and/or event by an upper layer
if (result != OK) {
return handleMetadataParseError(result, constAccessorPair.second.data(),
constAccessorPair.second.size());
}
return startTransaction(reader, metadataInfo);
}
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
// Process file data PDU
auto constAccessorPair = fp.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
}
cfdp::FileSize offset;
FileDataInfo fdInfo(offset);
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
ReturnValue_t result = reader.parseData();
if (result != OK) {
return result;
}
size_t fileSegmentLen = 0;
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen);
fileOpParams.offset = offset.value();
if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) {
FileSegmentRecvdParams segParams;
segParams.offset = offset.value();
segParams.id = tp.transactionId;
segParams.length = fileSegmentLen;
segParams.recContState = fdInfo.getRecordContinuationState();
size_t segmentMetadatLen = 0;
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
dp.user.fileSegmentRecvdIndication(segParams);
}
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
if (offset.value() + fileSegmentLen > tp.progress) {
tp.progress = offset.value() + fileSegmentLen;
}
if (result != returnvalue::OK) {
// TODO: Proper Error handling
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "File write error" << std::endl;
#endif
} else {
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
}
return result;
}
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
// Process EOF PDU
auto constAccessorPair = fp.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
}
EofInfo eofInfo(nullptr);
EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo);
ReturnValue_t result = reader.parseData();
if (result != OK) {
return result;
}
// TODO: Error handling
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
tp.crc = eofInfo.getChecksum();
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
if (fileSizeFromEof > tp.progress) {
// TODO: File size error
}
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
}
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
dp.user.eofRecvIndication(getTransactionId());
}
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
}
}
return returnvalue::OK;
}
ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
const uint8_t* rawData, size_t maxSize) {
// TODO: try to extract destination ID for error
// TODO: Invalid metadata PDU.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl;
#else
#endif
PduHeaderReader headerReader(rawData, maxSize);
result = headerReader.parseData();
if (result != OK) {
// TODO: Now this really should not happen. Warning or error,
// yield or cache appropriate returnvalue
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Parsing Header failed" << std::endl;
#else
#endif
// TODO: Trigger appropriate event
return result;
}
cfdp::EntityId destId;
headerReader.getDestId(destId);
RemoteEntityCfg* remoteCfg;
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
// TODO: No remote config for dest ID. I consider this a configuration error, which is not
// covered by the standard.
// Warning or error, yield or cache appropriate returnvalue
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "No remote config exists for destination ID" << std::endl;
#else
#endif
// TODO: Trigger appropriate event
}
// TODO: Appropriate returnvalue?
return returnvalue::FAILED;
}
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
if (fsmRes.state != CfdpStates::IDLE) {
// According to standard, discard metadata PDU if we are busy
return 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;
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
if (sourceNameSize > tp.sourceName.size()) {
// TODO: Warning, event etc.
return FAILED;
}
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
tp.sourceName[sourceNameSize] = '\0';
size_t destNameSize = 0;
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
if (destNameSize > tp.destName.size()) {
// TODO: Warning, event etc.
return FAILED;
}
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
tp.destName[destNameSize] = '\0';
reader.fillConfig(tp.pduConf);
tp.pduConf.direction = Direction::TOWARDS_SENDER;
tp.transactionId.entityId = tp.pduConf.sourceId;
tp.transactionId.seqNum = tp.pduConf.seqNum;
if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) {
// TODO: Warning, event etc.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler" << __func__
<< ": No remote configuration found for destination ID "
<< tp.pduConf.sourceId.getValue() << std::endl;
#endif
return FAILED;
}
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
// so there is no need to create a file or truncate an existing file
if (destNameSize > 0 and sourceNameSize > 0) {
FilesystemParams fparams(tp.destName.data());
// TODO: Filesystem errors?
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
}
}
}
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
params.fileSize = tp.fileSize.getSize();
params.destFileName = tp.destName.data();
params.sourceFileName = tp.sourceName.data();
params.msgsToUserArray = dynamic_cast<MessageToUserTlv*>(userTlvVec.data());
params.msgsToUserLen = info.getOptionsLen();
dp.user.metadataRecvdIndication(params);
return result;
}
cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
ReturnValue_t result;
if (tp.checksumType != ChecksumType::NULL_CHECKSUM) {
result = checksumVerification();
if (result != OK) {
// TODO: Warning / error handling?
}
} else {
tp.conditionCode = ConditionCode::NO_ERROR;
}
result = noticeOfCompletion();
if (result != OK) {
}
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
if (tp.closureRequested) {
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
} else {
finish();
}
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
}
return OK;
}
void cfdp::DestHandler::finish() {
tp.reset();
dp.packetListRef.clear();
fsmRes.state = CfdpStates::IDLE;
fsmRes.step = TransactionStep::IDLE;
}
ReturnValue_t cfdp::DestHandler::checksumVerification() {
std::array<uint8_t, 1024> buf{};
// TODO: Checksum verification and notice of completion
etl::crc32 crcCalc;
uint64_t currentOffset = 0;
FileOpParams params(tp.destName.data(), tp.fileSize.value());
while (currentOffset < tp.fileSize.value()) {
uint64_t readLen;
if (currentOffset + buf.size() > tp.fileSize.value()) {
readLen = tp.fileSize.value() - currentOffset;
} else {
readLen = buf.size();
}
if (readLen > 0) {
params.offset = currentOffset;
params.size = readLen;
auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size());
if (result != OK) {
// TODO: I think this is a case for a filestore rejection, but it might sense to print
// a warning or trigger an event because this should generally not happen
return FAILED;
}
crcCalc.add(buf.begin(), buf.begin() + readLen);
}
currentOffset += readLen;
}
uint32_t value = crcCalc.value();
if (value == tp.crc) {
tp.conditionCode = ConditionCode::NO_ERROR;
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
} else {
// TODO: Proper error handling
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl;
#endif
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
}
return OK;
}
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
if (dp.cfg.indicCfg.transactionFinishedIndicRequired) {
TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode,
tp.deliveryStatus);
dp.user.transactionFinishedIndication(params);
}
return OK;
}
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
FinishPduCreator finishedPdu(tp.pduConf, info);
store_address_t storeId;
uint8_t* dataPtr = nullptr;
ReturnValue_t result =
fp.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
#endif
fp.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
return result;
}
size_t serLen = 0;
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
<< std::endl;
#endif
fp.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
return result;
}
TmTcMessage msg(storeId);
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
#endif
fp.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
return result;
}
fsmRes.packetsSent++;
return OK;
}
cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const {
return fsmRes.step;
}
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) {
fsmRes.errors = errors;
fsmRes.result = OK;
if (fsmRes.errors > 0) {
fsmRes.result = FAILED;
}
return fsmRes;
}
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
if (result != OK and errorIdx < 3) {
fsmRes.errorCodes[errorIdx] = result;
errorIdx++;
}
}
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
fp.eventReporter = &reporter;
}
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }

View File

@ -1,202 +0,0 @@
#ifndef FSFW_CFDP_CFDPDESTHANDLER_H
#define FSFW_CFDP_CFDPDESTHANDLER_H
#include <etl/list.h>
#include <etl/set.h>
#include <optional>
#include <utility>
#include "RemoteConfigTableIF.h"
#include "UserBase.h"
#include "defs.h"
#include "fsfw/cfdp/handler/mib.h"
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
#include "fsfw/cfdp/pdu/PduConfig.h"
#include "fsfw/container/DynamicFIFO.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
#include "fsfw/storagemanager/storeAddress.h"
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
namespace cfdp {
struct PacketInfo {
PacketInfo(PduType type, store_address_t storeId,
std::optional<FileDirective> directive = std::nullopt)
: pduType(type), directiveType(directive), storeId(storeId) {}
PduType pduType = PduType::FILE_DATA;
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
store_address_t storeId = store_address_t::invalid();
PacketInfo() = default;
};
template <size_t SIZE>
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
template <size_t SIZE>
using PacketInfoList = etl::list<PacketInfo, SIZE>;
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
using PacketInfoListBase = etl::ilist<PacketInfo>;
struct DestHandlerParams {
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
PacketInfoListBase& packetList,
// TODO: This container can potentially take tons of space. For a better
// memory efficient implementation, an additional abstraction could be
// be used so users can use uint32_t as the pair type
LostSegmentsListBase& lostSegmentsContainer)
: cfg(std::move(cfg)),
user(user),
remoteCfgTable(remoteCfgTable),
packetListRef(packetList),
lostSegmentsContainer(lostSegmentsContainer) {}
LocalEntityCfg cfg;
UserBase& user;
RemoteConfigTableIF& remoteCfgTable;
PacketInfoListBase& packetListRef;
LostSegmentsListBase& lostSegmentsContainer;
uint8_t maxTlvsInOnePdu = 10;
size_t maxFilenameLen = 255;
};
struct FsfwParams {
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore,
StorageManagerIF& tmStore)
: FsfwParams(packetDest, msgQueue, eventReporter) {
this->tcStore = &tcStore;
this->tmStore = &tmStore;
}
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
EventReportingProxyIF* eventReporter)
: packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {}
AcceptsTelemetryIF& packetDest;
MessageQueueIF* msgQueue;
EventReportingProxyIF* eventReporter = nullptr;
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
};
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
class DestHandler {
public:
enum class TransactionStep {
IDLE = 0,
TRANSACTION_START = 1,
RECEIVING_FILE_DATA_PDUS = 2,
SENDING_ACK_PDU = 3,
TRANSFER_COMPLETION = 4,
SENDING_FINISHED_PDU = 5
};
struct FsmResult {
public:
ReturnValue_t result = returnvalue::OK;
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
TransactionStep step = TransactionStep::IDLE;
CfdpStates state = CfdpStates::IDLE;
uint32_t packetsSent = 0;
uint8_t errors = 0;
std::array<ReturnValue_t, 3> errorCodes = {};
void resetOfIteration() {
result = returnvalue::OK;
callStatus = CallStatus::CALL_AFTER_DELAY;
packetsSent = 0;
errors = 0;
errorCodes.fill(returnvalue::OK);
}
};
/**
* Will be returned if it is advisable to call the state machine operation call again
*/
ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2);
ReturnValue_t FAILURE = returnvalue::makeCode(0, 3);
explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams);
/**
*
* @return
* - @c returnvalue::OK State machine OK for this execution cycle
* - @c CALL_FSM_AGAIN State machine should be called again.
*/
const FsmResult& performStateMachine();
void setMsgQueue(MessageQueueIF& queue);
void setEventReporter(EventReportingProxyIF& reporter);
ReturnValue_t passPacket(PacketInfo packet);
ReturnValue_t initialize();
[[nodiscard]] CfdpStates getCfdpState() const;
[[nodiscard]] TransactionStep getTransactionStep() const;
[[nodiscard]] const TransactionId& getTransactionId() const;
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
[[nodiscard]] StorageManagerIF* getTcStore() const;
[[nodiscard]] StorageManagerIF* getTmStore() const;
private:
struct TransactionParams {
// Initialize char vectors with length + 1 for 0 termination
explicit TransactionParams(size_t maxFileNameLen)
: sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {}
void reset() {
pduConf = PduConfig();
transactionId = TransactionId();
std::fill(sourceName.begin(), sourceName.end(), '\0');
std::fill(destName.begin(), destName.end(), '\0');
fileSize.setFileSize(0, false);
conditionCode = ConditionCode::NO_ERROR;
deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
crc = 0;
progress = 0;
remoteCfg = nullptr;
closureRequested = false;
checksumType = ChecksumType::NULL_CHECKSUM;
}
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
bool closureRequested = false;
std::vector<char> sourceName;
std::vector<char> destName;
cfdp::FileSize fileSize;
TransactionId transactionId;
PduConfig pduConf;
ConditionCode conditionCode = ConditionCode::NO_ERROR;
FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
uint32_t crc = 0;
uint64_t progress = 0;
RemoteEntityCfg* remoteCfg = nullptr;
};
std::vector<cfdp::Tlv> tlvVec;
std::vector<cfdp::Tlv> userTlvVec;
DestHandlerParams dp;
FsfwParams fp;
TransactionParams tp;
FsmResult fsmRes;
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
ReturnValue_t handleEofPdu(const PacketInfo& info);
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
size_t maxSize);
ReturnValue_t handleTransferCompletion();
ReturnValue_t sendFinishedPdu();
ReturnValue_t noticeOfCompletion();
ReturnValue_t checksumVerification();
const FsmResult& updateFsmRes(uint8_t errors);
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
void finish();
};
} // namespace cfdp
#endif // FSFW_CFDP_CFDPDESTHANDLER_H

View File

@ -1 +0,0 @@
#include "SourceHandler.h"

View File

@ -1,6 +0,0 @@
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
class SourceHandler {};
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H

View File

@ -5,15 +5,5 @@ namespace cfdp {
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
static constexpr uint8_t SSID = SUBSYSTEM_ID::CFDP;
namespace events {
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 SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
} // namespace events
} // namespace cfdp
}
#endif // FSFW_CFDP_HANDLER_DEFS_H

View File

@ -24,8 +24,8 @@ ReturnValue_t HeaderCreator::serialize(uint8_t **buffer, size_t *size, size_t ma
*buffer += 1;
**buffer = pduDataFieldLen & 0x00ff;
*buffer += 1;
**buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 |
pduConf.seqNum.getWidth();
**buffer = segmentationCtrl << 7 | ((pduConf.sourceId.getWidth() - 1) << 4) |
segmentMetadataFlag << 3 | (pduConf.seqNum.getWidth() - 1);
*buffer += 1;
*size += 4;
ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness);

View File

@ -78,11 +78,11 @@ cfdp::SegmentationControl PduHeaderReader::getSegmentationControl() const {
}
cfdp::WidthInBytes PduHeaderReader::getLenEntityIds() const {
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte >> 4) & 0x07);
return static_cast<cfdp::WidthInBytes>(((pointers.fixedHeader->fourthByte >> 4) & 0b111) + 1);
}
cfdp::WidthInBytes PduHeaderReader::getLenSeqNum() const {
return static_cast<cfdp::WidthInBytes>(pointers.fixedHeader->fourthByte & 0x07);
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte & 0b111) + 1);
}
cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const {

View File

@ -23,6 +23,8 @@ class EntityIdTlv : public TlvIF {
*/
ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness);
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
// the compiler
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;

View File

@ -26,6 +26,8 @@ class FilestoreRequestTlv : public cfdp::FilestoreTlvBase {
*/
ReturnValue_t deSerialize(cfdp::Tlv &tlv, Endianness endianness);
using SerializeIF::deSerialize; // we overloaded above, so this is needed to uncofuse the
// compiler
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override;

View File

@ -29,6 +29,8 @@ class FilestoreResponseTlv : public cfdp::FilestoreTlvBase {
*/
ReturnValue_t deSerialize(const cfdp::Tlv& tlv, Endianness endianness);
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
// the compiler
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;

View File

@ -4,6 +4,7 @@
#include "../returnvalues/returnvalue.h"
#include "../serialize/SerializeAdapter.h"
#include "../serialize/SerializeIF.h"
#include "definitions.h"
/**
* @brief A List that stores its values in an array.
@ -19,9 +20,6 @@ class ArrayList {
friend class SerialArrayListAdapter;
public:
static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
/**
* This is the allocating constructor.
* It allocates an array of the specified size.
@ -187,7 +185,7 @@ class ArrayList {
*/
ReturnValue_t insert(T entry) {
if (size >= maxSize_) {
return FULL;
return containers::LIST_FULL;
}
entries[size] = entry;
++size;

View File

@ -12,6 +12,7 @@ template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
class FixedArrayList : public ArrayList<T, count_t> {
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
"count_t is not large enough to hold MAX_SIZE");
static_assert(MAX_SIZE > 0, "MAX_SIZE is 0");
private:
T data[MAX_SIZE];
@ -20,15 +21,19 @@ class FixedArrayList : public ArrayList<T, count_t> {
FixedArrayList() : ArrayList<T, count_t>(data, MAX_SIZE) {}
FixedArrayList(const FixedArrayList& other) : ArrayList<T, count_t>(data, MAX_SIZE) {
memcpy(this->data, other.data, sizeof(this->data));
this->entries = data;
this->size = other.size;
for (size_t idx = 0; idx < this->size; idx++) {
data[idx] = other.data[idx];
}
}
FixedArrayList& operator=(FixedArrayList other) {
memcpy(this->data, other.data, sizeof(this->data));
this->entries = data;
this->size = other.size;
for (size_t idx = 0; idx < this->size; idx++) {
data[idx] = other.data[idx];
}
return *this;
}

View File

@ -4,8 +4,8 @@
#include <type_traits>
#include <utility>
#include "../returnvalues/returnvalue.h"
#include "ArrayList.h"
#include "definitions.h"
/**
* @brief Map implementation for maps with a pre-defined size.
@ -24,11 +24,6 @@ class FixedMap : public SerializeIF {
"derived class from SerializeIF to be serialize-able");
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
private:
static const key_t EMPTY_SLOT = -1;
ArrayList<std::pair<key_t, T>, uint32_t> theMap;
@ -76,10 +71,10 @@ class FixedMap : public SerializeIF {
ReturnValue_t insert(key_t key, T value, Iterator* storedValue = nullptr) {
if (exists(key) == returnvalue::OK) {
return KEY_ALREADY_EXISTS;
return containers::KEY_ALREADY_EXISTS;
}
if (_size == theMap.maxSize()) {
return MAP_FULL;
return containers::MAP_FULL;
}
theMap[_size].first = key;
theMap[_size].second = value;
@ -93,7 +88,7 @@ class FixedMap : public SerializeIF {
ReturnValue_t insert(std::pair<key_t, T> pair) { return insert(pair.first, pair.second); }
ReturnValue_t exists(key_t key) const {
ReturnValue_t result = KEY_DOES_NOT_EXIST;
ReturnValue_t result = containers::KEY_DOES_NOT_EXIST;
if (findIndex(key) < _size) {
result = returnvalue::OK;
}
@ -103,7 +98,7 @@ class FixedMap : public SerializeIF {
ReturnValue_t erase(Iterator* iter) {
uint32_t i;
if ((i = findIndex((*iter).value->first)) >= _size) {
return KEY_DOES_NOT_EXIST;
return containers::KEY_DOES_NOT_EXIST;
}
theMap[i] = theMap[_size - 1];
--_size;
@ -114,7 +109,7 @@ class FixedMap : public SerializeIF {
ReturnValue_t erase(key_t key) {
uint32_t i;
if ((i = findIndex(key)) >= _size) {
return KEY_DOES_NOT_EXIST;
return containers::KEY_DOES_NOT_EXIST;
}
theMap[i] = theMap[_size - 1];
--_size;
@ -160,8 +155,8 @@ class FixedMap : public SerializeIF {
uint32_t maxSize() const { return theMap.maxSize(); }
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const {
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const override {
ReturnValue_t result =
SerializeAdapter::serialize(&this->_size, buffer, size, maxSize, streamEndianness);
uint32_t i = 0;
@ -175,7 +170,7 @@ class FixedMap : public SerializeIF {
return result;
}
virtual size_t getSerializedSize() const {
size_t getSerializedSize() const override {
uint32_t printSize = sizeof(_size);
uint32_t i = 0;
@ -187,8 +182,8 @@ class FixedMap : public SerializeIF {
return printSize;
}
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override {
ReturnValue_t result =
SerializeAdapter::deSerialize(&this->_size, buffer, size, streamEndianness);
if (this->_size > theMap.maxSize()) {

View File

@ -0,0 +1,14 @@
#ifndef FSFW_CONTAINER_DEFINITIONS_H_
#define FSFW_CONTAINER_DEFINITIONS_H_
#include "fsfw/retval.h"
namespace containers {
static const ReturnValue_t KEY_ALREADY_EXISTS = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x01);
static const ReturnValue_t MAP_FULL = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x02);
static const ReturnValue_t KEY_DOES_NOT_EXIST = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x03);
static const ReturnValue_t LIST_FULL = returnvalue::makeCode(CLASS_ID::ARRAY_LIST, 0x01);
} // namespace containers
#endif /* FSFW_CONTAINER_DEFINITIONS_H_ */

View File

@ -1,2 +1 @@
target_sources(${LIB_FSFW_NAME} PRIVATE ControllerBase.cpp
ExtendedControllerBase.cpp)
target_sources(${LIB_FSFW_NAME} PRIVATE ControllerBase.cpp)

View File

@ -12,10 +12,11 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
mode(MODE_OFF),
submode(SUBMODE_NONE),
modeHelper(this),
healthHelper(this, setObjectId) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
healthHelper(this, setObjectId),
actionHelper(this, commandQueue),
datapoolHelper(this),
housekeepingHelper(this) {
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
}
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
@ -47,6 +48,21 @@ ReturnValue_t ControllerBase::initialize() {
return result;
}
result = actionHelper.initialize(commandQueue);
if (result != returnvalue::OK) {
return result;
}
result = housekeepingHelper.initialize();
if (result != returnvalue::OK) {
return result;
}
result = datapoolHelper.initialize();
if (result != returnvalue::OK) {
return result;
}
return returnvalue::OK;
}
@ -66,6 +82,12 @@ void ControllerBase::handleQueue() {
if (result == returnvalue::OK) {
continue;
}
result = actionHelper.handleActionMessage(&command);
if (result == returnvalue::OK) {
continue;
}
result = handleCommandMessage(&command);
if (result == returnvalue::OK) {
continue;
@ -101,6 +123,15 @@ ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
return returnvalue::OK;
}
const ModeHelper* ControllerBase::getModeHelper() const { return &modeHelper; }
ActionHelper* ControllerBase::getActionHelper() { return &actionHelper; }
ReturnValue_t ControllerBase::executeAction(Action* action) { return action->handle(); }
DatapoolHelper* ControllerBase::getDatapoolHelper() { return &datapoolHelper; }
HousekeepingHelper* ControllerBase::getHousekeepingHelper() { return &housekeepingHelper; }
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
ReturnValue_t ControllerBase::setHealth(HealthState health) {

View File

@ -1,13 +1,15 @@
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
#include "fsfw/health/HasHealthIF.h"
#include "fsfw/health/HealthHelper.h"
#include "fsfw/modes/HasModesIF.h"
#include "fsfw/modes/ModeHelper.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
#include <fsfw/health/HasHealthIF.h>
#include <fsfw/health/HealthHelper.h>
#include <fsfw/introspection/ClasslessEnum.h>
#include <fsfw/modes/HasModesIF.h>
#include <fsfw/action/HasActionsIF.h>
#include <fsfw/datapool/HasDatapoolIF.h>
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/tasks/ExecutableObjectIF.h>
#include <fsfw/tasks/PeriodicTaskIF.h>
/**
* @brief Generic base class for controller classes
@ -17,10 +19,14 @@
*/
class ControllerBase : public HasModesIF,
public HasHealthIF,
public HasDatapoolIF,
public HasActionsIF,
public ExecutableObjectIF,
public SystemObject {
public:
static const Mode_t MODE_NORMAL = 2;
FSFW_CLASSLESS_ENUM(ControllerModes, Mode_t,
((CONTROLLER_MODE_ON, MODE_ON, "On"))((CONTROLLER_MODE_OFF, MODE_OFF,
"Off"))((MODE_NORMAL, 2, "Normal")))
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
~ControllerBase() override;
@ -39,6 +45,17 @@ class ControllerBase : public HasModesIF,
void setTaskIF(PeriodicTaskIF *task) override;
ReturnValue_t initializeAfterTaskCreation() override;
/** HasModeIF overrides */
const ModeHelper *getModeHelper() const override;
/** HasActionsIF override */
ActionHelper* getActionHelper() override;
ReturnValue_t executeAction(Action* action) override;
/** HasDatapoolIF overrides */
DatapoolHelper* getDatapoolHelper() override;
HousekeepingHelper* getHousekeepingHelper() override;
protected:
/**
* Implemented by child class. Handle command messages which are not
@ -68,6 +85,12 @@ class ControllerBase : public HasModesIF,
HealthHelper healthHelper;
ActionHelper actionHelper;
DatapoolHelper datapoolHelper;
HousekeepingHelper housekeepingHelper;
/**
* Pointer to the task which executes this component,
* is invalid before setTaskIF was called.

View File

@ -8,11 +8,12 @@ ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t
ExtendedControllerBase::~ExtendedControllerBase() = default;
ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy,
const uint8_t *data, size_t size) {
/* Needs to be overriden and implemented by child class. */
return returnvalue::OK;
ActionHelper *ExtendedControllerBase::getActionHelper() {
return &actionHelper;
}
ReturnValue_t ExtendedControllerBase::executeAction(Action *action) {
return action->handle();
}
object_id_t ExtendedControllerBase::getObjectId() const { return SystemObject::getObjectId(); }

View File

@ -29,6 +29,10 @@ class ExtendedControllerBase : public ControllerBase,
ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initializeAfterTaskCreation() override;
/* HasActionsIF overrides */
ActionHelper* getActionHelper() override;
ReturnValue_t executeAction(Action* actionId) override;
protected:
LocalDataPoolManager poolManager;
ActionHelper actionHelper;
@ -49,10 +53,6 @@ class ExtendedControllerBase : public ControllerBase,
/* Handle the four messages mentioned above */
void handleQueue() override;
/* HasActionsIF overrides */
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) override;
/* HasLocalDatapoolIF overrides */
LocalDataPoolManager* getHkManagerHandle() override;
[[nodiscard]] object_id_t getObjectId() const override;

View File

@ -1 +1 @@
target_sources(${LIB_FSFW_NAME} PRIVATE PoolDataSetBase.cpp PoolEntry.cpp)
target_sources(${LIB_FSFW_NAME} PRIVATE Dataset.cpp DatapoolHelper.cpp)

View File

@ -0,0 +1,20 @@
#include "DatapoolHelper.h"
DatapoolHelper::DatapoolHelper(HasDatapoolIF* owner) : HousekeepingHelper(owner) {}
ReturnValue_t DatapoolHelper::initialize() {
return HousekeepingHelper::initialize();
}
const Dataset* DatapoolHelper::getDataSet(HousekeepingSetId_t id) {
auto iter = dataSets.find(id);
if (iter == dataSets.end()) {
return nullptr;
}
return iter->second;
}
void DatapoolHelper::registerSet(Dataset* set) {
auto id = set->getId();
dataSets.emplace(id, set);
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "Dataset.h"
#include "HasDatapoolIF.h"
#include <fsfw/housekeeping/HousekeepingHelper.h>
#include <stdint.h>
#include <map>
class DatapoolHelper : public HousekeepingHelper {
public:
DatapoolHelper(HasDatapoolIF *owner);
~DatapoolHelper() = default;
const Dataset* getDataSet(HousekeepingSetId_t id);
const std::map<HousekeepingSetId_t, Dataset*>* getDatasets() const {
return &dataSets;
}
void registerSet(Dataset* set);
ReturnValue_t initialize();
private:
std::map<HousekeepingSetId_t, Dataset*> dataSets;
};

View File

@ -0,0 +1,141 @@
#include "Dataset.h"
#include <fsfw/ipc/MutexFactory.h>
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw/returnvalues/returnvalue.h>
//TODO for non allocated: detect if initialized, and if not, call it
#include "HasDatapoolIF.h"
#ifdef FSFW_INTROSPECTION
Dataset::Dataset(HasDatapoolIF* owner, const EnumIF &id, bool allowUserCommit)
: HousekeepingSet(owner, id), allocated(true), allowUserCommit(allowUserCommit) {
this->owner.pointer = owner;
owner->getDatapoolHelper()->registerSet(this);
mutex = MutexFactory::instance()->createMutex();
}
Dataset::Dataset(uint32_t owner_id, const EnumIF &id)
: HousekeepingSet(nullptr, id), allocated(false), allowUserCommit(false) {
this->owner.id = owner_id;
}
#else
Dataset::Dataset(HasDatapoolIF* owner, HousekeepingSetId_t id, bool allowUserCommit)
: HousekeepingSet(owner, id), allocated(true), allowUserCommit(allowUserCommit) {
this->owner.pointer = owner;
owner->getDatapoolHelper()->registerSet(this);
mutex = MutexFactory::instance()->createMutex();
}
Dataset::Dataset(uint32_t owner_id, HousekeepingSetId_t id) : HousekeepingSet(nullptr, id) {
this->owner.id = owner_id;
}
#endif
Dataset::~Dataset() { MutexFactory::instance()->deleteMutex(mutex); }
void Dataset::commit() {
if ((!allocated) && (!allowUserCommit)) {
return;
}
lock();
for (auto variable : variables) {
variable->commit();
}
unlock();
}
void Dataset::commit(bool valid) {
if ((!allocated) && (!allowUserCommit)) {
return;
}
setAllValid(valid);
commit();
}
void Dataset::setAllValid(bool valid) {
if ((!allocated) && (!allowUserCommit)) {
return;
}
for (auto variable : variables) {
variable->setValid(valid);
}
}
void Dataset::read() {
lock();
for (auto variable : variables) {
variable->read();
}
unlock();
}
bool Dataset::hasChanged() {
bool changed = hasChangedNoRead();
read();
return changed;
}
bool Dataset::hasChangedOrOlderThan(uint32_t seconds) {
bool changed = hasChanged();
// TODO time
read();
return changed;
}
const std::vector<DatasetEntryIF*>* Dataset::getVariables() const { return &variables; }
ReturnValue_t Dataset::initialize() {
if (allocated) {
// nothing to do
return returnvalue::OK;
}
HasDatapoolIF* actualOwner = ObjectManager::instance()->get<HasDatapoolIF>(owner.id);
if (actualOwner == nullptr) {
puts("owner type");
return returnvalue::FAILED;
}
const Dataset* theOtherSet = actualOwner->getDatapoolHelper()->getDataSet(this->id);
if (theOtherSet == nullptr) {
puts("no set");
return returnvalue::FAILED;
}
if (theOtherSet->variables.size() != variables.size()) {
return returnvalue::FAILED;
}
this->mutex = theOtherSet->mutex;
this->allowUserCommit = theOtherSet->allowUserCommit;
for (size_t i = 0; i < variables.size(); i++) {
variables[i]->connect(theOtherSet->variables[i]);
}
return returnvalue::OK;
}
// operator[]
bool Dataset::registerEntry(DatasetEntryIF* entry) {
variables.push_back(entry);
return allocated;
}
void Dataset::lock() { mutex->lockMutex(MutexIF::TimeoutType::BLOCKING); }
void Dataset::unlock() { mutex->unlockMutex(); }
bool Dataset::hasChangedNoRead() {
bool changed = false;
for (auto variable : variables) {
if (variable->changed()) {
changed = true;
break;
}
}
return changed;
}

183
src/fsfw/datapool/Dataset.h Normal file
View File

@ -0,0 +1,183 @@
#pragma once
#include <fsfw/housekeeping/HousekeepingSet.h>
#include <fsfw/introspection/Enum.h>
#include <fsfw/ipc/MutexIF.h>
#include <fsfw/returnvalues/returnvalue.h>
#include <fsfw/storagemanager/storeAddress.h>
#include <stdint.h>
#include <vector>
#include "DatasetEntryIF.h"
// TODO ring inclusion
// #include "HasDatapoolIF.h"
class HasDatapoolIF;
// TODO allow user commit and reporting TM
/**
* This class has a dual use
*
* 1) It is used as an IPC method:
* It implements a shared memory which can be written and read by different parties
*
* 2) It is used to define data that is to be downlinked, either periodically or
* triggered by an (abstract, not in the sense of fsfw/events) event occuring, ie
* data was received from an external source and should be shared with ground.
*
* Generating a downlinked report is coupled to commiting, as without a commit there is no
* change in information to be reported.
*
* Nominally, the decision to report is done by the set itself, depending on its settings.
* If a report is to be forced regardless of these settings, the commitAndReport() functions
* are provided which will always generate a report.
*
* Periodic reports are not tied to a specific tc and are reported as "unrequested". When forcing
* a report, optionally a tc can be provided which (logically) triggered the report.
*
* And, as life is complicated, there is a third set of commits: commitAndReportIfRequested(). Same
* as before, but this time, a report is only generated, if the store_address_t is valid. These are
* used if at the place where the commit is called, it is not known if there is a request (cf DHB
* interpretDeviceReply)
*/
class Dataset : public HousekeepingSet {
protected:
#ifdef FSFW_INTROSPECTION
Dataset(HasDatapoolIF* owner, const EnumIF &id, bool allowUserCommit);
Dataset(uint32_t owner_id, const EnumIF &id);
#else
Dataset(HasDatapoolIF* owner, HousekeepingSetId_t id, bool allowUserCommit);
Dataset(uint32_t owner_id, HousekeepingSetId_t id);
#endif
public:
~Dataset() override;
/**
* Copy content of local copies into actual variable
*
*/
void commit();
/**
* Copy content of local copies into actual variable
*
* calls setValid(valid) before committing
*
*/
void commit(bool valid);
/**
* Copy content of local copies into actual variable
* Force sending of TM packet
*
*/
void commitAndReport();
/**
* Copy content of local copies into actual variable
* Force sending of TM packet
*
* calls setValid(valid) before committing
*
*/
void commitAndReport(bool valid);
/**
* Copy content of local copies into actual variable
* Force sending of TM packet, in reference to tc
*
*/
void commitAndReport(store_address_t tc, size_t tc_offset);
/**
* Copy content of local copies into actual variable
* Force sending of TM packet, in reference to tc
*
* calls setValid(valid) before committing
*
*/
void commitAndReport(bool valid, store_address_t tc, size_t tc_offset);
/**
* Copy content of local copies into actual variable
* Force sending of TM packet, in reference to tc, if tc is valid
*
*/
void commitAndReportIfRequested(store_address_t tc, size_t tc_offset);
/**
* Copy content of local copies into actual variable
* Force sending of TM packet, in reference to tc, if tc is valid
*
* calls setValid(valid) before committing
*
*/
void commitAndReportIfRequested(bool valid, store_address_t tc, size_t tc_offset);
/**
* set all contained variables to #valid
*
*/
void setAllValid(bool valid);
/**
* Copy content of actual variables into local copies
*
*
*/
void read();
/**
* returns true if local copies and actual variables differ
*
* implicitely calls read()
*/
bool hasChanged();
/**
* returns true if local copies and actual variables differ
* or time since last time true has been returned is greater than
* supplied time
*
* implicitely calls read()
*
*/
bool hasChangedOrOlderThan(uint32_t seconds);
/**
* get List of contained Valiables
*/
virtual const std::vector<DatasetEntryIF*>* getVariables() const;
ReturnValue_t initialize();
// operator[]
bool registerEntry(DatasetEntryIF*);
protected:
bool allocated;
bool allowUserCommit;
union {
object_id_t id;
HasDatapoolIF* pointer;
} owner;
MutexIF* mutex;
std::vector<DatasetEntryIF*> variables;
/**
* lock the mutex of the set
*/
void lock();
/**
* unlock the mutex of the set
*/
void unlock();
bool hasChangedNoRead();
};

View File

@ -0,0 +1,87 @@
#pragma once
#include <fsfw/introspection/Parameter.h>
#include <fsfw/introspection/Types.h>
#include <fsfw/introspection/TypesHelper.h>
#include <stdio.h>
#include "Dataset.h"
#include "DatasetEntryIF.h"
// TODO: ifdef introspection stuff
template <typename T>
class DatasetEntry : public Parameter<T>, public DatasetEntryIF {
protected:
#ifdef FSFW_INTROSPECTION
DatasetEntry(Dataset *owner, const char *name)
: Parameter<T>(owner, name)
#else
DatasetEntry(Dataset *owner)
: Parameter<T>(owner)
#endif
{
allocated = owner->registerEntry(this);
if (!allocated) {
return;
}
storedValue = new T();
storedValid = new bool;
}
public:
#ifdef FSFW_INTROSPECTION
static DatasetEntry createDatasetEntry(Dataset *owner, const char *name) {
return DatasetEntry(owner, name);
}
#else
static DatasetEntry createDatasetEntry(Dataset *owner) { return DatasetEntry(owner); }
#endif
~DatasetEntry() {
if (allocated) {
delete storedValue;
delete storedValid;
}
}
virtual void setValid(bool isValid) { valid = isValid; }
virtual bool getValid() { return valid; }
//T value; //TODO can this be private?
protected:
virtual void commit() {
*storedValue = Parameter<T>::value;
*storedValid = valid;
}
virtual void read() {
Parameter<T>::value = *storedValue;
valid = *storedValid;
}
virtual void connect(DatasetEntryIF *entry) {
DatasetEntry<T> *theOther = dynamic_cast<DatasetEntry<T> *>(entry);
if (theOther == nullptr) {
// Configuration error
return;
}
this->storedValue = theOther->storedValue;
this->storedValid = theOther->storedValid;
}
virtual bool changed() { return ((Parameter<T>::value != *storedValue) || (valid != *storedValid)); }
private:
T *storedValue;
bool *storedValid;
bool valid;
bool allocated;
};
#ifdef FSFW_INTROSPECTION
#define createDatasetEntry(p1, p2) createDatasetEntry(p1, p2)
#else
#define createDatasetEntry(p1, p2) createDatasetEntry(p1)
#endif

View File

@ -0,0 +1,39 @@
#ifndef FSFW_DATAPOOL_POOLENTRYIF_H_
#define FSFW_DATAPOOL_POOLENTRYIF_H_
#include <cstdint>
#include <fsfw/introspection/Types.h>
class DatasetEntryIF {
friend class Dataset;
public:
virtual ~DatasetEntryIF() {}
/**
* @brief This method allows to set the valid information of the pool entry.
*/
virtual void setValid(bool isValid) = 0;
/**
* @brief This method allows to set the valid information of the pool entry.
*/
virtual bool getValid() = 0;
protected:
virtual void commit() = 0;
virtual void read() = 0;
virtual void connect(DatasetEntryIF* entry) = 0;
/**
* returns if value and actual value is different
*/
virtual bool changed() = 0;
private:
};
#endif /* FSFW_DATAPOOL_POOLENTRYIF_H_ */

View File

@ -0,0 +1,13 @@
#pragma once
//TODO ring
class DatapoolHelper;
#include "DatapoolHelper.h"
#include <fsfw/housekeeping/GeneratesHousekeepingIF.h>
class HasDatapoolIF: public GeneratesHousekeepingIF {
public:
virtual ~HasDatapoolIF() = default;
virtual DatapoolHelper* getDatapoolHelper() = 0;
};

View File

@ -1,217 +0,0 @@
#include "fsfw/datapool/PoolDataSetBase.h"
#include <cstring>
#include "fsfw/datapool/ReadCommitIFAttorney.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
const size_t maxFillCount)
: registeredVariables(registeredVariablesArray), maxFillCount(maxFillCount) {}
PoolDataSetBase::~PoolDataSetBase() {}
ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF* variable) {
if (registeredVariables == nullptr) {
/* Underlying container invalid */
return returnvalue::FAILED;
}
if (state != States::STATE_SET_UNINITIALISED) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl;
#else
sif::printError("DataSet::registerVariable: Call made in wrong position.");
#endif
return DataSetIF::DATA_SET_UNINITIALISED;
}
if (variable == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: Pool variable is nullptr." << std::endl;
#else
sif::printError("DataSet::registerVariable: Pool variable is nullptr.\n");
#endif
return DataSetIF::POOL_VAR_NULL;
}
if (fillCount >= maxFillCount) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: DataSet is full." << std::endl;
#else
sif::printError("DataSet::registerVariable: DataSet is full.\n");
#endif
return DataSetIF::DATA_SET_FULL;
}
registeredVariables[fillCount] = variable;
fillCount++;
return returnvalue::OK;
}
ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
ReturnValue_t result = returnvalue::OK;
ReturnValue_t error = result;
if (state == States::STATE_SET_UNINITIALISED) {
lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) {
result = readVariable(count);
if (result != returnvalue::OK) {
error = result;
}
}
state = States::STATE_SET_WAS_READ;
unlockDataPool();
} else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "PoolDataSetBase::read: Call made in wrong position. Don't forget to "
"commit member datasets!"
<< std::endl;
#else
sif::printWarning(
"PoolDataSetBase::read: Call made in wrong position. Don't forget to "
"commit member datasets!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
result = SET_WAS_ALREADY_READ;
}
if (error != returnvalue::OK) {
result = error;
}
return result;
}
uint16_t PoolDataSetBase::getFillCount() const { return fillCount; }
ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) {
ReturnValue_t result = returnvalue::OK;
if (registeredVariables[count] == nullptr) {
/* Configuration error. */
return returnvalue::FAILED;
}
/* These checks are often performed by the respective variable implementation too, but I guess
a double check does not hurt. */
if (registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_WRITE and
registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) {
if (protectEveryReadCommitCall) {
result =
registeredVariables[count]->read(timeoutTypeForSingleVars, mutexTimeoutForSingleVars);
} else {
/* The readWithoutLock function is protected, so we use the attorney here */
result = ReadCommitIFAttorney::readWithoutLock(registeredVariables[count]);
}
if (result != returnvalue::OK) {
result = INVALID_PARAMETER_DEFINITION;
}
}
return result;
}
ReturnValue_t PoolDataSetBase::commit(MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
if (state == States::STATE_SET_WAS_READ) {
handleAlreadyReadDatasetCommit(timeoutType, lockTimeout);
return returnvalue::OK;
} else {
return handleUnreadDatasetCommit(timeoutType, lockTimeout);
}
}
void PoolDataSetBase::handleAlreadyReadDatasetCommit(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) {
lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) {
if ((registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_READ) and
(registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
if (protectEveryReadCommitCall) {
registeredVariables[count]->commit(timeoutTypeForSingleVars, mutexTimeoutForSingleVars);
} else {
/* The commitWithoutLock function is protected, so we use the attorney here */
ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
}
}
}
state = States::STATE_SET_UNINITIALISED;
unlockDataPool();
}
ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) {
ReturnValue_t result = returnvalue::OK;
lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) {
if ((registeredVariables[count]->getReadWriteMode() == PoolVariableIF::VAR_WRITE) and
(registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
if (protectEveryReadCommitCall) {
result =
registeredVariables[count]->commit(timeoutTypeForSingleVars, mutexTimeoutForSingleVars);
} else {
/* The commitWithoutLock function is protected, so we use the attorney here */
ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
}
} else if (registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) {
if (result != COMMITING_WITHOUT_READING) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::commit(): commit-without-read call made "
"with non write-only variable."
<< std::endl;
#endif
result = COMMITING_WITHOUT_READING;
}
}
}
state = States::STATE_SET_UNINITIALISED;
unlockDataPool();
return result;
}
ReturnValue_t PoolDataSetBase::lockDataPool(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) {
return returnvalue::OK;
}
ReturnValue_t PoolDataSetBase::unlockDataPool() { return returnvalue::OK; }
ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
SerializeIF::Endianness streamEndianness) const {
ReturnValue_t result = returnvalue::FAILED;
for (uint16_t count = 0; count < fillCount; count++) {
result = registeredVariables[count]->serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
}
return result;
}
ReturnValue_t PoolDataSetBase::deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) {
ReturnValue_t result = returnvalue::FAILED;
for (uint16_t count = 0; count < fillCount; count++) {
result = registeredVariables[count]->deSerialize(buffer, size, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
}
return result;
}
size_t PoolDataSetBase::getSerializedSize() const {
uint32_t size = 0;
for (uint16_t count = 0; count < fillCount; count++) {
size += registeredVariables[count]->getSerializedSize();
}
return size;
}
void PoolDataSetBase::setContainer(PoolVariableIF** variablesContainer) {
this->registeredVariables = variablesContainer;
}
PoolVariableIF** PoolDataSetBase::getContainer() const { return registeredVariables; }
void PoolDataSetBase::setReadCommitProtectionBehaviour(bool protectEveryReadCommit,
MutexIF::TimeoutType timeoutType,
uint32_t mutexTimeout) {
this->protectEveryReadCommitCall = protectEveryReadCommit;
this->timeoutTypeForSingleVars = timeoutType;
this->mutexTimeoutForSingleVars = mutexTimeout;
}

View File

@ -1,173 +0,0 @@
#ifndef FSFW_DATAPOOL_POOLDATASETBASE_H_
#define FSFW_DATAPOOL_POOLDATASETBASE_H_
#include "PoolDataSetIF.h"
#include "PoolVariableIF.h"
#include "fsfw/ipc/MutexIF.h"
#include "fsfw/serialize/SerializeIF.h"
/**
* @brief The DataSetBase class manages a set of locally checked out variables.
* @details
* This class manages a list, where a set of local variables (or pool variables)
* are registered. They are checked-out (i.e. their values are looked
* up and copied) with the read call. After the user finishes working with the
* pool variables, he can write back all variable values to the pool with
* the commit call. The data set manages locking and freeing the data pool,
* to ensure that all values are read and written back at once.
*
* An internal state manages usage of this class. Variables may only be
* registered before the read call is made, and the commit call only
* after the read call.
*
* If pool variables are writable and not committed until destruction
* of the set, the DataSet class automatically sets the valid flag in the
* data pool to invalid (without) changing the variable's value.
*
* The base class lockDataPool und unlockDataPool implementation are empty
* and should be implemented to protect the underlying pool type.
* @author Bastian Baetz
* @ingroup data_pool
*/
class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
public:
/**
* @brief Creates an empty dataset. Use registerVariable or
* supply a pointer to this dataset to PoolVariable
* initializations to register pool variables.
*/
PoolDataSetBase(PoolVariableIF** registeredVariablesArray, size_t maxFillCount);
/* Forbidden for now */
PoolDataSetBase(const PoolDataSetBase& otherSet) = delete;
const PoolDataSetBase& operator=(const PoolDataSetBase& otherSet) = delete;
~PoolDataSetBase() override;
/**
* @brief The read call initializes reading out all registered variables.
* It is mandatory to call commit after every read call!
* @details
* It iterates through the list of registered variables and calls all read()
* functions of the registered pool variables (which read out their values
* from the data pool) which are not write-only.
* In case of an error (e.g. a wrong data type, or an invalid data pool id),
* the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned.
*
* The data pool is locked during the whole read operation and
* freed afterwards. It is mandatory to call commit after a read call,
* even if the read operation is not successful!
* @return
* - @c returnvalue::OK if all variables were read successfully.
* - @c INVALID_PARAMETER_DEFINITION if a pool entry does not exist or there
* is a type conflict.
* - @c SET_WAS_ALREADY_READ if read() is called twice without calling
* commit() in between
*/
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t lockTimeout = 20) override;
/**
* @brief The commit call initializes writing back the registered variables.
* @details
* It iterates through the list of registered variables and calls the
* commit() method of the remaining registered variables (which write back
* their values to the pool).
*
* The data pool is locked during the whole commit operation and
* freed afterwards. The state changes to "was committed" after this operation.
*
* If the set does contain at least one variable which is not write-only
* commit() can only be called after read(). If the set only contains
* variables which are write only, commit() can be called without a
* preceding read() call. Every read call must be followed by a commit call!
* @return - @c returnvalue::OK if all variables were read successfully.
* - @c COMMITING_WITHOUT_READING if set was not read yet and
* contains non write-only variables
*/
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t lockTimeout = 20) override;
/**
* Register the passed pool variable instance into the data set.
* @param variable
* @return
*/
virtual ReturnValue_t registerVariable(PoolVariableIF* variable) override;
/**
* Provides the means to lock the underlying data structure to ensure
* thread-safety. Default implementation is empty
* @return Always returns -@c returnvalue::OK
*/
virtual ReturnValue_t lockDataPool(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) override;
/**
* Provides the means to unlock the underlying data structure to ensure
* thread-safety. Default implementation is empty
* @return Always returns -@c returnvalue::OK
*/
virtual ReturnValue_t unlockDataPool() override;
virtual uint16_t getFillCount() const override;
/* SerializeIF implementations */
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
SerializeIF::Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override;
/**
* Can be used to individually protect every read and commit call.
* @param protectEveryReadCommit
* @param mutexTimeout
*/
void setReadCommitProtectionBehaviour(
bool protectEveryReadCommit, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t mutexTimeout = 20);
protected:
/**
* @brief The fill_count attribute ensures that the variables
* register in the correct array position and that the maximum
* number of variables is not exceeded.
*/
uint16_t fillCount = 0;
/**
* States of the seet.
*/
enum class States {
STATE_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED
STATE_SET_WAS_READ //!< DATA_SET_WAS_READ
};
/**
* @brief state manages the internal state of the data set,
* which is important e.g. for the behavior on destruction.
*/
States state = States::STATE_SET_UNINITIALISED;
/**
* @brief This array represents all pool variables registered in this set.
* Child classes can use a static or dynamic container to create
* an array of registered variables and assign the first entry here.
*/
PoolVariableIF** registeredVariables = nullptr;
const size_t maxFillCount = 0;
void setContainer(PoolVariableIF** variablesContainer);
PoolVariableIF** getContainer() const;
private:
bool protectEveryReadCommitCall = false;
MutexIF::TimeoutType timeoutTypeForSingleVars = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeoutForSingleVars = 20;
ReturnValue_t readVariable(uint16_t count);
void handleAlreadyReadDatasetCommit(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, uint32_t timeoutMs = 20);
ReturnValue_t handleUnreadDatasetCommit(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, uint32_t timeoutMs = 20);
};
#endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */

View File

@ -1,34 +0,0 @@
#ifndef FSFW_DATAPOOL_POOLDATASETIF_H_
#define FSFW_DATAPOOL_POOLDATASETIF_H_
#include "DataSetIF.h"
#include "ReadCommitIF.h"
/**
* @brief Extendes the DataSetIF by adding abstract functions to lock
* and unlock a data pool and read/commit semantics.
*/
class PoolDataSetIF : virtual public DataSetIF, virtual public ReadCommitIF {
public:
virtual ~PoolDataSetIF(){};
/**
* @brief Most underlying data structures will have a pool like structure
* and will require a lock and unlock mechanism to ensure
* thread-safety
* @return Lock operation result
*/
virtual ReturnValue_t lockDataPool(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) = 0;
/**
* @brief Unlock call corresponding to the lock call.
* @return Unlock operation result
*/
virtual ReturnValue_t unlockDataPool() = 0;
virtual bool isValid() const = 0;
};
#endif /* FSFW_DATAPOOL_POOLDATASETIF_H_ */

View File

@ -1,102 +0,0 @@
#include "fsfw/datapool/PoolEntry.h"
#include <algorithm>
#include <cstring>
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
template <typename T>
PoolEntry<T>::PoolEntry(uint8_t len, bool setValid) : length(len), valid(setValid) {
this->address = new T[this->length]();
std::memset(this->address, 0, this->getByteSize());
}
template <typename T>
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValues, bool setValid)
: length(static_cast<uint8_t>(initValues.size())), valid(setValid) {
this->address = new T[this->length]();
if (initValues.size() > 0) {
std::copy(initValues.begin(), initValues.end(), this->address);
}
}
template <typename T>
PoolEntry<T>::PoolEntry(const T* initValue, uint8_t setLength, bool setValid)
: length(setLength), valid(setValid) {
this->address = new T[this->length]();
if (initValue != nullptr) {
std::memcpy(this->address, initValue, this->getByteSize());
}
}
// As the data pool is global, this dtor is only be called on program exit.
// Warning! Never copy pool entries!
template <typename T>
PoolEntry<T>::~PoolEntry() {
delete[] this->address;
}
template <typename T>
uint16_t PoolEntry<T>::getByteSize() {
return (sizeof(T) * this->length);
}
template <typename T>
uint8_t PoolEntry<T>::getSize() {
return this->length;
}
template <typename T>
void* PoolEntry<T>::getRawData() {
return this->address;
}
template <typename T>
void PoolEntry<T>::setValid(bool isValid) {
this->valid = isValid;
}
template <typename T>
bool PoolEntry<T>::getValid() {
return valid;
}
template <typename T>
void PoolEntry<T>::print() {
const char* validString = nullptr;
if (valid) {
validString = "Valid";
} else {
validString = "Invalid";
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PoolEntry information." << std::endl;
sif::info << "PoolEntry validity: " << validString << std::endl;
#else
sif::printInfo("PoolEntry information.\n");
sif::printInfo("PoolEntry validity: %s\n", validString);
#endif
arrayprinter::print(reinterpret_cast<uint8_t*>(address), getByteSize());
}
template <typename T>
inline T* PoolEntry<T>::getDataPtr() {
return this->address;
}
template <typename T>
Type PoolEntry<T>::getType() {
return PodTypeConversion<T>::type;
}
template class PoolEntry<uint8_t>;
template class PoolEntry<uint16_t>;
template class PoolEntry<uint32_t>;
template class PoolEntry<uint64_t>;
template class PoolEntry<int8_t>;
template class PoolEntry<int16_t>;
template class PoolEntry<int32_t>;
template class PoolEntry<int64_t>;
template class PoolEntry<float>;
template class PoolEntry<double>;

View File

@ -1,140 +0,0 @@
#ifndef FSFW_DATAPOOL_POOLENTRY_H_
#define FSFW_DATAPOOL_POOLENTRY_H_
#include <cstddef>
#include <initializer_list>
#include <type_traits>
#include "PoolEntryIF.h"
/**
* @brief This is a small helper class that defines a single data pool entry.
* @details
* The helper is used to store all information together with the data as a
* single data pool entry. The content's type is defined by the template
* argument.
*
* It is prepared for use with plain old data types, but may be
* extended to complex types if necessary. It can be initialized with a
* certain value, size and validity flag.
*
* It holds a pointer to the real data and offers methods to access this data
* and to acquire additional information (such as validity and array/byte size).
* It is NOT intended to be used outside DataPool implementations as it performs
* dynamic memory allocation.
*
* @ingroup data_pool
*/
template <typename T>
class PoolEntry : public PoolEntryIF {
public:
static_assert(not std::is_same<T, bool>::value,
"Do not use boolean for the PoolEntry type, use uint8_t "
"instead! The ECSS standard defines a boolean as a one bit "
"field. Therefore it is preferred to store a boolean as an "
"uint8_t");
PoolEntry(uint8_t len = 1, bool setValid = false);
/**
* @brief In the classe's constructor, space is allocated on the heap and
* potential initialization values are copied to that space.
* @details
* Not passing any arguments will initialize an non-array pool entry
* with an initial invalid state and the value 0.
* Please note that if an initializer list is passed, the length of the
* initializer list needs to be correct for vector entries because
* required allocated space will be deduced from the initializer list length
* and the pool entry type.
* @param initValue
* Initializer list with values to initialize with, for example {0, 0} to
* initialize the a pool entry of a vector with two entries to 0.
* @param setValid
* Sets the initialization flag. It is invalid by default.
*/
PoolEntry(std::initializer_list<T> initValue, bool setValid = false);
/**
* @brief In the classe's constructor, space is allocated on the heap and
* potential init values are copied to that space.
* @param initValue
* A pointer to the single value or array that holds the init value.
* With the default value (nullptr), the entry is initalized with all 0.
* @param setLength
* Defines the array length of this entry.
* @param setValid
* Sets the initialization flag. It is invalid by default.
*/
PoolEntry(const T* initValue, uint8_t setLength = 1, bool setValid = false);
//! Explicitely deleted copy ctor, copying is not allowed.
PoolEntry(const PoolEntry&) = delete;
//! Explicitely deleted copy assignment, copying is not allowed.
PoolEntry& operator=(const PoolEntry&) = delete;
/**
* @brief The allocated memory for the variable is freed
* in the destructor.
* @details
* As the data pool is global, this dtor is only called on program exit.
* PoolEntries shall never be copied, as a copy might delete the variable
* on the heap.
*/
~PoolEntry();
/**
* Return typed pointer to start of data.
* @return
*/
T* getDataPtr();
/**
* @brief getSize returns the array size of the entry.
* @details
* For non-array pool entries return type size, for vector entries
* return type size times the number of entries.
*/
uint8_t getSize();
/**
* @brief This operation returns the size in bytes.
* @details The size is calculated by sizeof(type) * array_size.
*/
uint16_t getByteSize();
/**
* @brief This operation returns a the address pointer casted to void*.
*/
void* getRawData();
/**
* @brief This method allows to set the valid information
* of the pool entry.
*/
void setValid(bool isValid);
/**
* @brief This method allows to get the valid information
* of the pool entry.
*/
bool getValid();
/**
* @brief This is a debug method that prints all values and the valid
* information to the screen. It prints all array entries in a row.
*/
void print();
Type getType();
private:
/**
* @brief This attribute stores the length information.
*/
uint8_t length;
/**
* @brief Here, the validity information for a variable is stored.
* Every entry (single variable or vector) has one valid flag.
*/
uint8_t valid;
/**
* @brief This is the address pointing to the allocated memory.
*/
T* address;
};
#endif /* FSFW_DATAPOOL_POOLENTRY_H_ */

View File

@ -1,28 +0,0 @@
#ifndef FSFW_DATAPOOL_POOLVARLIST_H_
#define FSFW_DATAPOOL_POOLVARLIST_H_
#include "../datapool/PoolVariableIF.h"
#include "../datapoolglob/GlobalPoolVariable.h"
template <class T, uint8_t n_var>
class PoolVarList {
private:
GlobPoolVar<T> variables[n_var];
public:
PoolVarList(const uint32_t set_id[n_var], DataSetIF* dataSet,
PoolVariableIF::ReadWriteMode_t setReadWriteMode) {
// I really should have a look at the new init list c++ syntax.
if (dataSet == NULL) {
return;
}
for (uint8_t count = 0; count < n_var; count++) {
variables[count].dataPoolId = set_id[count];
variables[count].readWriteMode = setReadWriteMode;
dataSet->registerVariable(&variables[count]);
}
}
GlobPoolVar<T>& operator[](int i) { return variables[i]; }
};
#endif /* FSFW_DATAPOOL_POOLVARLIST_H_ */

View File

@ -1,62 +0,0 @@
#ifndef FSFW_DATAPOOL_POOLVARIABLEIF_H_
#define FSFW_DATAPOOL_POOLVARIABLEIF_H_
#include "../returnvalues/returnvalue.h"
#include "../serialize/SerializeIF.h"
#include "ReadCommitIF.h"
/**
* @brief This interface is used to control data pool
* variable representations.
* @details
* To securely handle data pool variables, all pool entries are locally
* managed by data pool variable access classes, which are called pool
* variables. To ensure a common state of a set of variables needed in a
* function, these local pool variables again are managed by other classes,
* like the DataSet classes. This interface provides unified access to
* local pool variables for such manager classes.
* @author Bastian Baetz
* @ingroup data_pool
*/
class PoolVariableIF : public SerializeIF, public ReadCommitIF {
public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF;
static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0);
static constexpr ReturnValue_t INVALID_POOL_ENTRY = MAKE_RETURN_CODE(0xA1);
static constexpr bool VALID = 1;
static constexpr bool INVALID = 0;
static constexpr uint32_t NO_PARAMETER = 0xffffffff;
enum ReadWriteMode_t { VAR_READ, VAR_WRITE, VAR_READ_WRITE };
/**
* @brief This is an empty virtual destructor,
* as it is proposed for C++ interfaces.
*/
virtual ~PoolVariableIF() {}
/**
* @brief This method returns if the variable is write-only,
* read-write or read-only.
*/
virtual ReadWriteMode_t getReadWriteMode() const = 0;
virtual void setReadWriteMode(ReadWriteMode_t newMode) = 0;
/**
* @brief This operation shall return the data pool id of the variable.
*/
virtual uint32_t getDataPoolId() const = 0;
/**
* @brief With this call, the valid information of the
* variable is returned.
*/
virtual bool isValid() const = 0;
/**
* @brief With this call, the valid information of the variable is set.
*/
virtual void setValid(bool validity) = 0;
};
using pool_rwm_t = PoolVariableIF::ReadWriteMode_t;
#endif /* FSFW_DATAPOOL_POOLVARIABLEIF_H_ */

View File

@ -1,27 +0,0 @@
#ifndef FSFW_DATAPOOL_READCOMMITIF_H_
#define FSFW_DATAPOOL_READCOMMITIF_H_
#include "../ipc/MutexIF.h"
#include "../returnvalues/returnvalue.h"
/**
* @brief Common interface for all software objects which employ read-commit
* semantics.
*/
class ReadCommitIF {
friend class ReadCommitIFAttorney;
public:
virtual ~ReadCommitIF() {}
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) = 0;
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) = 0;
protected:
/* Optional and protected because this is interesting for classes grouping members with commit
and read semantics where the lock is only necessary once. */
virtual ReturnValue_t readWithoutLock() { return read(MutexIF::TimeoutType::WAITING, 20); }
virtual ReturnValue_t commitWithoutLock() { return commit(MutexIF::TimeoutType::WAITING, 20); }
};
#endif /* FSFW_DATAPOOL_READCOMMITIF_H_ */

View File

@ -1,30 +0,0 @@
#ifndef FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_
#define FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_
#include <fsfw/datapool/ReadCommitIF.h>
#include <fsfw/returnvalues/returnvalue.h>
/**
* @brief This class determines which members are allowed to access protected members
* of the ReadCommitIF.
*/
class ReadCommitIFAttorney {
private:
static ReturnValue_t readWithoutLock(ReadCommitIF* readCommitIF) {
if (readCommitIF == nullptr) {
return returnvalue::FAILED;
}
return readCommitIF->readWithoutLock();
}
static ReturnValue_t commitWithoutLock(ReadCommitIF* readCommitIF) {
if (readCommitIF == nullptr) {
return returnvalue::FAILED;
}
return readCommitIF->commitWithoutLock();
}
friend class PoolDataSetBase;
};
#endif /* FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_ */

View File

@ -1,16 +0,0 @@
#ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
#define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
#include "PoolDataSetIF.h"
class SharedDataSetIF {
public:
virtual ~SharedDataSetIF(){};
private:
virtual ReturnValue_t lockDataset(MutexIF::TimeoutType timeoutType,
dur_millis_t mutexTimeout) = 0;
virtual ReturnValue_t unlockDataset() = 0;
};
#endif /* FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ */

View File

@ -1,11 +0,0 @@
#ifndef FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
#define FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
/* Collected related headers */
#include "fsfw/datapoollocal/LocalDataSet.h"
#include "fsfw/datapoollocal/LocalPoolVariable.h"
#include "fsfw/datapoollocal/LocalPoolVector.h"
#include "fsfw/datapoollocal/SharedLocalDataSet.h"
#include "fsfw/datapoollocal/StaticLocalDataSet.h"
#endif /* FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ */

View File

@ -26,7 +26,11 @@ void AssemblyBase::performChildOperation() {
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
doStartTransition(mode, submode);
triggerModeHelperEvents(mode, submode);
if (modeHelper.isForced()) {
triggerEvent(FORCING_MODE, mode, submode);
} else {
triggerEvent(CHANGING_MODE, mode, submode);
}
}
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
@ -73,10 +77,9 @@ bool AssemblyBase::handleChildrenChangedHealth() {
}
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
triggerEvent(TRYING_RECOVERY, iter->first, 0);
triggerEvent(TRYING_RECOVERY);
recoveryState = RECOVERY_STARTED;
recoveringDevice = iter;
// The user needs to take care of commanding the children off in commandChildren
doStartTransition(targetMode, targetSubmode);
} else {
triggerEvent(CHILD_CHANGED_HEALTH);
@ -225,9 +228,6 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
bool AssemblyBase::checkAndHandleRecovery() {
switch (recoveryState) {
case RECOVERY_STARTED:
// The recovery was already start in #handleChildrenChangedHealth and we just need
// to wait for an off time period.
// TODO: make time period configurable
recoveryState = RECOVERY_WAIT;
recoveryOffTimer.resetTimer();
return true;
@ -266,11 +266,3 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
modeHelper.setForced(true);
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
}
void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
if (modeHelper.isForced()) {
triggerEvent(FORCING_MODE, mode, submode);
} else {
triggerEvent(CHANGING_MODE, mode, submode);
}
}

View File

@ -12,8 +12,7 @@
* Documentation: Dissertation Baetz p.156, 157.
*
* This class reduces the complexity of controller components which would
* otherwise be needed for the handling of redundant devices. However, it can also be used to
* manage the mode keeping and recovery of non-redundant devices
* otherwise be needed for the handling of redundant devices.
*
* The template class monitors mode and health state of its children
* and checks availability of devices on every detected change.
@ -27,9 +26,11 @@
*
* Important:
*
* The implementation must call #registerChild for all commanded children during initialization.
* The implementation must call registerChild(object_id_t child)
* for all commanded children during initialization.
* The implementation must call the initialization function of the base class.
* (This will call the function in SubsystemBase)
*
*/
class AssemblyBase : public SubsystemBase {
public:
@ -46,10 +47,9 @@ class AssemblyBase : public SubsystemBase {
protected:
/**
* Command children to reach [mode,submode] combination. Can be done by setting
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
* a recovery might be on-going and the device needs to be commanded to off first.
* Command children to reach [mode,submode] combination
* Can be done by setting #commandsOutstanding correctly,
* or using executeTable()
* @param mode
* @param submode
* @return
@ -120,19 +120,8 @@ class AssemblyBase : public SubsystemBase {
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
/**
* @brief Default periodic handler
* @details
* This is the default periodic handler which will be called by the SubsystemBase
* performOperation. It performs the child transitions or reacts to changed health/mode states
* of children objects
*/
virtual void performChildOperation() override;
virtual void performChildOperation();
/**
* This function handles changed mode or health states of children
* @return
*/
bool handleChildrenChanged();
/**
@ -145,37 +134,12 @@ class AssemblyBase : public SubsystemBase {
bool handleChildrenChangedHealth();
/**
* Core transition handler. The default implementation will only do something if
* #commandsOutstanding is smaller or equal to zero, which means that all mode commands
* from the #doPerformTransition call were executed successfully.
*
* Unless a second step was requested, the function will then use #checkChildrenState to
* determine whether the target mode was reached.
*
* There is some special handling for certain (internal) modes:
* - A second step is necessary. #commandChildren will be performed again
* - The device health was overwritten. #commandChildren will be called
* - A recovery is ongoing. #checkAndHandleRecovery will be called.
*/
virtual void handleChildrenTransition();
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
/**
* Calls #doStartTransition and triggers an informative event as well that the mode will
* change
* @param mode
* @param submode
*/
virtual void startTransition(Mode_t mode, Submode_t submode);
/**
* This function starts the transition by setting the internal #targetSubmode and #targetMode
* variables and then calling the #commandChildren function.
* @param mode
* @param submode
*/
virtual void doStartTransition(Mode_t mode, Submode_t submode);
virtual bool isInTransition();
@ -196,7 +160,7 @@ class AssemblyBase : public SubsystemBase {
* Manages recovery of a device
* @return true if recovery is still ongoing, false else.
*/
virtual bool checkAndHandleRecovery();
bool checkAndHandleRecovery();
/**
* Helper method to overwrite health state of one of the children.
@ -204,8 +168,6 @@ class AssemblyBase : public SubsystemBase {
* @param objectId Must be a registered child.
*/
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
};
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */

View File

@ -12,7 +12,7 @@ ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCo
parentId(parent),
childHandlerFdir(setObjectId) {
this->setHkDestination(hkDestination);
this->setThermalStateRequestPoolIds(thermalStatePoolId, thermalRequestPoolId);
this->setThermalStateRequestPoolIds(); //TODO
}
ChildHandlerBase::~ChildHandlerBase() {}

View File

@ -1,10 +1,9 @@
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "fsfw/datapoollocal/LocalPoolVariable.h"
#include "DeviceHandlerBase.h"
#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h"
#include "fsfw/devicehandlers/DeviceTmReportingWrapper.h"
#include "fsfw/globalfunctions/CRC.h"
#include "fsfw/housekeeping/HousekeepingMessage.h"
#include "fsfw/ipc/MessageQueueMessage.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/objectmanager/ObjectManager.h"
@ -22,6 +21,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
CookieIF* comCookie, FailureIsolationBase* fdirInstance,
size_t cmdQueueSize)
: SystemObject(setObjectId),
mode(MODE_OFF),
submode(SUBMODE_NONE),
wiretappingMode(OFF),
storedRawData(StorageManagerIF::INVALID_ADDRESS),
deviceCommunicationId(deviceCommunication),
@ -30,19 +31,16 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
modeHelper(this),
parameterHelper(this),
actionHelper(this, nullptr),
poolManager(this, nullptr),
datapoolHelper(this),
childTransitionFailure(returnvalue::OK),
fdirInstance(fdirInstance),
defaultFDIRUsed(fdirInstance == nullptr),
switchOffWasReported(false),
childTransitionDelay(5000),
mode(MODE_OFF),
submode(SUBMODE_NONE),
transitionSourceMode(_MODE_POWER_DOWN),
transitionSourceSubMode(SUBMODE_NONE) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
insertInCommandMap(RAW_COMMAND_ID);
cookieInfo.state = COOKIE_UNUSED;
cookieInfo.pendingCommand = deviceCommandMap.end();
@ -50,18 +48,16 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", returnvalue::FAILED,
"Invalid cookie");
}
if (this->fdirInstance == nullptr) {
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
}
}
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
this->hkDestination = hkDestination;
}
void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId,
lp_id_t heaterRequestPoolId,
uint32_t thermalSetId) {
thermalSet =
new DeviceHandlerThermalSet(this, thermalSetId, thermalStatePoolId, heaterRequestPoolId);
}
void DeviceHandlerBase::setThermalStateRequestPoolIds() {}
DeviceHandlerBase::~DeviceHandlerBase() {
if (comCookie != nullptr) {
@ -112,9 +108,6 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) {
break;
case CommunicationAction::GET_READ:
doGetRead();
/* This will be performed after datasets have been updated by the
custom device implementation. */
poolManager.performHkOperation();
break;
default:
break;
@ -127,18 +120,6 @@ ReturnValue_t DeviceHandlerBase::initialize() {
if (result != returnvalue::OK) {
return result;
}
if (this->fdirInstance == nullptr) {
this->fdirInstance =
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
}
if (this->parent != objects::NO_OBJECT) {
HasModesIF* modeIF = ObjectManager::instance()->get<HasModesIF>(this->parent);
HasHealthIF* healthIF = ObjectManager::instance()->get<HasHealthIF>(this->parent);
if (modeIF != nullptr and healthIF != nullptr) {
setParentQueue(modeIF->getCommandQueue());
}
}
communicationInterface =
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
@ -215,6 +196,10 @@ ReturnValue_t DeviceHandlerBase::initialize() {
if (result != returnvalue::OK) {
return result;
}
result = datapoolHelper.initialize();
if (result != returnvalue::OK) {
return result;
}
result = fdirInstance->initialize();
if (result != returnvalue::OK) {
return result;
@ -225,22 +210,22 @@ ReturnValue_t DeviceHandlerBase::initialize() {
return result;
}
result = poolManager.initialize(commandQueue);
if (result != returnvalue::OK) {
return result;
}
// result = poolManager.initialize(commandQueue);
// if (result != returnvalue::OK) {
// return result;
// }
fillCommandAndReplyMap();
if (thermalSet != nullptr) {
// Set temperature target state to NON_OP.
result = thermalSet->read();
if (result == returnvalue::OK) {
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
thermalSet->heaterRequest.setValid(true);
thermalSet->commit();
}
}
// if (thermalSet != nullptr) { //TODO
// // Set temperature target state to NON_OP.
// result = thermalSet->read();
// if (result == returnvalue::OK) {
// thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
// thermalSet->heaterRequest.setValid(true);
// thermalSet->commit();
// }
// }
return returnvalue::OK;
}
@ -300,10 +285,10 @@ void DeviceHandlerBase::readCommandQueue() {
return;
}
result = poolManager.handleHousekeepingMessage(&command);
if (result == returnvalue::OK) {
return;
}
// result = poolManager.handleHousekeepingMessage(&command); //TODO
// if (result == returnvalue::OK) {
// return;
// }
result = handleDeviceHandlerMessage(&command);
if (result == returnvalue::OK) {
@ -362,23 +347,27 @@ void DeviceHandlerBase::doStateMachine() {
currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
setMode(_MODE_POWER_DOWN);
callChildStatemachine();
break;
}
ReturnValue_t switchState = getStateOfSwitches();
if ((switchState == PowerSwitchIF::SWITCH_ON) || (switchState == NO_SWITCH)) {
// NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition
childTransitionFailure = CHILD_TIMEOUT;
transitionSourceMode = _MODE_SHUT_DOWN;
transitionSourceSubMode = SUBMODE_NONE;
setMode(_MODE_START_UP);
callChildStatemachine();
}
} break;
case _MODE_WAIT_OFF: {
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
if (powerSwitcher == nullptr) {
setMode(MODE_OFF);
break;
}
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
setMode(MODE_ERROR_ON);
@ -426,7 +415,7 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, Submode_t s
}
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, void* replyDataSet /*TODO*/,
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId,
Countdown* countdown) {
// No need to check, as we may try to insert multiple times.
@ -441,14 +430,14 @@ ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
uint16_t maxDelayCycles,
LocalPoolDataSetBase* dataSet, size_t replyLen,
void* dataSet/*TODO*/, size_t replyLen,
bool periodic, Countdown* countdown) {
DeviceReplyInfo info;
info.maxDelayCycles = maxDelayCycles;
info.periodic = periodic;
info.delayCycles = 0;
info.replyLen = replyLen;
info.dataSet = dataSet;
//info.dataSet = dataSet;
info.command = deviceCommandMap.end();
info.countdown = countdown;
auto resultPair = deviceReplyMap.emplace(replyId, info);
@ -541,15 +530,15 @@ ReturnValue_t DeviceHandlerBase::updatePeriodicReply(bool enable, DeviceCommandI
return returnvalue::OK;
}
ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId,
LocalPoolDataSetBase* dataSet) {
auto replyIter = deviceReplyMap.find(replyId);
if (replyIter == deviceReplyMap.end()) {
return returnvalue::FAILED;
}
replyIter->second.dataSet = dataSet;
return returnvalue::OK;
}
// ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId,
// void* dataSet/*TODO*/) {
// auto replyIter = deviceReplyMap.find(replyId);
// if (replyIter == deviceReplyMap.end()) {
// return returnvalue::FAILED;
// }
// replyIter->second.dataSet = dataSet;
// return returnvalue::OK;
// }
void DeviceHandlerBase::callChildStatemachine() {
if (mode == _MODE_START_UP) {
@ -573,40 +562,27 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) {
}
void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
/**
* handle transition from OFF to NORMAL by continuing towards normal when ON is reached
*/
if (newMode == MODE_ON and continueToNormal) {
continueToNormal = false;
mode = _MODE_TO_NORMAL;
return;
}
/* TODO: This will probably be done by the LocalDataPoolManager now */
// changeHK(mode, submode, false);
submode = newSubmode;
mode = newMode;
modeChanged();
setNormalDatapoolEntriesInvalid();
if (newMode == MODE_OFF) {
disableCommandsAndReplies();
}
if (!isTransitionalMode()) {
// clear this flag when a non-transitional Mode is reached to be safe
continueToNormal = false;
modeHelper.modeChanged(newMode, newSubmode);
announceMode(false);
}
Clock::getUptime(&timeoutStart);
if (mode == MODE_OFF and thermalSet != nullptr) {
ReturnValue_t result = thermalSet->read();
if (result == returnvalue::OK) {
if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) {
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
}
thermalSet->heaterRequest.commit(PoolVariableIF::VALID);
}
}
// if (mode == MODE_OFF and thermalSet != nullptr) { //TODO
// ReturnValue_t result = thermalSet->read();
// if (result == returnvalue::OK) {
// if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) {
// thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
// }
// thermalSet->heaterRequest.commit(PoolVariableIF::VALID);
// }
// }
/* TODO: This will probably be done by the LocalDataPoolManager now */
// changeHK(mode, submode, true);
}
@ -1077,7 +1053,8 @@ Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) {
return transitionMode & ~(TRANSITION_MODE_BASE_ACTION_MASK | TRANSITION_MODE_CHILD_ACTION_MASK);
}
// SHOULDDO: throw away DHB and write a new one:
// SHOULDDO: Allow transition from OFF to NORMAL to reduce complexity in assemblies. And, by the
// way, throw away DHB and write a new one:
// - Include power and thermal completely, but more modular :-)
// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity.
// - Modularization?
@ -1089,25 +1066,25 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) {
return TRANS_NOT_ALLOWED;
}
if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) {
return TRANS_NOT_ALLOWED;
}
// Do not check thermal state for MODE_RAW
if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and
(thermalSet != nullptr)) {
ReturnValue_t result = thermalSet->read();
if (result == returnvalue::OK) {
if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
(not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) {
triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value);
return NON_OP_TEMPERATURE;
}
}
if ((commandedMode == MODE_ON) && (mode == MODE_OFF) and (thermalSet != nullptr)) {
// ReturnValue_t result = thermalSet->read(); //TODO
// if (result == returnvalue::OK) {
// if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
// (not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) {
// triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value);
// return NON_OP_TEMPERATURE;
// }
// }
}
return isModeCombinationValid(commandedMode, commandedSubmode);
}
void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commandedSubmode) {
continueToNormal = false;
switch (commandedMode) {
case MODE_ON:
handleTransitionToOnMode(commandedMode, commandedSubmode);
@ -1137,9 +1114,8 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commande
case MODE_NORMAL:
if (mode != MODE_OFF) {
setTransition(MODE_NORMAL, commandedSubmode);
} else { // mode is off
continueToNormal = true;
handleTransitionToOnMode(MODE_NORMAL, commandedSubmode);
} else {
replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED);
}
break;
}
@ -1154,15 +1130,15 @@ void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, Submode_t
// need to call it twice
childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON);
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
if (thermalSet != nullptr) {
ReturnValue_t result = thermalSet->read();
if (result == returnvalue::OK) {
if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
thermalSet->commit();
}
}
}
// if (thermalSet != nullptr) { //TODO
// ReturnValue_t result = thermalSet->read();
// if (result == returnvalue::OK) {
// if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
// thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
// thermalSet->commit();
// }
// }
// }
} else {
setTransition(MODE_ON, commandedSubmode);
}
@ -1297,7 +1273,6 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
if (iter->second.command != deviceCommandMap.end()) {
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
// This may fail, but we'll ignore the fault.
if (queueId != NO_COMMANDER) {
// This may fail, but we'll ignore the fault.
actionHelper.reportData(queueId, replyId, const_cast<SerializeIF*>(&dataSet));
@ -1333,22 +1308,23 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
}
}
ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
ActionHelper* DeviceHandlerBase::getActionHelper() { return &actionHelper; }
ReturnValue_t DeviceHandlerBase::executeAction(Action* action) {
ReturnValue_t result = acceptExternalDeviceCommands();
if (result != returnvalue::OK) {
return result;
}
DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId);
DeviceCommandMap::iterator iter = deviceCommandMap.find(action->getId());
if (iter == deviceCommandMap.end()) {
result = COMMAND_NOT_SUPPORTED;
} else if (iter->second.isExecuting) {
result = COMMAND_ALREADY_SENT;
} else {
iter->second.sendReplyTo = commandedBy;
result = buildCommandFromCommand(actionId, data, size);
result = action->handle();
}
if (result == returnvalue::OK) {
iter->second.sendReplyTo = action->commandedBy;
iter->second.isExecuting = true;
cookieInfo.pendingCommand = iter;
cookieInfo.state = COOKIE_WRITE_READY;
@ -1476,50 +1452,25 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
uint32_t parameter) {}
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
void DeviceHandlerBase::performOperationHook() {}
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) {
if (thermalSet != nullptr) {
localDataPoolMap.emplace(thermalSet->thermalStatePoolId,
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>);
localDataPoolMap.emplace(thermalSet->heaterRequestPoolId,
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>);
}
return returnvalue::OK;
}
ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
// In this function, the task handle should be valid if the task
// was implemented correctly. We still check to be 1000 % sure :-)
if (executingTask != nullptr) {
pstIntervalMs = executingTask->getPeriodMs();
}
this->poolManager.initializeAfterTaskCreation();
if (setStartupImmediately) {
startTransition(MODE_ON, getInitialSubmode());
startTransition(MODE_ON, SUBMODE_NONE);
}
return returnvalue::OK;
}
LocalPoolDataSetBase* DeviceHandlerBase::getDataSetHandle(sid_t sid) {
auto iter = deviceReplyMap.find(sid.ownerSetId);
if (iter != deviceReplyMap.end()) {
return iter->second.dataSet;
} else {
return nullptr;
}
}
object_id_t DeviceHandlerBase::getObjectId() const { return SystemObject::getObjectId(); }
void DeviceHandlerBase::setStartUpImmediately() { this->setStartupImmediately = true; }
dur_millis_t DeviceHandlerBase::getPeriodicOperationFrequency() const { return pstIntervalMs; }
DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const {
if (cookieInfo.pendingCommand != deviceCommandMap.end()) {
return cookieInfo.pendingCommand->first;
@ -1528,13 +1479,19 @@ DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const {
}
void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() {
for (const auto& reply : deviceReplyMap) {
if (reply.second.dataSet != nullptr) {
reply.second.dataSet->setValidity(false, true);
}
}
// for (const auto& reply : deviceReplyMap) {
// if (reply.second.dataSet != nullptr) {
// PoolReadGuard pg(reply.second.dataSet);
// if (pg.getReadResult() == returnvalue::OK) {
// reply.second.dataSet->setValidity(false, true);
// }
// }
// }
}
DatapoolHelper* DeviceHandlerBase::getDatapoolHelper() { return &datapoolHelper; }
HousekeepingHelper* DeviceHandlerBase::getHousekeepingHelper() { return &datapoolHelper; }
void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, const char* functionName,
ReturnValue_t errorCode, const char* errorPrint) {
if (errorPrint == nullptr) {
@ -1575,8 +1532,6 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, const ch
}
}
LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { return &poolManager; }
MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyId) const {
auto commandIter = deviceCommandMap.find(replyId);
if (commandIter == deviceCommandMap.end()) {
@ -1585,47 +1540,4 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
return commandIter->second.sendReplyTo;
}
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
void DeviceHandlerBase::setParent(object_id_t parent) { this->parent = parent; }
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
this->powerSwitcher = switcher;
}
Mode_t DeviceHandlerBase::getMode() {
return mode;
}
Submode_t DeviceHandlerBase::getSubmode() {
return submode;
}
void DeviceHandlerBase::disableCommandsAndReplies() {
for (auto& command : deviceCommandMap) {
if (command.second.isExecuting) {
command.second.isExecuting = false;
}
}
for (auto& reply : deviceReplyMap) {
if (!reply.second.periodic) {
if (reply.second.countdown != nullptr) {
reply.second.countdown->timeOut();
} else {
reply.second.delayCycles = 0;
}
reply.second.active = false;
}
}
}
ReturnValue_t DeviceHandlerBase::finishAction(bool success, DeviceCommandId_t action,
ReturnValue_t result) {
auto commandIter = deviceCommandMap.find(action);
if (commandIter == deviceCommandMap.end()) {
return MessageQueueIF::NO_QUEUE;
}
commandIter->second.isExecuting = false;
actionHelper.finish(success, commandIter->second.sendReplyTo, action, result);
return returnvalue::OK;
}
ModeHelper const* DeviceHandlerBase::getModeHelper() const { return &modeHelper; }

View File

@ -6,12 +6,11 @@
#include "DeviceCommunicationIF.h"
#include "DeviceHandlerFailureIsolation.h"
#include "DeviceHandlerIF.h"
#include "DeviceHandlerThermalSet.h"
#include "fsfw/action/ActionHelper.h"
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/datapool/PoolVariableIF.h"
#include "fsfw/datapoollocal/HasLocalDataPoolIF.h"
#include "fsfw/datapoollocal/LocalDataPoolManager.h"
// #include "fsfw/datapool/PoolVariableIF.h"
#include "fsfw/datapool/HasDatapoolIF.h"
// #include "fsfw/datapoollocal/LocalDataPoolManager.h"
#include "fsfw/health/HealthHelper.h"
#include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/modes/HasModesIF.h"
@ -23,7 +22,6 @@
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
#include "fsfw/util/dataWrapper.h"
namespace Factory {
void setStaticFrameworkObjectIds();
@ -85,7 +83,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
public HasHealthIF,
public HasActionsIF,
public ReceivesParameterMessagesIF,
public HasLocalDataPoolIF {
public HasDatapoolIF {
friend void(Factory::setStaticFrameworkObjectIds)();
public:
@ -103,57 +101,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
void setCustomFdir(FailureIsolationBase *fdir);
void setParent(object_id_t parent);
void setPowerSwitcher(PowerSwitchIF *switcher);
/**
* extending the modes of DeviceHandler IF for internal state machine
*/
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
//! This is a transitional state which can not be commanded. The device
//! handler performs all commands to get the device in a state ready to
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
//! This is a transitional state which can not be commanded.
//! The device handler performs all actions and commands to get the device
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
//! transition if available.
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
//! It is possible to set the mode to _MODE_TO_ON to use the to on
//! transition if available.
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
//! transition if available.
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
//! transition if available.
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
//! This is a transitional state which can not be commanded.
//! The device is shut down and ready to be switched off.
//! After the command to set the switch off has been sent,
//! the mode changes to @c _MODE_WAIT_OFF
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
//! This is a transitional state which can not be commanded. The device
//! will be switched on in this state. After the command to set the switch
//! on has been sent, the mode changes to @c _MODE_WAIT_ON.
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
//! This is a transitional state which can not be commanded. The switch has
//! been commanded off and the handler waits for it to be off.
//! When the switch is off, the mode changes to @c MODE_OFF.
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
//! This is a transitional state which can not be commanded. The switch
//! 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.
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);
/**
@ -165,10 +112,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param thermalStatePoolId
* @param thermalRequestPoolId
*/
void setThermalStateRequestPoolIds(
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);
void setThermalStateRequestPoolIds(); // TODO
/**
* @brief Helper function to ease device handler development.
* This will instruct the transition to MODE_ON immediately
@ -252,13 +196,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual void setParentQueue(MessageQueueId_t parentQueueId);
/** @brief Implementation required for HasActionIF */
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t *data, size_t size) override;
/** @brief Implementations required for HasActionIF */
ActionHelper *getActionHelper() override;
ReturnValue_t executeAction(Action *action) override;
Mode_t getTransitionSourceMode() const;
Submode_t getTransitionSourceSubMode() const;
virtual void getMode(Mode_t *mode, Submode_t *submode);
void getMode(Mode_t *mode, Submode_t *submode) override;
ModeHelper const *getModeHelper() const override;
HealthState getHealth();
ReturnValue_t setHealth(HealthState health);
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
@ -362,35 +307,10 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* - Anything else triggers an even with the returnvalue as a parameter
*/
virtual ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t *id) = 0;
/**
* @brief Build a device command packet from data supplied by a direct
* command (PUS Service 8)
* @details
* This will be called if an functional command via PUS Service 8 is received and is
* the primary interface for functional command instead of #executeAction for users. The
* supplied ActionId_t action ID will be converted to a DeviceCommandId_t command ID after
* an internal check whether the action ID is a key in the device command map.
*
* #rawPacket and #rawPacketLen should be set by this method to the packet to be sent.
* The existence of the command in the command map and the command size check against 0 are
* done by the base class.
*
* @param deviceCommand The command to build, already checked against deviceCommandMap
* @param commandData Pointer to the data from the direct command
* @param commandDataLen Length of commandData
* @return
* - @c returnvalue::OK to send command after #rawPacket and #rawPacketLen
* have been set.
* - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can
* be used if no reply is expected
* - Anything else triggers an event with the return code as a parameter as well as a
* step reply failed with the return code
*/
virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand,
const uint8_t *commandData,
size_t commandDataLen) = 0;
/* Reply handling */
// TODO add way to say, not enough data in buffer, try again later
// ComIF needs to decide if buffer will be appended or overwritten
/**
* @brief Scans a buffer for a valid reply.
* @details
@ -447,8 +367,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0;
MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const;
ReturnValue_t finishAction(bool success, DeviceCommandId_t action, ReturnValue_t result);
/**
* Helper function to get pending command. This is useful for devices
* like SPI sensors to identify the last sent command.
@ -508,7 +426,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* - @c returnvalue::FAILED else.
*/
ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
LocalPoolDataSetBase *replyDataSet = nullptr,
void *replyDataSet = nullptr,
size_t replyLen = 0, bool periodic = false,
bool hasDifferentReplyId = false,
DeviceCommandId_t replyId = 0,
@ -517,19 +435,19 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @brief This is a helper method to insert replies in the reply map.
* @param deviceCommand Identifier of the reply to add.
* @param maxDelayCycles The maximum number of delay cycles the reply waits
* until it times out.
* until it times out.
* @param periodic Indicates if the command is periodic (i.e. it is sent
* by the device repeatedly without request) or not. Default is aperiodic (0).
* Please note that periodic replies are disabled by default. You can enable them with
* #updatePeriodicReply
* by the device repeatedly without request) or not. Default is aperiodic (0).
* Please note that periodic replies are disabled by default. You can enable them with
* #updatePeriodicReply
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
* to provide a pointer to a Countdown object which will signal the timeout
* when expired
* to provide a pointer to a Countdown object which will signal the timeout
* when expired
* @return - @c returnvalue::OK when the command was successfully inserted,
* - @c returnvalue::FAILED else.
*/
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0,
void *dataSet = nullptr, size_t replyLen = 0,
bool periodic = false, Countdown *countdown = nullptr);
/**
@ -577,13 +495,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply, uint16_t delayCycles,
uint16_t maxDelayCycles, bool periodic = false);
/**
* @brief Can be used to set the dataset corresponding to a reply ID manually.
* @details
* Used by the local data pool manager.
*/
ReturnValue_t setReplyDataset(DeviceCommandId_t replyId, LocalPoolDataSetBase *dataset);
/**
* Get the time needed to transit from modeFrom to modeTo.
*
@ -602,15 +514,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) = 0;
/* Functions used by the local data pool manager */
/**
* This function is used to initialize the local housekeeping pool
* entries. The default implementation leaves the pool empty.
* @param localDataPoolMap
* @return
*/
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) override;
/**
* @brief Set all datapool variables that are update periodically in
* normal mode invalid
@ -620,16 +524,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* variables inside the dataset to invalid. The user can override this
* method optionally.
*/
virtual void setNormalDatapoolEntriesInvalid();
/**
* @brief Get the dataset handle for a given SID.
* @details
* The default implementation will use the deviceCommandMap to look for the corresponding
* dataset handle. The user can override this function if this is not desired.
* @param sid
* @return
*/
virtual LocalPoolDataSetBase *getDataSetHandle(sid_t sid) override;
virtual void setNormalDatapoolEntriesInvalid(); //TODO
DatapoolHelper* getDatapoolHelper() override;
HousekeepingHelper* getHousekeepingHelper() override;
/* HasModesIF overrides */
virtual void startTransition(Mode_t mode, Submode_t submode) override;
@ -709,12 +608,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
uint32_t parameter = 0);
/**
* @brief Can be overwritten by a child to specify the initial submode when device has been set
* to startup immediately.
*/
virtual Submode_t getInitialSubmode();
protected:
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
@ -744,18 +637,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
size_t rawPacketLen = 0;
/**
* Get the current mode
*
* set via setMode()
* The mode the device handler is currently in.
* This should never be changed directly but only with setMode()
*/
Mode_t getMode();
Mode_t mode;
/**
* Get the current Submode
*
* set via setMode()
* The submode the device handler is currently in.
* This should never be changed directly but only with setMode()
*/
Submode_t getSubmode();
Submode_t submode;
/** This is the counter value from performOperation(). */
uint8_t pstStep = 0;
@ -808,7 +698,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
/* Action helper for HasActionsIF */
ActionHelper actionHelper;
/* Housekeeping Manager */
LocalDataPoolManager poolManager;
DatapoolHelper datapoolHelper;
/**
* @brief Information about commands
@ -836,18 +726,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* This is used to keep track of pending replies.
*/
struct DeviceReplyInfo {
//! For Command-Reply combinations:
//! The maximum number of cycles the handler should wait for a reply
//! to this command.
//!
//! Reply Only:
//! For periodic replies, this variable will be the number of delay cycles between the replies.
//! For the non-periodic variant, this variable is not used as there is no meaningful
//! definition for delay
uint16_t maxDelayCycles;
//! This variable will be set to #maxDelayCycles if a reply is expected.
//! For non-periodic replies without a command, this variable is unused.
//! A runtime value of 0 means there is no reply is currently expected.
//! The currently remaining cycles the handler should wait for a reply,
//! 0 means there is no reply expected
uint16_t delayCycles;
size_t replyLen = 0; //!< Expected size of the reply.
//! if this is !=0, the delayCycles will not be reset to 0 but to
@ -856,7 +739,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
//! The dataset used to access housekeeping data related to the
//! respective device reply. Will point to a dataset held by
//! the child handler (if one is specified)
LocalPoolDataSetBase *dataSet = nullptr;
// LocalPoolDataSetBase *dataSet = nullptr; TODO
//! The command that expects this reply.
DeviceCommandMap::iterator command;
//! Instead of using delayCycles to specify the maximum time to wait for the device reply, it
@ -888,7 +771,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
//! and to send replies.
MessageQueueIF *commandQueue = nullptr;
DeviceHandlerThermalSet *thermalSet = nullptr;
void *thermalSet = nullptr; //TODO
/**
* Optional Error code. Can be set in doStartUp(), doShutDown() and
@ -903,7 +786,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
/** Pointer to the used FDIR instance. If not provided by child,
* default class is instantiated. */
FailureIsolationBase *fdirInstance;
object_id_t parent = objects::NO_OBJECT;
//! To correctly delete the default instance.
bool defaultFDIRUsed;
@ -944,8 +826,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW).
*
* If the transition is complete, the mode should be set to the target mode,
* which can be deduced from the current mode (which is
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]) using getBaseMode()
* which can be deduced from the current mode which is
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]
*
* The intended target submode is already set.
* The origin submode can be read in subModeFrom.
@ -1006,12 +888,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual void doOnActivity();
/**
* Required for HasLocalDataPoolIF, return a handle to the local pool manager.
* @return
*/
LocalDataPoolManager *getHkManagerHandle() override;
/**
* Returns the delay cycle count of a reply.
* A count != 0 indicates that the command is already executed.
@ -1103,7 +979,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* by #switches are on
* - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by
* #switches are off
* - @c PowerSwitchIF::returnvalue::FAILED if an error occured
* - @c returnvalue::FAILED if an error occured
*/
ReturnValue_t getStateOfSwitches();
@ -1191,22 +1067,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual ReturnValue_t doSendReadHook();
/**
* Send a RMAP getRead command.
*
* The size of the getRead command is #maxDeviceReplyLen.
* This is always executed, independently from the current mode.
*/
virtual void doSendRead(void);
/**
* Check the getRead reply and the contained data.
*
* If data was received scanForReply() and, if successful, handleReply()
* are called. If the current mode is @c MODE_RAW, the received packet
* is sent to the commanding object via commandQueue.
*/
virtual void doGetRead();
private:
/**
* State a cookie is in.
@ -1257,18 +1117,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
uint32_t childTransitionDelay;
/**
* The mode the device handler is currently in.
* This should not be changed directly but only with setMode()
*/
Mode_t mode;
/**
* The submode the device handler is currently in.
* This should not be changed directly but only with setMode()
*/
Submode_t submode;
/**
* @brief The mode the current transition originated from
*
@ -1286,15 +1134,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
Submode_t transitionSourceSubMode;
/**
* used to make the state machine continue from ON to NOMAL when
* a Device is commanded to NORMAL in OFF mode
*
* set in startTransition()
* evaluated in setMode() to continue to NORMAL when ON is reached
*/
bool continueToNormal;
/**
* read the command queue
*/
@ -1363,6 +1202,21 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* - if the action was successful, the reply timout counter is initialized
*/
void doGetWrite(void);
/**
* Send a RMAP getRead command.
*
* The size of the getRead command is #maxDeviceReplyLen.
* This is always executed, independently from the current mode.
*/
void doSendRead(void);
/**
* Check the getRead reply and the contained data.
*
* If data was received scanForReply() and, if successful, handleReply()
* are called. If the current mode is @c MODE_RAW, the received packet
* is sent to the commanding object via commandQueue.
*/
void doGetRead(void);
/**
* @brief Resets replies which use a timeout to detect missed replies.
@ -1400,8 +1254,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message);
virtual dur_millis_t getPeriodicOperationFrequency() const override;
void parseReply(const uint8_t *receivedData, size_t receivedDataLen);
void handleTransitionToOnMode(Mode_t commandedMode, Submode_t commandedSubmode);
@ -1416,11 +1268,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
ReturnValue_t errorCode = returnvalue::FAILED,
const char *errorPrint = nullptr);
/**
* @brief Disables all commands and replies when device is set to MODE_OFF
*/
void disableCommandsAndReplies();
};
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */

View File

@ -4,7 +4,8 @@
#include "fsfw/health/HealthTableIF.h"
#include "fsfw/modes/HasModesIF.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/power/Fuse.h"
//#include "fsfw/power/Fuse.h"
#include <fsfw/power/PowerSwitchIF.h>
#include "fsfw/serviceinterface/ServiceInterfaceStream.h"
#include "fsfw/thermal/ThermalComponentIF.h"
@ -29,7 +30,6 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
switch (event->getEvent()) {
case HasModesIF::MODE_TRANSITION_FAILED:
case HasModesIF::OBJECT_IN_INVALID_MODE:
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
// We'll try a recovery as long as defined in MAX_REBOOT.
// Might cause some AssemblyBase cycles, so keep number low.
handleRecovery(event->getEvent());
@ -78,16 +78,16 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
}
}
break;
case Fuse::FUSE_WENT_OFF:
// Not so good, because PCDU reacted.
case Fuse::POWER_ABOVE_HIGH_LIMIT:
// Better, because software detected over-current.
setFaulty(event->getEvent());
break;
case Fuse::POWER_BELOW_LOW_LIMIT:
// Device might got stuck during boot, retry.
handleRecovery(event->getEvent());
break;
// case Fuse::FUSE_WENT_OFF:
// // Not so good, because PCDU reacted.
// case Fuse::POWER_ABOVE_HIGH_LIMIT:
// // Better, because software detected over-current.
// setFaulty(event->getEvent());
// break;
// case Fuse::POWER_BELOW_LOW_LIMIT:
// // Device might got stuck during boot, retry.
// handleRecovery(event->getEvent());
// break;
//****Thermal*****
case ThermalComponentIF::COMPONENT_TEMP_LOW:
case ThermalComponentIF::COMPONENT_TEMP_HIGH:

View File

@ -2,8 +2,8 @@
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_
#include "../action/HasActionsIF.h"
#include "../datapoollocal/localPoolDefinitions.h"
#include "../events/Event.h"
#include "../introspection/ClasslessEnum.h"
#include "../ipc/MessageQueueSenderIF.h"
#include "../modes/HasModesIF.h"
#include "DeviceHandlerMessage.h"
@ -24,6 +24,9 @@ class DeviceHandlerIF {
static const DeviceCommandId_t RAW_COMMAND_ID = -1;
static const DeviceCommandId_t NO_COMMAND_ID = -2;
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
using dh_heater_request_t = uint8_t;
using dh_thermal_state_t = int8_t;
@ -34,23 +37,71 @@ class DeviceHandlerIF {
* The mode of the device itself is transparent to the user but related to the mode of the
* handler. MODE_ON and MODE_OFF are included in hasModesIF.h
*/
FSFW_CLASSLESS_ENUM(
DeviceHandlerMode, Mode_t,
//! The device is powered and ready to perform operations. In this mode, no
//! commands are sent by the device handler itself, but direct commands can be
//! commanded and will be executed/forwarded to the device
//! This is an alias of MODE_ON to have the FSFW_ENUM complete for introspection
((DEVICEHANDLER_MODE_ON, HasModesIF::MODE_ON, "On"))
//! The device is powered off. The only command accepted in this
//! mode is a mode change to on.
//! This is an alias of MODE_OFF to have the FSFW_ENUM complete for introspection
((DEVICEHANDLER_MODE_OFF, HasModesIF::MODE_OFF, "Off"))
//! The device is powered on and the device handler periodically sends
//! commands. The commands to be sent are selected by the handler
//! according to the submode.
((MODE_NORMAL, 2, "Normal"))
//! The device is powered on and ready to perform operations. In this mode,
//! raw commands can be sent. The device handler will send all replies
//! received from the command back to the commanding object as raw TM
((MODE_RAW, 3, "Raw"))
//! The device is shut down but the switch could not be turned off, so the
//! device still is powered. In this mode, only a mode change to @c MODE_OFF
//! can be commanded, which tries to switch off the device again.
((MODE_ERROR_ON, 4, "Error")))
// MODE_ON = 0, //!< The device is powered and ready to perform operations. In this mode, no
// commands are sent by the device handler itself, but direct commands van be commanded and will
// be interpreted MODE_OFF = 1, //!< The device is powered off. The only command accepted in this
// mode is a mode change to on.
//! The device is powered on and the device handler periodically sends
//! commands. The commands to be sent are selected by the handler
//! according to the submode.
static const Mode_t MODE_NORMAL = 2;
//! The device is powered on and ready to perform operations. In this mode,
//! raw commands can be sent. The device handler will send all replies
//! received from the command back to the commanding object.
static const Mode_t MODE_RAW = 3;
//! The device is shut down but the switch could not be turned off, so the
//! device still is powered. In this mode, only a mode change to @c MODE_OFF
//! can be commanded, which tries to switch off the device again.
static const Mode_t MODE_ERROR_ON = 4;
//! This is a transitional state which can not be commanded. The device
//! handler performs all commands to get the device in a state ready to
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
//! This is a transitional state which can not be commanded.
//! The device handler performs all actions and commands to get the device
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
//! transition if available.
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
//! It is possible to set the mode to _MODE_TO_ON to use the to on
//! transition if available.
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
//! transition if available.
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
//! transition if available.
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
//! This is a transitional state which can not be commanded.
//! The device is shut down and ready to be switched off.
//! After the command to set the switch off has been sent,
//! the mode changes to @c MODE_WAIT_OFF
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
//! This is a transitional state which can not be commanded. The device
//! will be switched on in this state. After the command to set the switch
//! on has been sent, the mode changes to @c MODE_WAIT_ON.
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
//! This is a transitional state which can not be commanded. The switch has
//! been commanded off and the handler waits for it to be off.
//! When the switch is off, the mode changes to @c MODE_OFF.
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
//! This is a transitional state which can not be commanded. The switch
//! 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.
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;
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH;
static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, severity::LOW);
@ -65,7 +116,6 @@ class DeviceHandlerIF {
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
@ -119,10 +169,10 @@ class DeviceHandlerIF {
NOTHING //!< Do nothing.
};
static constexpr uint32_t DEFAULT_THERMAL_SET_ID = sid_t::INVALID_SET_ID - 1;
static constexpr uint32_t DEFAULT_THERMAL_SET_ID = 0; // TODO sid_t::INVALID_SET_ID - 1;
static constexpr lp_id_t DEFAULT_THERMAL_STATE_POOL_ID = localpool::INVALID_LPID - 2;
static constexpr lp_id_t DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID = localpool::INVALID_LPID - 1;
static constexpr int DEFAULT_THERMAL_STATE_POOL_ID = 0; // TODOlocalpool::INVALID_LPID - 2;
static constexpr int DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID = 0; // TODOlocalpool::INVALID_LPID - 1;
/**
* Default Destructor

View File

@ -1,10 +1,9 @@
#ifndef FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
#define FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/objectmanager/SystemObjectIF.h"
#include "fsfw/serialize/SerializeIF.h"
#include "fsfw/util/dataWrapper.h"
#include "../action/HasActionsIF.h"
#include "../objectmanager/SystemObjectIF.h"
#include "../serialize/SerializeIF.h"
class DeviceTmReportingWrapper : public SerializeIF {
public:

View File

@ -8,9 +8,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
parentQueue(parentQueue),
commandQueue(),
healthHelper(this, setObjectId) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
commandQueue = QueueFactory::instance()->createMessageQueue(3);
}
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }

View File

@ -15,15 +15,16 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
{fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, sizeof(EventIdRangeMatcher)},
{fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, sizeof(ReporterRangeMatcher)}};
EventManager::EventManager(object_id_t setObjectId)
EventManager::EventManager(object_id_t setObjectId, uint32_t eventQueueDepth)
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
mutex = MutexFactory::instance()->createMutex();
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
eventReportQueue = QueueFactory::instance()->createMessageQueue(
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
eventQueueDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
}
EventManager::~EventManager() {
listenerList.clear();
QueueFactory::instance()->deleteMessageQueue(eventReportQueue);
MutexFactory::instance()->deleteMutex(mutex);
}
@ -38,6 +39,16 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
if (result == returnvalue::OK) {
#if FSFW_OBJ_EVENT_TRANSLATION == 1
printEvent(&message);
#else
//TODO
sif::debug << "EventManager: ";
sif::debug << "0x" << std::hex << std::setw(8) << std::setfill('0') << message.getReporter()
<< std::setfill(' ') << std::dec;
sif::debug << " reported event with ID " << message.getEventId() << std::endl;
sif::debug << std::hex << "P1 Hex: 0x"
<< message.getParameter1() << " | P1 Dec: " << std::dec << message.getParameter1()
<< std::hex << " | P2 Hex: 0x" << message.getParameter2()
<< " | P2 Dec: " << std::dec << message.getParameter2() << std::endl;
#endif
notifyListeners(&message);
}
@ -73,9 +84,14 @@ ReturnValue_t EventManager::registerListener(MessageQueueId_t listener,
if (!result.second) {
return returnvalue::FAILED;
}
return returnvalue::OK;
}
ReturnValue_t EventManager::unregisterListener(MessageQueueId_t listener) {
return listenerList.erase(listener) == 1 ? returnvalue::OK : returnvalue::FAILED;
}
ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) {
return subscribeToEventRange(listener, event);
}

View File

@ -21,9 +21,7 @@ extern const char* translateEvents(Event event);
class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject {
public:
static const uint16_t MAX_EVENTS_PER_CYCLE = 80;
EventManager(object_id_t setObjectId);
EventManager(object_id_t setObjectId, uint32_t eventQueueDepth);
virtual ~EventManager();
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
@ -31,6 +29,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
MessageQueueId_t getEventReportQueue();
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
ReturnValue_t unregisterListener(MessageQueueId_t listener) override;
ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event);
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object);
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,

View File

@ -18,6 +18,7 @@ class EventManagerIF {
virtual ReturnValue_t registerListener(MessageQueueId_t listener,
bool forwardAllButSelected = false) = 0;
virtual ReturnValue_t unregisterListener(MessageQueueId_t listener) = 0;
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;

View File

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

View File

@ -9,9 +9,8 @@
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
uint8_t messageDepth, uint8_t parameterDomainBase)
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
auto mqArgs = MqArgs(owner, static_cast<void*>(this));
eventQueue = QueueFactory::instance()->createMessageQueue(
messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
eventQueue =
QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
}
FailureIsolationBase::~FailureIsolationBase() {
@ -24,7 +23,7 @@ FailureIsolationBase::~FailureIsolationBase() {
#endif
return;
}
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId);
manager->unregisterListener(eventQueue->getId());
QueueFactory::instance()->deleteMessageQueue(eventQueue);
}
@ -62,12 +61,11 @@ ReturnValue_t FailureIsolationBase::initialize() {
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
if (parentIF == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FailureIsolationBase::intialize: Parent object "
<< "invalid" << std::endl;
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
#else
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
sif::printError("Make sure it implements ConfirmsFailuresIF\n");
sif::error << "FailureIsolationBase::intialize: Parent object"
<< "invalid." << std::endl;
#endif
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
return returnvalue::FAILED;

View File

@ -12,12 +12,13 @@
class FailureIsolationBase : public ConfirmsFailuresIF, public HasParametersIF {
public:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
//! FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO);
//! FDIR tries to restart device. Par1: event that caused recovery.
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
//! FDIR turns off device. Par1: event that caused recovery.
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
static const Event FDIR_CHANGED_STATE =
MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
//!< (oldState) to par1 (newState).
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(
3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);

View File

@ -40,7 +40,6 @@ class HasFileSystemIF {
//! [EXPORT] : P1: Can be file system specific error code
static constexpr ReturnValue_t GENERIC_FILE_ERROR = MAKE_RETURN_CODE(0);
static constexpr ReturnValue_t GENERIC_DIR_ERROR = MAKE_RETURN_CODE(1);
static constexpr ReturnValue_t FILESYSTEM_INACTIVE = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t GENERIC_RENAME_ERROR = MAKE_RETURN_CODE(3);
//! [EXPORT] : File system is currently busy

View File

@ -44,13 +44,13 @@ class Type : public SerializeIF {
static ActualType_t getActualType(uint8_t ptc, uint8_t pfc);
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override;
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override;
private:
ActualType_t actualType;

View File

@ -24,7 +24,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
MatchTree(iterator root, uint8_t maxDepth = -1)
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
virtual ~MatchTree() {}
virtual ~MatchTree() { clear(); }
virtual bool match(T number) override { return matchesTree(number); }
bool matchesTree(T number) {
iterator iter = this->begin();
@ -176,6 +176,45 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
return cleanUpElement(position);
}
void clear() {
Node* localRoot = BinaryTree<SerializeableMatcherIF<T>>::rootNode;
if (localRoot == nullptr) {
return;
}
Node* node = localRoot->left;
while (true) {
if (node->left != nullptr) {
node = node->left;
continue;
}
if (node->right != nullptr) {
node = node->right;
continue;
}
if (node->parent == nullptr) {
// this is the root node with no children
if (node->value != nullptr) {
cleanUpElement(iterator(node));
}
return;
}
// leaf
{
Node* parent = node->parent;
if (parent->left == node) {
parent->left = nullptr;
} else {
parent->right = nullptr;
}
cleanUpElement(iterator(node));
node = parent;
}
}
}
virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; }
bool matchSubtree(iterator iter, T number) {

View File

@ -1,8 +1,8 @@
#include "fsfw/globalfunctions/timevalOperations.h"
timeval& operator+=(timeval& lhs, const timeval& rhs) {
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
sum += rhs.tv_sec * 1000000. + rhs.tv_usec;
int64_t sum = static_cast<int64_t>(lhs.tv_sec) * 1000000. + lhs.tv_usec;
sum += static_cast<int64_t>(rhs.tv_sec) * 1000000. + rhs.tv_usec;
lhs.tv_sec = sum / 1000000;
lhs.tv_usec = sum - lhs.tv_sec * 1000000;
return lhs;

View File

@ -5,7 +5,11 @@
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId)
: objectId(objectId), owner(owner) {}
HealthHelper::~HealthHelper() { healthTable->removeObject(objectId); }
HealthHelper::~HealthHelper() {
if (healthTable != nullptr) {
healthTable->removeObject(objectId);
}
}
ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) {
switch (message->getCommand()) {

View File

@ -6,8 +6,6 @@
HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) {
mutex = MutexFactory::instance()->createMutex();
;
mapIterator = healthMap.begin();
}

View File

@ -8,6 +8,8 @@
#include "HealthTableIF.h"
class HealthTable : public HealthTableIF, public SystemObject {
friend class CServiceHealthCommanding;
public:
explicit HealthTable(object_id_t objectid);
~HealthTable() override;

View File

@ -1,2 +1,2 @@
target_sources(${LIB_FSFW_NAME} PRIVATE HousekeepingMessage.cpp
PeriodicHousekeepingHelper.cpp)
target_sources(${LIB_FSFW_NAME} PRIVATE HousekeepingHelper.cpp
HousekeepingSet.cpp )

View File

@ -0,0 +1,16 @@
#pragma once
#include <fsfw/tmtc/FsfwProtocolHeader.h>
#include "HousekeepingHelper.h"
class GeneratesHousekeepingIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::GENERATES_HOUSEKEEPING;
enum Functions : FsfwProtocolHeader::FunctionType_t { REPORT };
virtual ~GeneratesHousekeepingIF() = default;
virtual HousekeepingHelper* getHousekeepingHelper() = 0;
};

View File

@ -0,0 +1,46 @@
#include "HousekeepingHelper.h"
#include <fsfw/objectmanager/ObjectManager.h>
#include "GeneratesHousekeepingIF.h"
HousekeepingHelper::HousekeepingHelper(GeneratesHousekeepingIF* owner) : owner(owner) {}
ReturnValue_t HousekeepingHelper::initialize() {
tmManager = ObjectManager::instance()->get<TmManager>(objects::TM_MANAGER);
if (tmManager == nullptr) {
return returnvalue::FAILED;
}
return returnvalue::OK;
}
const HousekeepingSet* HousekeepingHelper::getHousekeepingSet(HousekeepingSetId_t id) {
auto iter = housekeepingSets.find(id);
if (iter == housekeepingSets.end()) {
return nullptr;
}
return iter->second;
}
void HousekeepingHelper::registerSet(HousekeepingSet* set) {
auto id = set->getId();
housekeepingSets.emplace(id, set);
}
ReturnValue_t HousekeepingHelper::reportHousekeeping(HousekeepingSet* set, const Action* action) {
SystemObjectIF* ownerAsObject = dynamic_cast<SystemObjectIF*>(owner);
if (ownerAsObject == nullptr) {
sif::error << "Duuuuuuuude, what the hell?" << std::endl;
return returnvalue::FAILED;
}
store_address_t tc;
size_t tcOffset = 0;
if (action != nullptr) {
tc = action->tc;
tcOffset = action->tcOffset;
}
return tmManager->sendTmPacket(ownerAsObject->getObjectId(),
GeneratesHousekeepingIF::INTERFACE_ID,
GeneratesHousekeepingIF::Functions::REPORT, set, tc, tcOffset);
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <fsfw/returnvalues/returnvalue.h>
#include <fsfw/serialize/SerializeIF.h>
#include <fsfw/tmtc/TmManager.h>
#include <map>
#include "HousekeepingSet.h"
class HousekeepingHelper {
friend class HousekeepingSet;
public:
HousekeepingHelper(GeneratesHousekeepingIF* owner);
~HousekeepingHelper() = default;
const HousekeepingSet* getHousekeepingSet(HousekeepingSetId_t id);
const std::map<HousekeepingSetId_t, HousekeepingSet*>* getHousekeepingSets() const {
return &housekeepingSets;
}
ReturnValue_t initialize();
protected:
GeneratesHousekeepingIF* owner;
TmManager* tmManager = nullptr;
void registerSet(HousekeepingSet* set);
ReturnValue_t reportHousekeeping(HousekeepingSet* set, const Action* action = nullptr);
private:
std::map<HousekeepingSetId_t, HousekeepingSet*> housekeepingSets;
};

View File

@ -0,0 +1,146 @@
#include "HousekeepingSet.h"
#include <fsfw/datapool/DatasetEntryIF.h>
#include "GeneratesHousekeepingIF.h"
#ifdef FSFW_INTROSPECTION
HousekeepingSet::HousekeepingSet(GeneratesHousekeepingIF* owner, const EnumIF &id) {
if (owner != nullptr) {
helper = owner->getHousekeepingHelper();
helper->registerSet(this);
}
this->id = id.getValue();
description = id.getDescription();
}
const char* HousekeepingSet::getDescription() const { return description; }
#else
HousekeepingSet::HousekeepingSet(GeneratesHousekeepingIF* owner, HousekeepingSetId_t id) : id(id) {
if (owner != nullptr) {
helper = owner->getHousekeepingHelper();
helper->registerSet(this);
}
}
#endif
HousekeepingSet::~HousekeepingSet() {}
void HousekeepingSet::report(const Action* action) {
if (helper != nullptr) {
helper->reportHousekeeping(this, action);
}
}
ReturnValue_t HousekeepingSet::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(&id, buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
for (auto parameter : parameterList) {
result = parameter->serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
}
// Fill valid flags
size_t index = 0;
for (auto parameter : parameterList) {
size_t byteIndex = index / 8;
size_t bitIndex = index % 8;
if (*size + byteIndex > maxSize) { // TODO audition me
return SerializeIF::STREAM_TOO_SHORT;
}
/**
* check if the parameter is a datasetParameter which knows its validity
* If not, just set to valid
*/
DatasetEntryIF* dataSetParameter = dynamic_cast<DatasetEntryIF*>(parameter);
if (dataSetParameter != nullptr) {
if (dataSetParameter->getValid()) {
(*buffer)[byteIndex] |= (1 << bitIndex);
} else {
(*buffer)[byteIndex] &= ~(1 << bitIndex);
}
} else {
(*buffer)[byteIndex] |= (1 << bitIndex);
}
index++;
}
*size += (parameterList.size() - 1) / 8 + 1;
if (*size > maxSize) {
// how did we end up here
return SerializeIF::STREAM_TOO_SHORT;
}
*buffer += (parameterList.size() - 1) / 8 + 1;
return returnvalue::OK;
}
size_t HousekeepingSet::getSerializedSize() const {
size_t size = SerializeAdapter::getSerializedSize(&id);
for (auto parameter : parameterList) {
size += parameter->getSerializedSize();
}
const size_t validBytes = (parameterList.size() - 1) / 8 + 1;
size += validBytes;
return size;
}
ReturnValue_t HousekeepingSet::deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
ReturnValue_t result = returnvalue::OK;
/**
* When deserializing, the id needs to be deserialized first, to find the correct class to
* deserialize with. Consequentely, it is assumed, that the pointer was already advanced
*
* SerializeAdapter::deSerialize(&id, buffer, size, streamEndianness); if (result !=
*/
for (auto parameter : *getParameters()) {
result = parameter->deSerialize(buffer, size, streamEndianness);
if (result != returnvalue::OK) {
return result;
}
}
// read valid flags
size_t index = 0;
for (auto parameter : parameterList) {
size_t byteIndex = index / 8;
size_t bitIndex = index % 8;
if (byteIndex > *size) { // TODO audition me
return SerializeIF::BUFFER_TOO_SHORT;
}
/**
* check if the parameter is a datasetParameter which knows its validity
* If not, just set to valid
*/
DatasetEntryIF* dataSetParameter = dynamic_cast<DatasetEntryIF*>(parameter);
if (dataSetParameter != nullptr) {
bool valid = ((*buffer)[byteIndex] & (1 << bitIndex)) != 0;
dataSetParameter->setValid(valid);
}
index++;
}
if (*size < (parameterList.size() - 1) / 8 + 1) {
// how did we end up here
return SerializeIF::BUFFER_TOO_SHORT;
}
*size -= (parameterList.size() - 1) / 8 + 1;
*buffer += (parameterList.size() - 1) / 8 + 1;
return returnvalue::OK;
}
void HousekeepingSet::registerParameter(ParameterIF* parameter) {
parameterList.push_back(parameter);
}
std::vector<ParameterIF*> const* HousekeepingSet::getParameters() const { return &parameterList; }

View File

@ -0,0 +1,54 @@
#pragma once
#include <fsfw/action/Action.h>
#include <fsfw/introspection/Enum.h>
#include <fsfw/introspection/HasTmTcParametersIF.h>
#include <fsfw/serialize/SerializeIF.h>
#include <cstdint>
class HousekeepingHelper;
class GeneratesHousekeepingIF;
using HousekeepingSetId_t = uint32_t;
class HousekeepingSet : public HasTmTcParametersIF, public SerializeIF {
friend class ParameterIF;
public:
#ifdef FSFW_INTROSPECTION
HousekeepingSet(GeneratesHousekeepingIF* owner, const EnumIF &id);
#else
HousekeepingSet(GeneratesHousekeepingIF* owner, HousekeepingSetId_t id);
#endif
virtual ~HousekeepingSet();
HousekeepingSetId_t getId() const { return id; }
virtual void report(const Action* action = nullptr);
std::vector<ParameterIF*> const* getParameters() const override;
#ifdef FSFW_INTROSPECTION
const char* getDescription() const;
#endif
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const override;
size_t getSerializedSize() const override;
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;
protected:
HousekeepingHelper* helper = nullptr;
HousekeepingSetId_t id;
#ifdef FSFW_INTROSPECTION
const char* description;
#endif
std::vector<ParameterIF*> parameterList;
void registerParameter(ParameterIF* parameter) override;
};

View File

@ -54,8 +54,8 @@ class HousekeepingSnapshot : public SerializeIF {
HousekeepingSnapshot(uint8_t* timeStamp, size_t timeStampSize, LocalPoolObjectBase* dataSetPtr)
: timeStamp(timeStamp), timeStampSize(timeStampSize), updateData(dataSetPtr){};
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const {
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const {
if (timeStamp != nullptr) {
/* Endianness will always be MACHINE, so we can simply use memcpy
here. */
@ -70,15 +70,15 @@ class HousekeepingSnapshot : public SerializeIF {
return updateData->serialize(buffer, size, maxSize, streamEndianness);
}
virtual size_t getSerializedSize() const {
size_t getSerializedSize() const {
if (updateData == nullptr) {
return 0;
}
return timeStampSize + updateData->getSerializedSize();
}
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override {
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override {
if (*size < timeStampSize) {
return SerializeIF::STREAM_TOO_SHORT;
}

View File

@ -1,22 +1,22 @@
#ifndef FSFW_INTERNALERROR_INTERNALERRORDATASET_H_
#define FSFW_INTERNALERROR_INTERNALERRORDATASET_H_
#include <fsfw/datapoollocal/LocalPoolVariable.h>
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
#include <cstdint>
#include <fsfw/objectmanager/SystemObjectIF.h>
enum errorPoolIds { TM_HITS, QUEUE_HITS, STORE_HITS };
class InternalErrorDataset : public StaticLocalDataSet<3 * sizeof(uint32_t)> {
class InternalErrorDataset {
public:
static constexpr uint8_t ERROR_SET_ID = 0;
InternalErrorDataset(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, ERROR_SET_ID) {}
InternalErrorDataset(void* owner) {}
InternalErrorDataset(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, ERROR_SET_ID)) {}
InternalErrorDataset(object_id_t objectId) {}
lp_var_t<uint32_t> tmHits = lp_var_t<uint32_t>(sid.objectId, TM_HITS, this);
lp_var_t<uint32_t> queueHits = lp_var_t<uint32_t>(sid.objectId, QUEUE_HITS, this);
lp_var_t<uint32_t> storeHits = lp_var_t<uint32_t>(sid.objectId, STORE_HITS, this);
// lp_var_t<uint32_t> tmHits = lp_var_t<uint32_t>(sid.objectId, TM_HITS, this);
// lp_var_t<uint32_t> queueHits = lp_var_t<uint32_t>(sid.objectId, QUEUE_HITS, this);
// lp_var_t<uint32_t> storeHits = lp_var_t<uint32_t>(sid.objectId, STORE_HITS, this);
};
#endif /* FSFW_INTERNALERROR_INTERNALERRORDATASET_H_ */

View File

@ -1,34 +1,24 @@
#include "fsfw/internalerror/InternalErrorReporter.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include "fsfw/ipc/MutexFactory.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
: SystemObject(setObjectId),
poolManager(this, commandQueue),
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
internalErrorDataset(this) {
mutex = MutexFactory::instance()->createMutex();
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
InternalErrorReporter::~InternalErrorReporter() {
MutexFactory::instance()->deleteMutex(mutex);
}
void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
this->diagnosticPrintout = enable;
}
ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
CommandMessage message;
ReturnValue_t result = commandQueue->receiveMessage(&message);
if (result != MessageQueueIF::EMPTY) {
poolManager.handleHousekeepingMessage(&message);
}
uint32_t newQueueHits = getAndResetQueueHits();
uint32_t newTmHits = getAndResetTmHits();
uint32_t newStoreHits = getAndResetStoreHits();
@ -38,33 +28,33 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "InternalErrorReporter::performOperation: Errors "
<< "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
<< newStoreHits << std::endl;
<< "occured!" << std::endl;
sif::debug << "Queue errors: " << newQueueHits << std::endl;
sif::debug << "TM errors: " << newTmHits << std::endl;
sif::debug << "Store errors: " << newStoreHits << std::endl;
#else
sif::printDebug(
"InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
"| %lu\n",
static_cast<unsigned int>(newQueueHits), static_cast<unsigned int>(newTmHits),
static_cast<unsigned int>(newStoreHits));
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
#endif
}
}
#endif
{
PoolReadGuard readGuard(&internalErrorDataset);
if (readGuard.getReadResult() == returnvalue::OK) {
internalErrorDataset.queueHits.value += newQueueHits;
internalErrorDataset.storeHits.value += newStoreHits;
internalErrorDataset.tmHits.value += newTmHits;
internalErrorDataset.setValidity(true, true);
if ((newQueueHits != 0) or (newStoreHits != 0) or (newTmHits != 0)) {
internalErrorDataset.setChanged(true);
}
}
}
// {
// PoolReadGuard readGuard(&internalErrorDataset);
// if (readGuard.getReadResult() == returnvalue::OK) {
// internalErrorDataset.queueHits.value += newQueueHits;
// internalErrorDataset.storeHits.value += newStoreHits;
// internalErrorDataset.tmHits.value += newTmHits;
// internalErrorDataset.setValidity(true, true);
// if ((newQueueHits != 0) or (newStoreHits != 0) or (newTmHits != 0)) {
// internalErrorDataset.setChanged(true);
// }
// }
// }
poolManager.performHkOperation();
return returnvalue::OK;
}
@ -121,47 +111,15 @@ void InternalErrorReporter::incrementStoreHits() {
object_id_t InternalErrorReporter::getObjectId() const { return SystemObject::getObjectId(); }
MessageQueueId_t InternalErrorReporter::getCommandQueue() const {
return this->commandQueue->getId();
}
ReturnValue_t InternalErrorReporter::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(errorPoolIds::TM_HITS, &tmHitsEntry);
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, &queueHitsEntry);
localDataPoolMap.emplace(errorPoolIds::STORE_HITS, &storeHitsEntry);
poolManager.subscribeForDiagPeriodicPacket(subdp::DiagnosticsHkPeriodicParams(
internalErrorSid, false,
static_cast<float>(getPeriodicOperationFrequency()) / static_cast<float>(1000.0)));
internalErrorDataset.setValidity(true, true);
return returnvalue::OK;
}
dur_millis_t InternalErrorReporter::getPeriodicOperationFrequency() const {
return this->executingTask->getPeriodMs();
}
LocalPoolDataSetBase *InternalErrorReporter::getDataSetHandle(sid_t sid) {
return &internalErrorDataset;
}
void InternalErrorReporter::setTaskIF(PeriodicTaskIF *task) { this->executingTask = task; }
// MessageQueueId_t InternalErrorReporter::getCommandQueue() const {
// return this->commandQueue->getId();
// }
ReturnValue_t InternalErrorReporter::initialize() {
ReturnValue_t result = poolManager.initialize(commandQueue);
if (result != returnvalue::OK) {
return result;
}
return SystemObject::initialize();
}
ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() {
return poolManager.initializeAfterTaskCreation();
}
void InternalErrorReporter::setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
this->timeoutType = timeoutType;
this->timeoutMs = timeoutMs;
}
LocalDataPoolManager *InternalErrorReporter::getHkManagerHandle() { return &poolManager; }

View File

@ -2,7 +2,7 @@
#define FSFW_INTERNALERROR_INTERNALERRORREPORTER_H_
#include "InternalErrorReporterIF.h"
#include "fsfw/datapoollocal/LocalDataPoolManager.h"
// #include "fsfw/datapoollocal/LocalDataPoolManager.h"
#include "fsfw/internalerror/InternalErrorDataset.h"
#include "fsfw/ipc/MutexIF.h"
#include "fsfw/objectmanager/SystemObject.h"
@ -18,8 +18,7 @@
*/
class InternalErrorReporter : public SystemObject,
public ExecutableObjectIF,
public InternalErrorReporterIF,
public HasLocalDataPoolIF {
public InternalErrorReporterIF {
public:
InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth = 5);
@ -35,15 +34,10 @@ class InternalErrorReporter : public SystemObject,
virtual ~InternalErrorReporter();
virtual object_id_t getObjectId() const override;
virtual MessageQueueId_t getCommandQueue() const override;
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
virtual dur_millis_t getPeriodicOperationFrequency() const override;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
LocalDataPoolManager* getHkManagerHandle() override;
//virtual MessageQueueId_t getCommandQueue() const override;
virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
//virtual ReturnValue_t initializeAfterTaskCreation() override;
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual void queueMessageNotSent() override;
@ -52,19 +46,13 @@ class InternalErrorReporter : public SystemObject,
virtual void storeFull() override;
virtual void setTaskIF(PeriodicTaskIF* task) override;
protected:
MessageQueueIF* commandQueue;
LocalDataPoolManager poolManager;
PeriodicTaskIF* executingTask = nullptr;
// MessageQueueIF* commandQueue;
MutexIF* mutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 20;
sid_t internalErrorSid;
InternalErrorDataset internalErrorDataset;
bool diagnosticPrintout = true;
@ -72,9 +60,6 @@ class InternalErrorReporter : public SystemObject,
uint32_t queueHits = 0;
uint32_t tmHits = 0;
uint32_t storeHits = 0;
PoolEntry<uint32_t> tmHitsEntry = PoolEntry<uint32_t>();
PoolEntry<uint32_t> storeHitsEntry = PoolEntry<uint32_t>();
PoolEntry<uint32_t> queueHitsEntry = PoolEntry<uint32_t>();
uint32_t getAndResetQueueHits();
void incrementQueueHits();

View File

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

View File

@ -0,0 +1,48 @@
#pragma once
#include <fsfw/returnvalues/returnvalue.h>
#include <boost/preprocessor.hpp>
// TODO ifdef EnumIF, consistent naming of functions arrays and macros (probably enum values and
// descriptions)
#include "EnumIF.h"
#include "EnumCommon.h"
#ifdef FSFW_INTROSPECTION
#define FSFW_CLASSLESS_ENUM(name, type, elements) \
enum : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) }; \
\
class name : public EnumIF { \
public: \
enum : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) }; \
name(type value) : value(value) {} \
name() : value(-1) {} \
name(const name &other) : value(other.value) {} \
int64_t getValue() const override { return value; } \
operator type() { return value; } \
name &operator=(name other) { \
value = other.value; \
return *this; \
} \
name &operator=(type value) { \
this->value = value; \
return *this; \
} \
CREATE_KEY_ARRAY(elements, type) \
VALUE_CHECK(type) \
GET_INDEX() \
CREATE_DESCRIPTION_ARRAY(elements) \
GET_DESCRIPTION_FUNC() \
private: \
type value; \
};
#else
#define FSFW_CLASSLESS_ENUM(name, type, elements) \
enum name : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) };
#endif

Some files were not shown because too many files have changed in this diff Show More