Compare commits

..

175 Commits

Author SHA1 Message Date
43d4953e4a Merge remote-tracking branch 'ksat/mueller/master' into mueller/master 2021-05-27 14:10:12 +02:00
e6059812b5 Merge remote-tracking branch 'upstream/development' into mueller/master 2021-05-27 14:00:03 +02:00
46cfe7452a for for ISR variant 2021-05-27 13:40:01 +02:00
e6868464bf queue map manager working 2021-05-27 13:38:40 +02:00
e15f03fb0a added FreeRTOS queue map manager 2021-05-27 13:12:34 +02:00
59e7f0caae added more messages 2021-05-27 12:50:48 +02:00
a2deac3441 Merge branch 'mueller/master' of https://egit.irs.uni-stuttgart.de/KSat/fsfw into mueller/master 2021-05-27 12:47:14 +02:00
5eadcaf10d file system message update 2021-05-27 12:46:45 +02:00
2bf5a972e1 introduced std check 2021-05-27 11:56:52 +02:00
5d2c62e75d abstract function defined again 2021-05-26 14:15:48 +02:00
5ac68f731e Merge pull request 'Doc Update + PUS IDs' (#422) from mueller/another-update-package into development
Reviewed-on: #422
2021-05-25 14:49:10 +02:00
7fa0443725 Merge branch 'development' into mueller/another-update-package 2021-05-25 14:48:58 +02:00
f4cb63c53c Merge pull request 'TCP Server Update' (#421) from KSat/fsfw:mueller/tcp-server into development
Reviewed-on: #421
2021-05-25 14:13:49 +02:00
0cde6f317d Merge branch 'development' into mueller/tcp-server 2021-05-25 14:10:46 +02:00
2737bc390c Merge pull request 'Update Package' (#420) from KSat/fsfw:mueller/update-package into development
Reviewed-on: #420
2021-05-25 14:10:33 +02:00
07ba05b209 Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-05-25 14:06:18 +02:00
f3d9fb645e Merge remote-tracking branch 'ksat/mueller/master' into mueller/master 2021-05-25 14:05:59 +02:00
e9adaf672f Merge branch 'mueller/master' into eive/develop 2021-05-18 16:18:47 +02:00
fc4e65b2fc Merge remote-tracking branch 'ksat/mueller/master' into mueller/master 2021-05-18 15:55:31 +02:00
36030ef87c typo 2021-05-18 15:37:05 +02:00
b7060a9c78 update README 2021-05-18 15:35:47 +02:00
e147d5a4f5 some more information 2021-05-18 15:34:31 +02:00
a8c0d96c39 some fixes 2021-05-18 15:32:52 +02:00
ed27d388d5 added tmtc chapter in doc 2021-05-18 15:31:04 +02:00
e2ae9756f3 updated documentation 2021-05-18 15:12:48 +02:00
c07672f9b4 changed class id file for refactored modgen 2021-05-18 14:57:54 +02:00
6db2efc20d copmment block for fw class ids 2021-05-18 11:36:36 +02:00
94062c67d3 added more pus services 2021-05-18 11:28:37 +02:00
9e0146f579 comment added 2021-05-18 11:16:54 +02:00
d3423b30b0 minot changes 2021-05-18 11:14:26 +02:00
58a532fc4d added health service to fsfw objects 2021-05-18 11:13:28 +02:00
ac027e3ff2 Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-05-17 16:00:41 +02:00
ff6b4134a5 Merge remote-tracking branch 'ksat/mueller/master' into mueller/master 2021-05-17 14:13:53 +02:00
5847081a24 tweaks and fixes for TCP 2021-05-13 22:17:21 +02:00
0bc124fd21 renamed tcpip tasks 2021-05-13 21:46:46 +02:00
1e9c789287 Merge remote-tracking branch 'upstream/mueller/tcp-server' into mueller/master 2021-05-13 21:11:59 +02:00
b06113993c Merge remote-tracking branch 'origin/development' into mueller/master 2021-05-12 18:38:10 +02:00
4fa56a2f1d moved string port argument 2021-05-12 18:37:52 +02:00
a320e3e1ef Merge branch 'mueller/update-package' of https://egit.irs.uni-stuttgart.de/KSat/fsfw into mueller/update-package 2021-05-12 17:32:53 +02:00
4095be449a some more preprocessor replacements 2021-05-12 17:32:40 +02:00
d20f0c5da1 Merge branch 'development' into mueller/update-package 2021-05-12 17:25:37 +02:00
9496ed42e2 Merge pull request 'Implements Network Endianness' (#419) from gaisser/fsfw:gaisser_network_serialize into development
Reviewed-on: #419
2021-05-12 17:25:13 +02:00
14027e449c Merge remote-tracking branch 'gaisser/gaisser_network_serialize' into mueller/merge-test 2021-05-12 17:18:12 +02:00
1626b266d7 platform header file 2021-05-12 16:47:53 +02:00
d27f49c968 added platform header file 2021-05-12 16:38:02 +02:00
a6dd2d5dcb event manager update 2021-05-12 16:37:12 +02:00
8293e6b0c7 more include fixes 2021-05-12 14:48:39 +02:00
d81c6f40fb define fixes 2021-05-12 14:43:08 +02:00
5b23b928cf added missing include 2021-05-12 14:28:37 +02:00
cd016c8281 event manager printout refactoring 2021-05-12 13:40:26 +02:00
e1c91f82b7 some fixes and tweaks 2021-05-12 10:54:10 +02:00
9d0155d9ae Added a returnvalue 2021-05-11 15:30:49 +02:00
d807998f4d Added Missing includes in Host Osal
Updated correct defaults for Host MessageQueues
2021-05-11 15:25:38 +02:00
8b17c40aa6 Added Network Byte Order 2021-05-11 15:02:04 +02:00
d7d24bd9aa Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-05-05 22:48:29 +02:00
c1d30aad13 TCP server implementation finished
A lot of smaller tweaks and smaller refactoring done
in UDP TMTC bridge as well
2021-05-05 15:59:41 +02:00
126def219b continued tmtc server and bridge 2021-05-05 12:59:42 +02:00
08b9e92d25 Merge pull request 'PUS C Telemetry implementation' (#414) from mueller/pus-c-support into development
Reviewed-on: #414
2021-05-04 14:43:39 +02:00
86431c854b Merge remote-tracking branch 'origin/development' into mueller/pus-c-support 2021-05-04 14:07:56 +02:00
f3530d3c7e small format change for event to test 2021-04-30 23:59:45 +02:00
0a76c5b0b5 Merge pull request 'use timestamp size from FSFWConfig.h' (#418) from mueller/use-config-timestamp-size into development
Reviewed-on: #418
2021-04-29 20:54:45 +02:00
6ede3f9ba2 Merge remote-tracking branch 'origin/development' into mueller/pus-c-support 2021-04-29 20:24:37 +02:00
097244bf8b use timestamp size from FSFWConfig.h 2021-04-29 19:51:38 +02:00
5c9b1769c1 Merge remote-tracking branch 'origin/development' into mueller/master 2021-04-28 22:18:08 +02:00
413ff0d1b9 parameter wrapper bugfix 2021-04-26 14:17:57 +02:00
5273ffa721 Merge remote-tracking branch 'origin/meier/dhbMultipleReplies' into mueller/master 2021-04-25 11:08:54 +02:00
e7c00b5633 Merge branch 'mueller/master' into meier/dhbMultipleReplies 2021-04-25 10:49:56 +02:00
f2ab07c782 Merge branch 'meier/dhbMultipleReplies' into mueller/master 2021-04-24 23:55:37 +02:00
ff33a1274d deleted old bridge 2021-04-24 23:54:13 +02:00
e7cfd324ae Merge branch 'mueller/master' into meier/dhbMultipleReplies 2021-04-24 23:43:53 +02:00
52b549b97c adapted object factory to fsfw changes 2021-04-24 22:54:18 +02:00
cac9a0eecd Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-04-24 22:48:43 +02:00
56d43f5b49 better output 2021-04-24 22:46:12 +02:00
10e7e42388 Merge branch 'development' into meier/dhbMultipleReplies 2021-04-24 18:05:00 +02:00
fc34e7fd75 Merge branch 'development' of https://egit.irs.uni-stuttgart.de/eive/fsfw into development 2021-04-24 18:04:43 +02:00
18a9729c75 added multiple reply support 2021-04-24 13:52:06 +02:00
763347f203 Merge remote-tracking branch 'upstream/development' into mueller/master 2021-04-22 19:55:02 +02:00
1ff52e43a0 Merge remote-tracking branch 'origin/development' into mueller/master 2021-04-22 19:52:44 +02:00
7f1cbaef23 updated default cmakelists 2021-04-22 18:09:23 +02:00
3356ccc9d4 tested new comment export string for retvals 2021-04-22 17:45:46 +02:00
3f91803422 fixes from code review 2021-04-20 18:35:11 +02:00
5759c2cbe6 Merge remote-tracking branch 'origin/development' into mueller/pus-c-support 2021-04-20 18:03:49 +02:00
e45b8bc739 Merge remote-tracking branch 'origin/development' into mueller/pus-c-support 2021-04-20 16:31:35 +02:00
dcd72d421e Merge branch 'mueller/master' into mueller/pus-c-support 2021-04-20 16:19:04 +02:00
cc8c3aef3d removed unused interface 2021-04-20 16:18:39 +02:00
9352e15405 Merge remote-tracking branch 'origin/development' into mueller/pus-c-support 2021-04-20 16:07:21 +02:00
1cceda8e63 Merge branch 'mueller/thermal-handler' into mueller/master 2021-04-20 15:59:44 +02:00
8c4381eca6 Merge remote-tracking branch 'ksat/mueller/master' into mueller/master 2021-04-20 15:49:55 +02:00
29a05eb113 Merge remote-tracking branch 'ksat/mueller/master' into mueller/pus-c-support 2021-04-20 15:49:32 +02:00
534b4850df Merge remote-tracking branch 'upstream/development' into mueller/master 2021-04-20 15:36:18 +02:00
a66fc53396 config define moved, better warning 2021-04-20 15:31:03 +02:00
5471030c32 Merge remote-tracking branch 'origin/development' into mueller/master 2021-04-20 15:13:28 +02:00
770356f8b6 fix for warning print 2021-04-19 14:38:56 +02:00
62e409a9f2 doc fix 2021-04-15 10:07:39 +02:00
cf8a9996a7 added new test stub 2021-04-13 10:42:49 +02:00
fc7e401ddc pus c working 2021-04-13 01:24:26 +02:00
ed186b04df finalized PUS C TM support 2021-04-13 00:19:09 +02:00
f906605097 addes pus packet c implementation 2021-04-12 23:55:33 +02:00
9a2fbefc9f refactoring continued 2021-04-12 22:24:11 +02:00
07f1216316 error found 2021-04-12 22:12:18 +02:00
4faa5b0685 fixes 2021-04-12 22:02:16 +02:00
ae1dab1fce sth broke 2021-04-12 21:53:08 +02:00
9a5f717169 refactoring to allow PUS c implementation 2021-04-12 21:17:53 +02:00
d7d52439d7 added new option 2021-04-12 20:40:41 +02:00
5d93cf12f7 another coverity fix 2021-04-11 18:55:10 +02:00
438049bb80 another coverity fix 2021-04-11 18:50:48 +02:00
6e6fb62b3c last coverity fixes 2021-04-11 18:36:24 +02:00
7b8928ef47 Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-04-11 15:02:26 +02:00
924ea420a9 missing include for windows 2021-04-11 14:58:53 +02:00
fbe860c6a5 refactored addr print, using AI_PASSIVE now 2021-04-11 14:54:02 +02:00
8b266aa542 Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-04-11 11:52:09 +02:00
5144cbd789 additional inc path now in IF 2021-04-11 02:26:11 +02:00
720ce59680 Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-04-10 21:58:27 +02:00
f1ffa88e07 small bugfix 2021-04-10 14:29:00 +02:00
d4b26825af Merge branch 'mueller/master' of https://egit.irs.uni-stuttgart.de/fsfw/fsfw into mueller/master 2021-04-10 14:13:09 +02:00
7e249db15e Merge remote-tracking branch 'origin/mueller/host-osal-vector-mq' into mueller/master 2021-04-09 18:50:32 +02:00
83e7dbb1f0 Coveritx fixes 2021-04-09 16:17:21 +02:00
2e417c787d coverity 2021-04-09 16:14:14 +02:00
316310e993 coverity 2021-04-09 15:49:33 +02:00
6db0725aa4 coverity fix 2021-04-09 15:39:48 +02:00
e0d39b1feb coverity 2021-04-09 09:17:11 +02:00
d9a0a4f2ea coverity 2021-04-09 09:14:42 +02:00
b8c7a65709 coverity fix 2021-04-09 08:59:32 +02:00
d3c3a9147a bumped version number 2021-04-09 08:29:56 +02:00
40cc3c383b this should work 2021-04-09 00:45:04 +02:00
d92a20a669 coverity 2021-04-08 22:49:36 +02:00
c1f4ae08fb typo fix 2021-04-08 22:28:44 +02:00
2b84ab018c implemented mq properly 2021-04-08 20:53:54 +02:00
9e881b6a16 Merge remote-tracking branch 'origin/development' into mueller/master 2021-04-08 20:41:07 +02:00
905d525aa2 small fix DHB 2021-04-08 19:12:21 +02:00
e6a1a7cc2d coverity fix for event message 2021-04-08 19:10:49 +02:00
dd367bf083 coverity: initialize entry 2021-04-08 19:09:00 +02:00
8f4ab6d7ed coverity: initialize member 2021-04-08 19:07:51 +02:00
b30a3aaa38 coverity fix 2021-04-08 19:07:03 +02:00
efb7c8760a coverity action helper fix 2021-04-08 19:01:06 +02:00
bddd8720b2 another coverity fix 2021-04-08 18:59:48 +02:00
00d9a4f3ed more coverity fixes 2021-04-08 18:57:24 +02:00
f988271be4 coverity fixes 2021-04-08 18:53:22 +02:00
38d929c2a8 coverity fixes 2021-04-08 18:48:44 +02:00
e799e45198 bugfix for RTEMS 2021-04-08 16:20:24 +02:00
9ee1bd15c4 now fixed properly 2021-04-08 15:38:36 +02:00
cbeb78f089 Merge branch 'development' into mueller/master 2021-04-08 15:32:38 +02:00
80aab5f461 super evil bug 2021-04-08 15:25:22 +02:00
43ddb44573 fixed temperature sensor object 2021-04-07 22:12:01 +02:00
9f8a345e35 Merge remote-tracking branch 'upstream/development' into mueller/master 2021-04-07 21:53:11 +02:00
3ff5484415 disabled debugging mode 2021-04-07 13:44:03 +02:00
7322a7d0f5 improvements for ccsds distributor 2021-04-07 12:09:06 +02:00
0e76333d33 minor improvements for PUS distributor 2021-04-07 12:03:28 +02:00
dea2205908 improved output 2021-04-01 15:20:53 +02:00
d1a256cbf6 added missing include 2021-03-31 19:53:58 +02:00
f2da31239c Merge remote-tracking branch 'upstream/mueller/master' into development 2021-03-29 14:36:53 +02:00
42720e6f7d Merge branch 'development' of https://egit.irs.uni-stuttgart.de/eive/fsfw into development 2021-03-26 12:25:20 +01:00
83d0db8242 fixed udp bridge 2021-03-20 15:53:43 +01:00
533d164cac Merge remote-tracking branch 'upstream/mueller/udp-hotfix' into mueller/master 2021-03-20 14:59:43 +01:00
0e92fa4046 Merge remote-tracking branch 'upstream/development' into mueller/master 2021-03-19 15:41:58 +01:00
32b289cbec Merge pull request 'FSFW Update' (#4) from mueller/master into eive/develop
Reviewed-on: eive/fsfw#4
2021-03-19 15:40:15 +01:00
fa108f0a3b Merge branch 'development' of https://egit.irs.uni-stuttgart.de/eive/fsfw into development 2021-03-19 15:38:06 +01:00
f82cc1bca4 Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-03-08 11:47:54 +01:00
778ef4ef23 cleaned up a bit, no functional change 2021-03-06 20:36:54 +01:00
17b8d3fed0 printout for trans timeout 2021-03-06 18:12:41 +01:00
d57955ade7 Merge branch 'mueller/master' of https://egit.irs.uni-stuttgart.de/eive/fsfw into mueller/master 2021-03-05 21:12:21 +01:00
18e40d6248 Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-03-05 19:22:46 +01:00
41e30dcb6c Merge branch 'development' of https://egit.irs.uni-stuttgart.de/eive/fsfw into development 2021-03-04 19:14:12 +01:00
92f249dc62 zero size handling 2021-02-24 00:23:48 +01:00
f3cc664d4f small printout tweak 2021-02-23 22:07:32 +01:00
91f69aa34f Merge branch 'eive/develop' into mueller/master 2021-02-23 14:47:30 +01:00
8b561d073c Merge remote-tracking branch 'upstream/development' into eive/develop 2021-02-23 14:47:15 +01:00
c55cf8f279 Merge branch 'mueller/hotfix' into mueller/master 2021-02-23 14:41:50 +01:00
c5b2c47af4 Merge branch 'mueller/mutex-update' into mueller/master 2021-02-23 14:14:40 +01:00
f0178a8f73 preprocessor optimization 2021-02-23 14:13:55 +01:00
e1b57424f8 Merge branch 'mueller/mutex-update' into mueller/master 2021-02-23 14:12:04 +01:00
8d7d4c639a Merge branch 'mueller/mutex-update' into mueller/master 2021-02-23 14:11:16 +01:00
a3d245f5a0 mutex helper print support and nullptr check 2021-02-23 11:28:12 +01:00
1ccfb74709 Merge branch 'mueller/linux-no-deadline-missed-printout' into eive/develop 2021-02-22 18:45:39 +01:00
939fa16d1a Merge remote-tracking branch 'upstream/mueller/master' into development 2021-02-06 16:14:29 +01:00
78 changed files with 2367 additions and 975 deletions

View File

@ -18,6 +18,13 @@ add_library(${LIB_FSFW_NAME})
set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos) set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
elseif(${CMAKE_CXX_STANDARD} LESS 11)
message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++11 support")
endif()
if(NOT OS_FSFW) if(NOT OS_FSFW)
message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS") message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS")
# Assume host OS and autodetermine from OS_FSFW # Assume host OS and autodetermine from OS_FSFW

View File

@ -38,11 +38,12 @@ a starting point. The [configuration section](doc/README-config.md#top) provides
[1. High-level overview](doc/README-highlevel.md#top) <br> [1. High-level overview](doc/README-highlevel.md#top) <br>
[2. Core components](doc/README-core.md#top) <br> [2. Core components](doc/README-core.md#top) <br>
[3. OSAL overview](doc/README-osal.md#top) <br> [3. Configuration](doc/README-config.md#top) <br>
[4. PUS services](doc/README-pus.md#top) <br> [4. OSAL overview](doc/README-osal.md#top) <br>
[5. Device Handler overview](doc/README-devicehandlers.md#top) <br> [5. PUS services](doc/README-pus.md#top) <br>
[6. Controller overview](doc/README-controllers.md#top) <br> [6. Device Handler overview](doc/README-devicehandlers.md#top) <br>
[7. Local Data Pools](doc/README-localpools.md#top) <br> [7. Controller overview](doc/README-controllers.md#top) <br>
[8. Local Data Pools](doc/README-localpools.md#top) <br>

View File

@ -66,6 +66,10 @@ protected:
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override = 0; LocalDataPoolManager& poolManager) override = 0;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
// Mode abstract functions
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override = 0;
}; };

View File

@ -19,7 +19,8 @@ class VirtualChannelReception;
class DataLinkLayer : public CCSDSReturnValuesIF { class DataLinkLayer : public CCSDSReturnValuesIF {
public: public:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1;
static const Event RF_AVAILABLE = MAKE_EVENT(0, severity::INFO); //!< A RF available signal was detected. P1: raw RFA state, P2: 0 //! [EXPORT] : [COMMENT] A RF available signal was detected. P1: raw RFA state, P2: 0
static const Event RF_AVAILABLE = MAKE_EVENT(0, severity::INFO);
static const Event RF_LOST = MAKE_EVENT(1, severity::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0 static const Event RF_LOST = MAKE_EVENT(1, severity::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0
static const Event BIT_LOCK = MAKE_EVENT(2, severity::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0 static const Event BIT_LOCK = MAKE_EVENT(2, severity::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0
static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0 static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0

View File

@ -1,15 +1,23 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
ipc/missionMessageTypes.cpp
objects/FsfwFactory.cpp
pollingsequence/PollingSequenceFactory.cpp
)
# Should be added to include path
target_include_directories(${TARGET_NAME} PRIVATE target_include_directories(${TARGET_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
) )
if(NOT FSFW_CONFIG_PATH) target_sources(${TARGET_NAME} PRIVATE
set(FSFW_CONFIG_PATH ${CMAKE_CURRENT_SOURCE_DIR}) ipc/missionMessageTypes.cpp
pollingsequence/PollingSequenceFactory.cpp
objects/FsfwFactory.cpp
)
# If a special translation file for object IDs exists, compile it.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
target_sources(${TARGET_NAME} PRIVATE
objects/translateObjects.cpp
)
endif() endif()
# If a special translation file for events exists, compile it.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
target_sources(${TARGET_NAME} PRIVATE
events/translateEvents.cpp
)
endif()

View File

@ -17,6 +17,8 @@
#define FSFW_DISABLE_PRINTOUT 0 #define FSFW_DISABLE_PRINTOUT 0
#endif #endif
#define FSFW_USE_PUS_C_TELEMETRY 1
//! Can be used to disable the ANSI color sequences for C stdio. //! Can be used to disable the ANSI color sequences for C stdio.
#define FSFW_COLORED_OUTPUT 1 #define FSFW_COLORED_OUTPUT 1
@ -48,9 +50,9 @@
#define FSFW_USE_REALTIME_FOR_LINUX 1 #define FSFW_USE_REALTIME_FOR_LINUX 1
namespace fsfwconfig { namespace fsfwconfig {
//! Default timestamp size. The default timestamp will be an eight byte CDC
//! short timestamp. //! Default timestamp size. The default timestamp will be an seven byte CDC short timestamp.
static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8; static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 7;
//! Configure the allocated pool sizes for the event manager. //! Configure the allocated pool sizes for the event manager.
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;

View File

@ -1,12 +1,30 @@
Configuring the FSFW
## Configuring the FSFW ======
The FSFW can be configured via the `fsfwconfig` folder. A template folder has The FSFW can be configured via the `fsfwconfig` folder. A template folder has
been provided to have a starting point for this. The folder should be added been provided to have a starting point for this. The folder should be added
to the include path. to the include path. The primary configuration file is the `FSFWConfig.h` folder. Some
of the available options will be explained in more detail here.
# Auto-Translation of Events
### Configuring the Event Manager The FSFW allows the automatic translation of events, which allows developers to track triggered
events directly via console output. Using this feature requires:
1. `FSFW_OBJ_EVENT_TRANSLATION` set to 1 in the configuration file.
2. Special auto-generated translation files which translate event IDs and object IDs into
human readable strings. These files can be generated using the
[modgen Python scripts](https://git.ksat-stuttgart.de/source/modgen.git).
3. The generated translation files for the object IDs should be named `translatesObjects.cpp`
and `translateObjects.h` and should be copied to the `fsfwconfig/objects` folder
4. The generated translation files for the event IDs should be named `translateEvents.cpp` and
`translateEvents.h` and should be copied to the `fsfwconfig/events` folder
An example implementations of these translation file generators can be found as part
of the [SOURCE project here](https://git.ksat-stuttgart.de/source/sourceobsw/-/tree/development/generators)
or the [FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/generators)
## Configuring the Event Manager
The number of allowed subscriptions can be modified with the following The number of allowed subscriptions can be modified with the following
parameters: parameters:
@ -18,4 +36,5 @@ static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
} }
``` ```

View File

@ -19,8 +19,9 @@ A nullptr check of the returning Pointer must be done. This function is based on
```cpp ```cpp
template <typename T> T* ObjectManagerIF::get( object_id_t id ) template <typename T> T* ObjectManagerIF::get( object_id_t id )
``` ```
* A typical way to create all objects on startup is a handing a static produce function to the ObjectManager on creation. * A typical way to create all objects on startup is a handing a static produce function to the
By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards. ObjectManager on creation. By calling objectManager->initialize() the produce function will be
called and all SystemObjects will be initialized afterwards.
### Event Manager ### Event Manager
@ -36,14 +37,19 @@ By calling objectManager->initialize() the produce function will be called and a
### Stores ### Stores
* The message based communication can only exchange a few bytes of information inside the message itself. Therefore, additional information can * The message based communication can only exchange a few bytes of information inside the message
be exchanged with Stores. With this, only the store address must be exchanged in the message. itself. Therefore, additional information can be exchanged with Stores. With this, only the
* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC Store is used. For outgoing TM a TM store is used. store address must be exchanged in the message.
* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC
Store is used. For outgoing TM a TM store is used.
* All of them should use the Thread Safe Class storagemanager/PoolManager * All of them should use the Thread Safe Class storagemanager/PoolManager
### Tasks ### Tasks
There are two different types of tasks: There are two different types of tasks:
* The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the insertion to the Tasks. * The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the
* FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for DeviceHandlers, where polling should be in a defined order. An example can be found in defaultcfg/fsfwconfig/pollingSequence insertion to the Tasks.
* FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for
DeviceHandlers, where polling should be in a defined order. An example can be found in
`defaultcfg/fsfwconfig/pollingSequence` folder

View File

@ -1,99 +1,135 @@
# High-level overview High-level overview
======
## Structure # Structure
The general structure is driven by the usage of interfaces provided by objects. The general structure is driven by the usage of interfaces provided by objects.
The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be widely available, even with older compilers. The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be
widely available, even with older compilers.
The FSFW uses dynamic allocation during the initialization but provides static containers during runtime. The FSFW uses dynamic allocation during the initialization but provides static containers during runtime.
This simplifies the instantiation of objects and allows the usage of some standard containers. This simplifies the instantiation of objects and allows the usage of some standard containers.
Dynamic Allocation after initialization is discouraged and different solutions are provided in the FSFW to achieve that. Dynamic Allocation after initialization is discouraged and different solutions are provided in the
The fsfw uses run-time type information but exceptions are not allowed. FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed.
### Failure Handling # Failure Handling
Functions should return a defined ReturnValue_t to signal to the caller that something has gone wrong. Functions should return a defined `ReturnValue_t` to signal to the caller that something has
Returnvalues must be unique. For this the function HasReturnvaluesIF::makeReturnCode or the Macro MAKE_RETURN can be used. gone wrong. Returnvalues must be unique. For this the function `HasReturnvaluesIF::makeReturnCode`
The CLASS_ID is a unique id for that type of object. See returnvalues/FwClassIds. or the macro `MAKE_RETURN` can be used. The `CLASS_ID` is a unique id for that type of object.
See `returnvalues/FwClassIds` folder. The user can add custom `CLASS_ID`s via the
`fsfwconfig` folder.
### OSAL # OSAL
The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS.
The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes. The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes.
The [OSAL README](doc/README-osal.md#top) provides more detailed information on provided components and how to use them. The [OSAL README](doc/README-osal.md#top) provides more detailed information on provided components
and how to use them.
### Core Components # Core Components
The FSFW has following core components. More detailed informations can be found in the The FSFW has following core components. More detailed informations can be found in the
[core component section](doc/README-core.md#top): [core component section](doc/README-core.md#top):
1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks with fixed timeslots 1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks
2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID to the object handles. with fixed timeslots
3. Static Stores: Different stores are provided to store data of variable size (like telecommands or small telemetry) in a pool structure without 2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID
using dynamic memory allocation. These pools are allocated up front. to the object handles.
3. Static Stores: Different stores are provided to store data of variable size (like telecommands
or small telemetry) in a pool structure without using dynamic memory allocation.
These pools are allocated up front.
3. Clock: This module provided common time related functions 3. Clock: This module provided common time related functions
4. EventManager: This module allows routing of events generated by `SystemObjects` 4. EventManager: This module allows routing of events generated by `SystemObjects`
5. HealthTable: A component which stores the health states of objects 5. HealthTable: A component which stores the health states of objects
### Static IDs in the framework # Static IDs in the framework
Some parts of the framework use a static routing address for communication. Some parts of the framework use a static routing address for communication.
An example setup of ids can be found in the example config in "defaultcft/fsfwconfig/objects/Factory::setStaticFrameworkObjectIds()". An example setup of ids can be found in the example config in `defaultcft/fsfwconfig/objects`
inside the function `Factory::setStaticFrameworkObjectIds()`.
### Events # Events
Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT. This works analog to the returnvalues. Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT.
Every object that needs own EventIds has to get a unique SUBSYSTEM_ID. This works analog to the returnvalues. Every object that needs own EventIds has to get a
Every SystemObject can call triggerEvent from the parent class. unique SUBSYSTEM_ID. Every SystemObject can call triggerEvent from the parent class.
Therefore, event messages contain the specific EventId and the objectId of the object that has triggered. Therefore, event messages contain the specific EventId and the objectId of the object that
has triggered.
### Internal Communication # Internal Communication
Components communicate mostly over Message through Queues. Components communicate mostly via Messages through Queues.
Those queues are created by calling the singleton QueueFactory::instance()->create(). Those queues are created by calling the singleton `QueueFactory::instance()->create()` which
will create `MessageQueue` instances for the used OSAL.
### External Communication # External Communication
The external communication with the mission control system is mostly up to the user implementation. The external communication with the mission control system is mostly up to the user implementation.
The FSFW provides PUS Services which can be used to but don't need to be used. The FSFW provides PUS Services which can be used to but don't need to be used.
The services can be seen as a conversion from a TC to a message based communication and back. The services can be seen as a conversion from a TC to a message based communication and back.
#### CCSDS Frames, CCSDS Space Packets and PUS ## TMTC Communication
If the communication is based on CCSDS Frames and Space Packets, several classes can be used to distributed the packets to the corresponding services. Those can be found in tcdistribution. The FSFW provides some components to facilitate TMTC handling via the PUS commands.
If Space Packets are used, a timestamper must be created. For example, a UDP or TCP PUS server socket can be opened on a specific port using the
An example can be found in the timemanager folder, this uses CCSDSTime::CDS_short. files located in `osal/common`. The FSFW example uses this functionality to allow sending telecommands
and receiving telemetry using the [TMTC commander application](https://github.com/spacefisch/tmtccmd).
Simple commands like the PUS Service 17 ping service can be tested by simply running the
`tmtc_client_cli.py` or `tmtc_client_gui.py` utility in
the [example tmtc folder](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/tmtc)
while the `fsfw_example` application is running.
#### Device Handlers More generally, any class responsible for handling incoming telecommands and sending telemetry
can implement the generic `TmTcBridge` class located in `tmtcservices`. Many applications
also use a dedicated polling task for reading telecommands which passes telecommands
to the `TmTcBridge` implementation.
## CCSDS Frames, CCSDS Space Packets and PUS
If the communication is based on CCSDS Frames and Space Packets, several classes can be used to
distributed the packets to the corresponding services. Those can be found in `tcdistribution`.
If Space Packets are used, a timestamper has to be provided by the user.
An example can be found in the `timemanager` folder, which uses `CCSDSTime::CDS_short`.
# Device Handlers
DeviceHandlers are another important component of the FSFW. DeviceHandlers are another important component of the FSFW.
The idea is, to have a software counterpart of every physical device to provide a simple mode, health and commanding interface. The idea is, to have a software counterpart of every physical device to provide a simple mode,
By separating the underlying Communication Interface with DeviceCommunicationIF, a device handler (DH) can be tested on different hardware. health and commanding interface. By separating the underlying Communication Interface with
The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction. `DeviceCommunicationIF`, a device handler (DH) can be tested on different hardware.
Device Handlers can be created by overriding `DeviceHandlerBase`. The DH has mechanisms to monitor the communication with the physical device which allow
A standard FDIR component for the DH will be created automatically but can be overwritten by the user. for FDIR reaction. Device Handlers can be created by implementing `DeviceHandlerBase`.
More information on DeviceHandlers can be found in the related [documentation section](doc/README-devicehandlers.md#top). A standard FDIR component for the DH will be created automatically but can
be overwritten by the user. More information on DeviceHandlers can be found in the
related [documentation section](doc/README-devicehandlers.md#top).
#### Modes, Health # Modes and Health
The two interfaces HasModesIF and HasHealthIF provide access for commanding and monitoring of components. The two interfaces `HasModesIF` and `HasHealthIF` provide access for commanding and monitoring
On-board Mode Management is implement in hierarchy system. of components. On-board Mode Management is implement in hierarchy system.
DeviceHandlers and Controllers are the lowest part of the hierarchy. DeviceHandlers and Controllers are the lowest part of the hierarchy.
The next layer are Assemblies. Those assemblies act as a component which handle redundancies of handlers. The next layer are Assemblies. Those assemblies act as a component which handle
Assemblies share a common core with the next level which are the Subsystems. redundancies of handlers. Assemblies share a common core with the next level which
are the Subsystems.
Those Assemblies are intended to act as auto-generated components from a database which describes the subsystem modes. Those Assemblies are intended to act as auto-generated components from a database which describes
The definitions contain transition and target tables which contain the DH, Assembly and Controller Modes to be commanded. the subsystem modes. The definitions contain transition and target tables which contain the DH,
Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a switch into any higher AOCS mode might first turn on the sensors, than the actuators and the controller as last component. Assembly and Controller Modes to be commanded.
Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a
switch into any higher AOCS mode might first turn on the sensors, than the actuators and the
controller as last component.
The target table is used to describe the state that is checked continuously by the subsystem. The target table is used to describe the state that is checked continuously by the subsystem.
All of this allows System Modes to be generated as Subsystem object as well from the same database. All of this allows System Modes to be generated as Subsystem object as well from the same database.
This System contains list of subsystem modes in the transition and target tables. This System contains list of subsystem modes in the transition and target tables.
Therefore, it allows a modular system to create system modes and easy commanding of those, because only the highest components must be commanded. Therefore, it allows a modular system to create system modes and easy commanding of those, because
only the highest components must be commanded.
The health state represents if the component is able to perform its tasks. The health state represents if the component is able to perform its tasks.
This can be used to signal the system to avoid using this component instead of a redundant one. This can be used to signal the system to avoid using this component instead of a redundant one.
The on-board FDIR uses the health state for isolation and recovery. The on-board FDIR uses the health state for isolation and recovery.
## Unit Tests # Unit Tests
Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include catch2 itself. More information on how to run these tests can be found in the separate Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include
catch2 itself. More information on how to run these tests can be found in the separate
[`fsfw_tests` reposoitory](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests) [`fsfw_tests` reposoitory](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests)

View File

@ -1,8 +1,6 @@
#include "EventManager.h" #include "EventManager.h"
#include "EventMessage.h" #include "EventMessage.h"
#include <FSFWConfig.h>
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
@ -115,53 +113,6 @@ ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener,
return result; return result;
} }
#if FSFW_OBJ_EVENT_TRANSLATION == 1
void EventManager::printEvent(EventMessage* message) {
const char *string = 0;
switch (message->getSeverity()) {
case severity::INFO:
#if DEBUG_INFO_EVENT == 1
string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "EVENT: ";
if (string != 0) {
sif::info << string;
} else {
sif::info << "0x" << std::hex << message->getReporter() << std::dec;
}
sif::info << " reported " << translateEvents(message->getEvent()) << " ("
<< std::dec << message->getEventId() << std::hex << ") P1: 0x"
<< message->getParameter1() << " P2: 0x"
<< message->getParameter2() << std::dec << std::endl;
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* DEBUG_INFO_EVENT == 1 */
break;
default:
string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "EventManager: ";
if (string != 0) {
sif::debug << string;
}
else {
sif::debug << "0x" << std::hex << message->getReporter() << std::dec;
}
sif::debug << " reported " << translateEvents(message->getEvent())
<< " (" << std::dec << message->getEventId() << ") "
<< std::endl;
sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1()
<< ", P1 Dec: " << std::dec << message->getParameter1()
<< std::endl;
sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2()
<< ", P2 Dec: " << std::dec << message->getParameter2()
<< std::endl;
#endif
break;
}
}
#endif
void EventManager::lockMutex() { void EventManager::lockMutex() {
mutex->lockMutex(timeoutType, timeoutMs); mutex->lockMutex(timeoutType, timeoutMs);
} }
@ -175,3 +126,85 @@ void EventManager::setMutexTimeout(MutexIF::TimeoutType timeoutType,
this->timeoutType = timeoutType; this->timeoutType = timeoutType;
this->timeoutMs = timeoutMs; this->timeoutMs = timeoutMs;
} }
#if FSFW_OBJ_EVENT_TRANSLATION == 1
void EventManager::printEvent(EventMessage* message) {
switch (message->getSeverity()) {
case severity::INFO: {
#if FSFW_DEBUG_INFO == 1
printUtility(sif::OutputTypes::OUT_INFO, message);
#endif /* DEBUG_INFO_EVENT == 1 */
break;
}
default:
printUtility(sif::OutputTypes::OUT_DEBUG, message);
break;
}
}
void EventManager::printUtility(sif::OutputTypes printType, EventMessage *message) {
const char *string = 0;
if(printType == sif::OutputTypes::OUT_INFO) {
string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "EventManager: ";
if (string != 0) {
sif::info << string;
}
else {
sif::info << "0x" << std::hex << std::setw(8) << std::setfill('0') <<
message->getReporter() << std::setfill(' ') << std::dec;
}
sif::info << " report event with ID " << message->getEventId() << std::endl;
sif::info << 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;
#else
if (string != 0) {
sif::printInfo("Event Manager: %s reported event with ID %d\n", string,
message->getEventId());
}
else {
sif::printInfo("Event Manager: Reporter ID 0x%08x reported event with ID %d\n",
message->getReporter(), message->getEventId());
}
sif::printInfo("P1 Hex: 0x%x | P1 Dec: %d | P2 Hex: 0x%x | P2 Dec: %d\n",
message->getParameter1(), message->getParameter1(),
message->getParameter2(), message->getParameter2());
#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */
}
else {
string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "EventManager: ";
if (string != 0) {
sif::debug << string;
}
else {
sif::debug << "0x" << std::hex << std::setw(8) << std::setfill('0') <<
message->getReporter() << std::setfill(' ') << std::dec;
}
sif::debug << " report 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;
#else
if (string != 0) {
sif::printDebug("Event Manager: %s reported event with ID %d\n", string,
message->getEventId());
}
else {
sif::printDebug("Event Manager: Reporter ID 0x%08x reported event with ID %d\n",
message->getReporter(), message->getEventId());
}
sif::printDebug("P1 Hex: 0x%x | P1 Dec: %d | P2 Hex: 0x%x | P2 Dec: %d\n",
message->getParameter1(), message->getParameter1(),
message->getParameter2(), message->getParameter2());
#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */
}
}
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */

View File

@ -6,6 +6,7 @@
#include <FSFWConfig.h> #include <FSFWConfig.h>
#include "../serviceinterface/ServiceInterface.h"
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "../storagemanager/LocalPool.h" #include "../storagemanager/LocalPool.h"
#include "../tasks/ExecutableObjectIF.h" #include "../tasks/ExecutableObjectIF.h"
@ -67,6 +68,7 @@ protected:
#if FSFW_OBJ_EVENT_TRANSLATION == 1 #if FSFW_OBJ_EVENT_TRANSLATION == 1
void printEvent(EventMessage *message); void printEvent(EventMessage *message);
void printUtility(sif::OutputTypes printType, EventMessage* message);
#endif #endif
void lockMutex(); void lockMutex();

View File

@ -1,30 +1,37 @@
#ifndef FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ #ifndef FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
#define FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ #define FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
#include <cstdint>
namespace SUBSYSTEM_ID { namespace SUBSYSTEM_ID {
enum { enum: uint8_t {
MEMORY = 22, MEMORY = 22,
OBSW = 26, OBSW = 26,
CDH = 28, CDH = 28,
TCS_1 = 59, TCS_1 = 59,
PCDU_1 = 42, PCDU_1 = 42,
PCDU_2 = 43, PCDU_2 = 43,
HEATER = 50, HEATER = 50,
T_SENSORS = 52, T_SENSORS = 52,
FDIR = 70, FDIR = 70,
FDIR_1 = 71, FDIR_1 = 71,
FDIR_2 = 72, FDIR_2 = 72,
HK = 73, HK = 73,
SYSTEM_MANAGER = 74, SYSTEM_MANAGER = 74,
SYSTEM_MANAGER_1 = 75, SYSTEM_MANAGER_1 = 75,
SYSTEM_1 = 79, SYSTEM_1 = 79,
PUS_SERVICE_1 = 80, PUS_SERVICE_1 = 80,
PUS_SERVICE_9 = 89, PUS_SERVICE_2 = 82,
PUS_SERVICE_17 = 97, PUS_SERVICE_3 = 83,
FW_SUBSYSTEM_ID_RANGE PUS_SERVICE_5 = 85,
PUS_SERVICE_6 = 86,
PUS_SERVICE_8 = 88,
PUS_SERVICE_9 = 89,
PUS_SERVICE_17 = 97,
PUS_SERVICE_23 = 103,
FW_SUBSYSTEM_ID_RANGE
}; };
} }
#endif /* FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ */ #endif /* FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ */

View File

@ -5,6 +5,15 @@
void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, void arrayprinter::print(const uint8_t *data, size_t size, OutputType type,
bool printInfo, size_t maxCharPerLine) { bool printInfo, size_t maxCharPerLine) {
if(size == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Size is zero, nothing to print" << std::endl;
#else
sif::printInfo("Size is zero, nothing to print\n");
#endif
return;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
if(printInfo) { if(printInfo) {
sif::info << "Printing data with size " << size << ": " << std::endl; sif::info << "Printing data with size " << size << ": " << std::endl;

View File

@ -22,11 +22,11 @@ public:
static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF;
//! No new messages on the queue //! No new messages on the queue
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1); static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1);
//! No space left for more messages //! [EXPORT] : [COMMENT] No space left for more messages
static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); static const ReturnValue_t FULL = MAKE_RETURN_CODE(2);
//! Returned if a reply method was called without partner //! [EXPORT] : [COMMENT] Returned if a reply method was called without partner
static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3); static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3);
//! Returned if the target destination is invalid. //! [EXPORT] : [COMMENT] Returned if the target destination is invalid.
static constexpr ReturnValue_t DESTINATION_INVALID = MAKE_RETURN_CODE(4); static constexpr ReturnValue_t DESTINATION_INVALID = MAKE_RETURN_CODE(4);
virtual ~MessageQueueIF() {} virtual ~MessageQueueIF() {}

View File

@ -1,5 +1,5 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE MemoryHelper.cpp
MemoryHelper.cpp MemoryMessage.cpp
MemoryMessage.cpp GenericFileSystemMessage.cpp
) )

View File

@ -0,0 +1,132 @@
#include "GenericFileSystemMessage.h"
void GenericFileSystemMessage::setCreateFileCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_CREATE_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setDeleteFileCommand(
CommandMessage* message, store_address_t storeId) {
message->setCommand(CMD_DELETE_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setCreateDirectoryCommand(
CommandMessage* message, store_address_t storeId) {
message->setCommand(CMD_CREATE_DIRECTORY);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setReportFileAttributesCommand(CommandMessage *message,
store_address_t storeId) {
message->setCommand(CMD_REPORT_FILE_ATTRIBUTES);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setReportFileAttributesReply(CommandMessage *message,
store_address_t storeId) {
message->setCommand(REPLY_REPORT_FILE_ATTRIBUTES);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setDeleteDirectoryCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_DELETE_DIRECTORY);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setLockFileCommand(CommandMessage *message,
store_address_t storeId) {
message->setCommand(CMD_LOCK_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setUnlockFileCommand(CommandMessage *message,
store_address_t storeId) {
message->setCommand(CMD_UNLOCK_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setSuccessReply(CommandMessage *message) {
message->setCommand(COMPLETION_SUCCESS);
}
void GenericFileSystemMessage::setFailureReply(CommandMessage *message,
ReturnValue_t errorCode, uint32_t errorParam) {
message->setCommand(COMPLETION_FAILED);
message->setParameter(errorCode);
message->setParameter2(errorParam);
}
store_address_t GenericFileSystemMessage::getStoreId(const CommandMessage* message) {
store_address_t temp;
temp.raw = message->getParameter2();
return temp;
}
ReturnValue_t GenericFileSystemMessage::getFailureReply(
const CommandMessage *message, uint32_t* errorParam) {
if(errorParam != nullptr) {
*errorParam = message->getParameter2();
}
return message->getParameter();
}
void GenericFileSystemMessage::setFinishStopWriteCommand(CommandMessage *message,
store_address_t storeId) {
message->setCommand(CMD_FINISH_APPEND_TO_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setFinishStopWriteReply(CommandMessage *message,
store_address_t storeId) {
message->setCommand(REPLY_FINISH_APPEND);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setCopyCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_COPY_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setWriteCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_APPEND_TO_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setReadCommand(CommandMessage* message,
store_address_t storeId) {
message->setCommand(CMD_READ_FROM_FILE);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setFinishAppendReply(CommandMessage* message,
store_address_t storageID) {
message->setCommand(REPLY_FINISH_APPEND);
message->setParameter2(storageID.raw);
}
void GenericFileSystemMessage::setReadReply(CommandMessage* message,
bool readFinished, store_address_t storeId) {
message->setCommand(REPLY_READ_FROM_FILE);
message->setParameter(readFinished);
message->setParameter2(storeId.raw);
}
void GenericFileSystemMessage::setReadFinishedReply(CommandMessage *message,
store_address_t storeId) {
message->setCommand(REPLY_READ_FINISHED_STOP);
message->setParameter2(storeId.raw);
}
bool GenericFileSystemMessage::getReadReply(const CommandMessage *message,
store_address_t *storeId) {
if(storeId != nullptr) {
(*storeId).raw = message->getParameter2();
}
return message->getParameter();
}

View File

@ -0,0 +1,113 @@
#ifndef MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_
#define MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_
#include <cstdint>
#include <fsfw/ipc/CommandMessageIF.h>
#include <fsfw/ipc/FwMessageTypes.h>
#include <fsfw/ipc/CommandMessage.h>
#include <fsfw/storagemanager/storeAddress.h>
/**
* @brief These messages are sent to an object implementing HasFilesystemIF.
* @details
* Enables a message-based file management. The user can add custo commands be implementing
* this generic class.
* @author Jakob Meier, R. Mueller
*/
class GenericFileSystemMessage {
public:
/* Instantiation forbidden */
GenericFileSystemMessage() = delete;
static const uint8_t MESSAGE_ID = messagetypes::FILE_SYSTEM_MESSAGE;
/* PUS standard (ECSS-E-ST-70-41C15 2016 p.654) */
static const Command_t CMD_CREATE_FILE = MAKE_COMMAND_ID(1);
static const Command_t CMD_DELETE_FILE = MAKE_COMMAND_ID(2);
/** Report file attributes */
static const Command_t CMD_REPORT_FILE_ATTRIBUTES = MAKE_COMMAND_ID(3);
static const Command_t REPLY_REPORT_FILE_ATTRIBUTES = MAKE_COMMAND_ID(4);
/** Command to lock a file, setting it read-only */
static const Command_t CMD_LOCK_FILE = MAKE_COMMAND_ID(5);
/** Command to unlock a file, enabling further operations on it */
static const Command_t CMD_UNLOCK_FILE = MAKE_COMMAND_ID(6);
/**
* Find file in repository, using a search pattern.
* Please note that * is the wildcard character.
* For example, when looking for all files which start with have the
* structure tm<something>.bin, tm*.bin can be used.
*/
static const Command_t CMD_FIND_FILE = MAKE_COMMAND_ID(7);
static const Command_t CMD_CREATE_DIRECTORY = MAKE_COMMAND_ID(9);
static const Command_t CMD_DELETE_DIRECTORY = MAKE_COMMAND_ID(10);
static const Command_t CMD_RENAME_DIRECTORY = MAKE_COMMAND_ID(11);
/** Dump contents of a repository */
static const Command_t CMD_DUMP_REPOSITORY = MAKE_COMMAND_ID(12);
/** Repository dump reply */
static const Command_t REPLY_DUMY_REPOSITORY = MAKE_COMMAND_ID(13);
static constexpr Command_t CMD_COPY_FILE = MAKE_COMMAND_ID(14);
static constexpr Command_t CMD_MOVE_FILE = MAKE_COMMAND_ID(15);
static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(128);
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(129);
// These command IDs will remain until CFDP has been introduced and consolidated.
/** Append operation commands */
static const Command_t CMD_APPEND_TO_FILE = MAKE_COMMAND_ID(130);
static const Command_t CMD_FINISH_APPEND_TO_FILE = MAKE_COMMAND_ID(131);
static const Command_t REPLY_FINISH_APPEND = MAKE_COMMAND_ID(132);
static const Command_t CMD_READ_FROM_FILE = MAKE_COMMAND_ID(140);
static const Command_t REPLY_READ_FROM_FILE = MAKE_COMMAND_ID(141);
static const Command_t CMD_STOP_READ = MAKE_COMMAND_ID(142);
static const Command_t REPLY_READ_FINISHED_STOP = MAKE_COMMAND_ID(143);
static void setLockFileCommand(CommandMessage* message, store_address_t storeId);
static void setUnlockFileCommand(CommandMessage* message, store_address_t storeId);
static void setCreateFileCommand(CommandMessage* message,
store_address_t storeId);
static void setDeleteFileCommand(CommandMessage* message,
store_address_t storeId);
static void setReportFileAttributesCommand(CommandMessage* message,
store_address_t storeId);
static void setReportFileAttributesReply(CommandMessage* message,
store_address_t storeId);
static void setCreateDirectoryCommand(CommandMessage* message,
store_address_t storeId);
static void setDeleteDirectoryCommand(CommandMessage* message,
store_address_t storeId);
static void setSuccessReply(CommandMessage* message);
static void setFailureReply(CommandMessage* message,
ReturnValue_t errorCode, uint32_t errorParam = 0);
static void setCopyCommand(CommandMessage* message, store_address_t storeId);
static void setWriteCommand(CommandMessage* message,
store_address_t storeId);
static void setFinishStopWriteCommand(CommandMessage* message,
store_address_t storeId);
static void setFinishStopWriteReply(CommandMessage* message,
store_address_t storeId);
static void setFinishAppendReply(CommandMessage* message,
store_address_t storeId);
static void setReadCommand(CommandMessage* message,
store_address_t storeId);
static void setReadFinishedReply(CommandMessage* message,
store_address_t storeId);
static void setReadReply(CommandMessage* message, bool readFinished,
store_address_t storeId);
static bool getReadReply(const CommandMessage* message,
store_address_t* storeId);
static store_address_t getStoreId(const CommandMessage* message);
static ReturnValue_t getFailureReply(const CommandMessage* message,
uint32_t* errorParam = nullptr);
};
#endif /* MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_ */

View File

@ -108,9 +108,9 @@ void ObjectManager::initialize() {
result = it.second->checkObjectConnections(); result = it.second->checkObjectConnections();
if ( result != RETURN_OK ) { if ( result != RETURN_OK ) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::ObjectManager: Object " << std::hex << sif::error << "ObjectManager::ObjectManager: Object 0x" << std::hex <<
(int) it.first << " connection check failed with code 0x" (int) it.first << " connection check failed with code 0x" << result <<
<< result << std::dec << std::endl; std::dec << std::endl;
#endif #endif
errorCount++; errorCount++;
} }

View File

@ -4,7 +4,7 @@
#include "frameworkObjects.h" #include "frameworkObjects.h"
#include "SystemObjectIF.h" #include "SystemObjectIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
/** /**
* @brief This class provides an interface to the global object manager. * @brief This class provides an interface to the global object manager.

View File

@ -1,8 +1,9 @@
#ifndef FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ #ifndef FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_
#define FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ #define FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_
#include <fsfw/objectmanager/SystemObjectIF.h> #include "SystemObjectIF.h"
// The objects will be instantiated in the ID order
namespace objects { namespace objects {
enum framework_objects: object_id_t { enum framework_objects: object_id_t {
FSFW_OBJECTS_START = 0x53000000, FSFW_OBJECTS_START = 0x53000000,
@ -16,6 +17,7 @@ enum framework_objects: object_id_t {
PUS_SERVICE_17_TEST = 0x53000017, PUS_SERVICE_17_TEST = 0x53000017,
PUS_SERVICE_20_PARAMETERS = 0x53000020, PUS_SERVICE_20_PARAMETERS = 0x53000020,
PUS_SERVICE_200_MODE_MGMT = 0x53000200, PUS_SERVICE_200_MODE_MGMT = 0x53000200,
PUS_SERVICE_201_HEALTH = 0x53000201,
//Generic IDs for IPC, modes, health, events //Generic IDs for IPC, modes, health, events
HEALTH_TABLE = 0x53010000, HEALTH_TABLE = 0x53010000,

View File

@ -15,6 +15,7 @@ target_sources(${LIB_FSFW_NAME}
TaskFactory.cpp TaskFactory.cpp
Timekeeper.cpp Timekeeper.cpp
TaskManagement.cpp TaskManagement.cpp
QueueMapManager.cpp
) )
# FreeRTOS is required to link the FSFW now. It is recommended to compile # FreeRTOS is required to link the FSFW now. It is recommended to compile

View File

@ -1,26 +1,23 @@
#include "MessageQueue.h" #include "MessageQueue.h"
#include "QueueMapManager.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManagerIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
// TODO I guess we should have a way of checking if we are in an ISR and then
// use the "fromISR" versions of all calls
// As a first step towards this, introduces system context variable which needs
// to be switched manually
// Haven't found function to find system context.
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
maxMessageSize(maxMessageSize) { maxMessageSize(maxMessageSize) {
handle = xQueueCreate(messageDepth, maxMessageSize); handle = xQueueCreate(messageDepth, maxMessageSize);
#if FSFW_CPP_OSTREAM_ENABLED == 1
if (handle == nullptr) { if (handle == nullptr) {
sif::error << "MessageQueue::MessageQueue:" #if FSFW_CPP_OSTREAM_ENABLED == 1
<< " Creation failed." << std::endl; sif::error << "MessageQueue::MessageQueue: Creation failed" << std::endl;
sif::error << "Specified Message Depth: " << messageDepth sif::error << "Specified Message Depth: " << messageDepth << std::endl;
<< std::endl; sif::error << "Specified Maximum Message Size: " << maxMessageSize << std::endl;
sif::error << "Specified Maximum Message Size: " #else
<< maxMessageSize << std::endl; sif::printError("MessageQueue::MessageQueue: Creation failed\n");
sif::printError("Specified Message Depth: %d\n", messageDepth);
} sif::printError("Specified MAximum Message Size: %d\n", maxMessageSize);
#endif #endif
}
QueueMapManager::instance()->addMessageQueue(handle, &queueId);
} }
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {
@ -62,13 +59,15 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
callContext); callContext);
} }
QueueHandle_t MessageQueue::getNativeQueueHandle() {
return handle;
}
ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) {
if (result != pdPASS) { if (result != pdPASS) {
if (not ignoreFault) { if (not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter = objectManager-> InternalErrorReporterIF* internalErrorReporter = objectManager->
get<InternalErrorReporterIF>( get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != nullptr) { if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
@ -110,7 +109,7 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
} }
MessageQueueId_t MessageQueue::getId() const { MessageQueueId_t MessageQueue::getId() const {
return reinterpret_cast<MessageQueueId_t>(handle); return queueId;
} }
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
@ -132,29 +131,24 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault, CallContext callContext) { bool ignoreFault, CallContext callContext) {
BaseType_t result = pdFALSE; BaseType_t result = pdFALSE;
QueueHandle_t destination = nullptr; if(sendTo == MessageQueueIF::NO_QUEUE) {
return MessageQueueIF::DESTINATION_INVALID;
if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) {
return MessageQueueIF::DESTINATION_INVALID;
} }
else {
destination = reinterpret_cast<QueueHandle_t>(sendTo); QueueHandle_t destination = QueueMapManager::instance()->getMessageQueue(sendTo);
if(destination == nullptr) {
return MessageQueueIF::DESTINATION_INVALID;
} }
message->setSender(sentFrom); message->setSender(sentFrom);
if(callContext == CallContext::TASK) { if(callContext == CallContext::TASK) {
result = xQueueSendToBack(destination, result = xQueueSendToBack(destination, static_cast<const void*>(message->getBuffer()), 0);
static_cast<const void*>(message->getBuffer()), 0);
} }
else { else {
/* If the call context is from an interrupt, /* If the call context is from an interrupt, request a context switch if a higher priority
* request a context switch if a higher priority task task was blocked by the interrupt. */
* was blocked by the interrupt. */
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
result = xQueueSendFromISR(reinterpret_cast<QueueHandle_t>(sendTo), result = xQueueSendFromISR(destination, static_cast<const void*>(message->getBuffer()),
static_cast<const void*>(message->getBuffer()),
&xHigherPriorityTaskWoken); &xHigherPriorityTaskWoken);
if(xHigherPriorityTaskWoken == pdTRUE) { if(xHigherPriorityTaskWoken == pdTRUE) {
TaskManagement::requestContextSwitch(callContext); TaskManagement::requestContextSwitch(callContext);

View File

@ -11,11 +11,6 @@
#include <freertos/queue.h> #include <freertos/queue.h>
#include <fsfw/ipc/MessageQueueMessage.h> #include <fsfw/ipc/MessageQueueMessage.h>
// TODO: this class assumes that MessageQueueId_t is the same size as void*
// (the FreeRTOS handle type), compiler will catch this but it might be nice
// to have something checking or even an always working solution
// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/
/** /**
* @brief This class manages sending and receiving of * @brief This class manages sending and receiving of
* message queue messages. * message queue messages.
@ -112,6 +107,8 @@ public:
bool isDefaultDestinationSet() const override; bool isDefaultDestinationSet() const override;
QueueHandle_t getNativeQueueHandle();
protected: protected:
/** /**
* @brief Implementation to be called from any send Call within * @brief Implementation to be called from any send Call within
@ -141,6 +138,8 @@ protected:
private: private:
bool defaultDestinationSet = false; bool defaultDestinationSet = false;
QueueHandle_t handle; QueueHandle_t handle;
MessageQueueId_t queueId = MessageQueueIF::NO_QUEUE;
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE; MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE; MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
const size_t maxMessageSize; const size_t maxMessageSize;

View File

@ -0,0 +1,58 @@
#include "QueueMapManager.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexGuard.h"
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
QueueMapManager::QueueMapManager() {
mapLock = MutexFactory::instance()->createMutex();
}
QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager();
}
return QueueMapManager::mqManagerInstance;
}
ReturnValue_t QueueMapManager::addMessageQueue(QueueHandle_t queue, MessageQueueId_t* id) {
MutexGuard lock(mapLock);
uint32_t currentId = queueCounter++;
auto returnPair = queueMap.emplace(currentId, queue);
if(not returnPair.second) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "QueueMapManager::addMessageQueue This ID is already "
"inside the map!" << std::endl;
#else
sif::printError("QueueMapManager::addMessageQueue This ID is already "
"inside the map!\n");
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
if (id != nullptr) {
*id = currentId;
}
return HasReturnvaluesIF::RETURN_OK;
}
QueueHandle_t QueueMapManager::getMessageQueue(MessageQueueId_t messageQueueId) const {
auto queueIter = queueMap.find(messageQueueId);
if(queueIter != queueMap.end()) {
return queueIter->second;
}
else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "QueueMapManager::getQueueHandle: The ID " << messageQueueId <<
" does not exists in the map!" << std::endl;
#else
sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n",
messageQueueId);
#endif
}
return nullptr;
}
QueueMapManager::~QueueMapManager() {
MutexFactory::instance()->deleteMutex(mapLock);
}

View File

@ -0,0 +1,50 @@
#ifndef FSFW_OSAL_FREERTOS_QUEUEMAPMANAGER_H_
#define FSFW_OSAL_FREERTOS_QUEUEMAPMANAGER_H_
#include "../../ipc/MutexIF.h"
#include "../../ipc/messageQueueDefinitions.h"
#include "../../ipc/MessageQueueIF.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include <map>
using QueueMap = std::map<MessageQueueId_t, QueueHandle_t>;
class QueueMapManager {
public:
//! Returns the single instance of QueueMapManager
static QueueMapManager* instance();
/**
* Insert a message queue and the corresponding QueueHandle into the map
* @param queue The message queue to insert.
* @param id The passed value will be set unless a nullptr is passed
* @return
*/
ReturnValue_t addMessageQueue(QueueHandle_t queue, MessageQueueId_t* id);
/**
* Get the message queue handle by providing a message queue ID. Returns nullptr
* if the queue ID does not exist in the internal map.
* @param messageQueueId
* @return
*/
QueueHandle_t getMessageQueue(MessageQueueId_t messageQueueId) const;
private:
//! External instantiation forbidden. Constructor still required for singleton instantiation.
QueueMapManager();
~QueueMapManager();
uint32_t queueCounter = 0;
MutexIF* mapLock;
QueueMap queueMap;
static QueueMapManager* mqManagerInstance;
};
#endif /* FSFW_OSAL_FREERTOS_QUEUEMAPMANAGER_H_ */

View File

@ -5,6 +5,7 @@ if(DEFINED WIN32 OR DEFINED UNIX)
UdpTcPollingTask.cpp UdpTcPollingTask.cpp
UdpTmTcBridge.cpp UdpTmTcBridge.cpp
TcpTmTcServer.cpp TcpTmTcServer.cpp
TcpTmTcBridge.cpp
) )
endif() endif()

View File

@ -1,10 +1,9 @@
#include "TcpIpBase.h" #include "TcpIpBase.h"
#include "../../platform.h"
#ifdef __unix__ #ifdef PLATFORM_UNIX
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
TcpIpBase::TcpIpBase() { TcpIpBase::TcpIpBase() {
@ -37,17 +36,17 @@ TcpIpBase::~TcpIpBase() {
} }
int TcpIpBase::closeSocket(socket_t socket) { int TcpIpBase::closeSocket(socket_t socket) {
#ifdef _WIN32 #ifdef PLATFORM_WIN
return closesocket(socket); return closesocket(socket);
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
return close(socket); return close(socket);
#endif #endif
} }
int TcpIpBase::getLastSocketError() { int TcpIpBase::getLastSocketError() {
#ifdef _WIN32 #ifdef PLATFORM_WIN
return WSAGetLastError(); return WSAGetLastError();
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
return errno; return errno;
#endif #endif
} }

View File

@ -1,28 +1,25 @@
#ifndef FSFW_OSAL_COMMON_TCPIPIF_H_ #ifndef FSFW_OSAL_COMMON_TCPIPIF_H_
#define FSFW_OSAL_COMMON_TCPIPIF_H_ #define FSFW_OSAL_COMMON_TCPIPIF_H_
#include <fsfw/returnvalues/HasReturnvaluesIF.h> #include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../platform.h"
#ifdef _WIN32
#ifdef PLATFORM_WIN
#include <winsock2.h> #include <winsock2.h>
#elif defined(PLATFORM_UNIX)
#elif defined(__unix__)
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
class TcpIpBase { class TcpIpBase {
protected: protected:
#ifdef _WIN32 #ifdef PLATFORM_WIN
static constexpr int SHUT_RECV = SD_RECEIVE; static constexpr int SHUT_RECV = SD_RECEIVE;
static constexpr int SHUT_SEND = SD_SEND; static constexpr int SHUT_SEND = SD_SEND;
static constexpr int SHUT_BOTH = SD_BOTH; static constexpr int SHUT_BOTH = SD_BOTH;
using socket_t = SOCKET; using socket_t = SOCKET;
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
using socket_t = int; using socket_t = int;
static constexpr int INVALID_SOCKET = -1; static constexpr int INVALID_SOCKET = -1;

View File

@ -0,0 +1,77 @@
#include "TcpTmTcBridge.h"
#include "tcpipHelpers.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/ipc/MutexGuard.h>
#include <fsfw/osal/common/TcpTmTcBridge.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#elif defined(__unix__)
#include <netdb.h>
#include <arpa/inet.h>
#endif
const std::string TcpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
// Connection is always up, TM is requested by connecting to server and receiving packets
registerCommConnect();
}
ReturnValue_t TcpTmTcBridge::initialize() {
ReturnValue_t result = TmTcBridge::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcpTmTcBridge::initialize: TmTcBridge initialization failed!"
<< std::endl;
#else
sif::printError("TcpTmTcBridge::initialize: TmTcBridge initialization failed!\n");
#endif
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
TcpTmTcBridge::~TcpTmTcBridge() {
if(mutex != nullptr) {
MutexFactory::instance()->deleteMutex(mutex);
}
}
ReturnValue_t TcpTmTcBridge::handleTm() {
// Simply store the telemetry in the FIFO, the server will use it to access the TM
MutexGuard guard(mutex, timeoutType, mutexTimeoutMs);
TmTcMessage message;
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message);
result == HasReturnvaluesIF::RETURN_OK;
result = tmTcReceptionQueue->receiveMessage(&message))
{
status = storeDownlinkData(&message);
if(status != HasReturnvaluesIF::RETURN_OK) {
break;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
// Not used. The Server uses the FIFO to access and send the telemetry.
return HasReturnvaluesIF::RETURN_OK;
}
void TcpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType,
dur_millis_t timeoutMs) {
this->timeoutType = timeoutType;
this->mutexTimeoutMs = timeoutMs;
}

View File

@ -0,0 +1,71 @@
#ifndef FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_
#define FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_
#include "TcpIpBase.h"
#include "../../tmtcservices/TmTcBridge.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#elif defined(__unix__)
#include <sys/socket.h>
#endif
#include <string>
/**
* @brief This class should be used with the TcpTmTcServer to implement a TCP server
* for receiving and sending PUS telemetry and telecommands (TMTC)
* @details
* This bridge tasks takes care of filling a FIFO which generated telemetry. The TcpTmTcServer
* will take care of sending the telemetry stored in the FIFO if a client connects to the
* server. This bridge will also be the default destination for telecommands, but the telecommands
* will be relayed to a specified tcDestination directly.
*/
class TcpTmTcBridge:
public TmTcBridge {
friend class TcpTmTcServer;
public:
/* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_UDP_SERVER_PORT;
/**
* Constructor
* @param objectId Object ID of the TcpTmTcBridge.
* @param tcDestination Destination for received TC packets. Any received telecommands will
* be sent there directly. The destination object needs to implement
* AcceptsTelecommandsIF.
* @param tmStoreId TM store object ID. It is recommended to the default object ID
* @param tcStoreId TC store object ID. It is recommended to the default object ID
*/
TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId = objects::TM_STORE,
object_id_t tcStoreId = objects::TC_STORE);
virtual~ TcpTmTcBridge();
/**
* Set properties of internal mutex.
*/
void setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs);
ReturnValue_t initialize() override;
protected:
ReturnValue_t handleTm() override;
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
//! Access to the FIFO needs to be mutex protected because it is used by the bridge and
//! the server.
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
dur_millis_t mutexTimeoutMs = 20;
MutexIF* mutex;
};
#endif /* FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_ */

View File

@ -1,23 +1,33 @@
#include "TcpTmTcServer.h" #include "TcpTmTcServer.h"
#include "TcpTmTcBridge.h"
#include "tcpipHelpers.h" #include "tcpipHelpers.h"
#include "../../serviceinterface/ServiceInterface.h"
#ifdef _WIN32 #include "../../platform.h"
#include "../../container/SharedRingBuffer.h"
#include "../../ipc/MessageQueueSenderIF.h"
#include "../../ipc/MutexGuard.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../tmtcservices/TmTcMessage.h"
#ifdef PLATFORM_WIN
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(PLATFORM_UNIX)
#elif defined(__unix__)
#include <netdb.h> #include <netdb.h>
#endif #endif
const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7301"; #ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED
const std::string TcpTmTcServer::DEFAULT_TCP_CLIENT_PORT = "7302"; #define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0
#endif
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge, const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7303";
std::string customTcpServerPort):
SystemObject(objectId), tcpPort(customTcpServerPort) { TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
size_t receptionBufferSize, std::string customTcpServerPort):
SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge),
tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) {
if(tcpPort == "") { if(tcpPort == "") {
tcpPort = DEFAULT_TCP_SERVER_PORT; tcpPort = DEFAULT_TCP_SERVER_PORT;
} }
@ -31,6 +41,18 @@ ReturnValue_t TcpTmTcServer::initialize() {
return result; return result;
} }
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcpTmTcServer::initialize: TC store uninitialized!" << std::endl;
#else
sif::printError("TcpTmTcServer::initialize: TC store uninitialized!\n");
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<TcpTmTcBridge>(tmtcBridgeId);
int retval = 0; int retval = 0;
struct addrinfo *addrResult = nullptr; struct addrinfo *addrResult = nullptr;
struct addrinfo hints = {}; struct addrinfo hints = {};
@ -40,34 +62,25 @@ ReturnValue_t TcpTmTcServer::initialize() {
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
// Listen to all addresses (0.0.0.0) by using AI_PASSIVE in the hint flags
retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult); retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult);
if (retval != 0) { if (retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcpTmTcServer: Retrieving address info failed!" <<
std::endl;
#endif
handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL); handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
/* Open TCP (stream) socket */ // Open TCP (stream) socket
listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype, listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype,
addrResult->ai_protocol); addrResult->ai_protocol);
if(listenerTcpSocket == INVALID_SOCKET) { if(listenerTcpSocket == INVALID_SOCKET) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcWinTcpServer: Socket creation failed!" << std::endl;
#endif
freeaddrinfo(addrResult); freeaddrinfo(addrResult);
handleError(Protocol::TCP, ErrorSources::SOCKET_CALL); handleError(Protocol::TCP, ErrorSources::SOCKET_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
// Bind to the address found by getaddrinfo
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen)); retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
if(retval == SOCKET_ERROR) { if(retval == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcpTmTcServer: Binding socket failed!" <<
std::endl;
#endif
freeaddrinfo(addrResult); freeaddrinfo(addrResult);
handleError(Protocol::TCP, ErrorSources::BIND_CALL); handleError(Protocol::TCP, ErrorSources::BIND_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@ -84,49 +97,130 @@ TcpTmTcServer::~TcpTmTcServer() {
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
using namespace tcpip; using namespace tcpip;
/* If a connection is accepted, the corresponding socket will be assigned to the new socket */ // If a connection is accepted, the corresponding socket will be assigned to the new socket
socket_t clientSocket = 0; socket_t connSocket = 0;
sockaddr clientSockAddr = {}; // sockaddr clientSockAddr = {};
socklen_t connectorSockAddrLen = 0; // socklen_t connectorSockAddrLen = 0;
int retval = 0; int retval = 0;
/* Listen for connection requests permanently for lifetime of program */ // Listen for connection requests permanently for lifetime of program
while(true) { while(true) {
retval = listen(listenerTcpSocket, currentBacklog); retval = listen(listenerTcpSocket, tcpBacklog);
if(retval == SOCKET_ERROR) { if(retval == SOCKET_ERROR) {
handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500); handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500);
continue; continue;
} }
clientSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen); //connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
connSocket = accept(listenerTcpSocket, nullptr, nullptr);
if(clientSocket == INVALID_SOCKET) { if(connSocket == INVALID_SOCKET) {
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500); handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
closeSocket(clientSocket); closeSocket(connSocket);
continue; continue;
}; };
retval = recv(clientSocket, reinterpret_cast<char*>(receptionBuffer.data()), handleServerOperation(connSocket);
receptionBuffer.size(), 0);
if(retval > 0) {
#if FSFW_TCP_RCV_WIRETAPPING_ENABLED == 1
sif::info << "TcpTmTcServer::performOperation: Received " << retval << " bytes."
std::endl;
#endif
handleError(Protocol::TCP, ErrorSources::RECV_CALL, 500);
}
else if(retval == 0) {
// Done, shut down connection and go back to listening for client requests
retval = shutdown(connSocket, SHUT_SEND);
if(retval != 0) {
handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL);
} }
else { closeSocket(connSocket);
}
/* Done, shut down connection */
retval = shutdown(clientSocket, SHUT_SEND);
closeSocket(clientSocket);
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
if(tmtcBridge == nullptr) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
/* Initialize the destination after task creation. This ensures
that the destination has already been set in the TMTC bridge. */
targetTcDestination = tmtcBridge->getRequestQueue();
tcStore = tmtcBridge->tcStore;
tmStore = tmtcBridge->tmStore;
return HasReturnvaluesIF::RETURN_OK;
}
void TcpTmTcServer::handleServerOperation(socket_t connSocket) {
int retval = 0;
do {
// Read all telecommands sent by the client
retval = recv(connSocket,
reinterpret_cast<char*>(receptionBuffer.data()),
receptionBuffer.capacity(),
tcpFlags);
if (retval > 0) {
handleTcReception(retval);
}
else if(retval == 0) {
// Client has finished sending telecommands, send telemetry now
handleTmSending(connSocket);
}
else {
// Should not happen
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL);
}
} while(retval > 0);
}
ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) {
#if FSFW_TCP_RECV_WIRETAPPING_ENABLED == 1
arrayprinter::print(receptionBuffer.data(), bytesRead);
#endif
store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRecvd);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning<< "TcpTmTcServer::handleServerOperation: Data storage failed." << std::endl;
sif::warning << "Packet size: " << bytesRecvd << std::endl;
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UdpTcPollingTask::handleSuccessfullTcRead: "
" Sending message to queue failed" << std::endl;
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
tcStore->deleteData(storeId);
}
return result;
}
void TcpTmTcServer::setTcpBacklog(uint8_t tcpBacklog) {
this->tcpBacklog = tcpBacklog;
}
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket) {
// Access to the FIFO is mutex protected because it is filled by the bridge
MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
store_address_t storeId;
while((not tmtcBridge->tmFifo->empty()) and
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
tmtcBridge->tmFifo->retrieve(&storeId);
// Using the store accessor will take care of deleting TM from the store automatically
ConstStorageAccessor storeAccessor(storeId);
ReturnValue_t result = tmStore->getData(storeId, storeAccessor);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
int retval = send(connSocket,
reinterpret_cast<const char*>(storeAccessor.data()),
storeAccessor.size(),
tcpTmFlags);
if(retval != static_cast<int>(storeAccessor.size())) {
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::SEND_CALL);
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,24 +1,40 @@
#ifndef FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ #ifndef FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_
#define FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ #define FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_
#include "TcpIpBase.h" #include "TcpIpBase.h"
#include "../../platform.h"
#include "../../ipc/messageQueueDefinitions.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../objectmanager/frameworkObjects.h"
#include "../../objectmanager/SystemObject.h" #include "../../objectmanager/SystemObject.h"
#include "../../storagemanager/StorageManagerIF.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
#ifdef __unix__ #ifdef PLATFORM_UNIX
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#include <string> #include <string>
#include <vector> #include <vector>
//! Debugging preprocessor define. class TcpTmTcBridge;
#define FSFW_TCP_RCV_WIRETAPPING_ENABLED 0
/** /**
* @brief Windows TCP server used to receive telecommands on a Windows Host * @brief TCP server implementation
* @details * @details
* Based on: https://docs.microsoft.com/en-us/windows/win32/winsock/complete-server-code * This server will run for the whole program lifetime and will take care of serving client
* requests on a specified TCP server port. This server was written in a generic way and
* can be used on Unix and on Windows systems.
*
* If a connection is accepted, the server will read all telecommands sent by a client and then
* send all telemetry currently found in the TMTC bridge FIFO.
*
* Reading telemetry without sending telecommands is possible by connecting, shutting down the
* send operation immediately and then reading the telemetry. It is therefore recommended to
* connect to the server regularly, even if no telecommands need to be sent.
*
* The server will listen to a specific port on all addresses (0.0.0.0).
*/ */
class TcpTmTcServer: class TcpTmTcServer:
public SystemObject, public SystemObject,
@ -27,27 +43,51 @@ class TcpTmTcServer:
public: public:
/* The ports chosen here should not be used by any other process. */ /* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_TCP_SERVER_PORT; static const std::string DEFAULT_TCP_SERVER_PORT;
static const std::string DEFAULT_TCP_CLIENT_PORT;
TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge, static constexpr size_t ETHERNET_MTU_SIZE = 1500;
/**
* TCP Server Constructor
* @param objectId Object ID of the TCP Server
* @param tmtcTcpBridge Object ID of the TCP TMTC Bridge object
* @param receptionBufferSize This will be the size of the reception buffer. Default buffer
* size will be the Ethernet MTU size
* @param customTcpServerPort The user can specify another port than the default (7301) here.
*/
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
size_t receptionBufferSize = ETHERNET_MTU_SIZE + 1,
std::string customTcpServerPort = ""); std::string customTcpServerPort = "");
virtual~ TcpTmTcServer(); virtual~ TcpTmTcServer();
void setTcpBacklog(uint8_t tcpBacklog);
ReturnValue_t initialize() override; ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t opCode) override; ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initializeAfterTaskCreation() override;
protected:
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
private: private:
//! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT;
TcpTmTcBridge* tmtcBridge = nullptr;
std::string tcpPort; std::string tcpPort;
int tcpFlags = 0;
socket_t listenerTcpSocket = 0; socket_t listenerTcpSocket = 0;
struct sockaddr tcpAddress; struct sockaddr tcpAddress;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
int tcpAddrLen = sizeof(tcpAddress); int tcpAddrLen = sizeof(tcpAddress);
int currentBacklog = 3; int tcpBacklog = 3;
std::vector<uint8_t> receptionBuffer; std::vector<uint8_t> receptionBuffer;
int tcpSockOpt = 0; int tcpSockOpt = 0;
int tcpTmFlags = 0;
void handleServerOperation(socket_t connSocket);
ReturnValue_t handleTcReception(size_t bytesRecvd);
ReturnValue_t handleTmSending(socket_t connSocket);
}; };
#endif /* FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ */ #endif /* FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ */

View File

@ -1,26 +1,23 @@
#include "UdpTcPollingTask.h" #include "UdpTcPollingTask.h"
#include "tcpipHelpers.h" #include "tcpipHelpers.h"
#include "../../platform.h"
#include "../../globalfunctions/arrayprinter.h" #include "../../globalfunctions/arrayprinter.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
#ifdef _WIN32 #ifdef PLATFORM_WIN
#include <winsock2.h> #include <winsock2.h>
#elif defined(PLATFORM_UNIX)
#else
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
//! Debugging preprocessor define. //! Debugging preprocessor define.
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0 #define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t maxRecvSize, object_id_t tmtcUdpBridge, size_t maxRecvSize,
double timeoutSeconds): SystemObject(objectId), double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) { tmtcBridgeId(tmtcUdpBridge) {
if(frameSize > 0) { if(frameSize > 0) {
this->frameSize = frameSize; this->frameSize = frameSize;
} }
@ -155,7 +152,7 @@ ReturnValue_t UdpTcPollingTask::initializeAfterTaskCreation() {
} }
void UdpTcPollingTask::setTimeout(double timeoutSeconds) { void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
#ifdef _WIN32 #ifdef PLATFORM_WIN
DWORD timeoutMs = timeoutSeconds * 1000.0; DWORD timeoutMs = timeoutSeconds * 1000.0;
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD)); reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
@ -165,7 +162,7 @@ void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
"receive timeout failed with " << strerror(errno) << std::endl; "receive timeout failed with " << strerror(errno) << std::endl;
#endif #endif
} }
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
timeval tval; timeval tval;
tval = timevalOperations::toTimeval(timeoutSeconds); tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,

View File

@ -1,5 +1,5 @@
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ #ifndef FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ #define FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_
#include "UdpTmTcBridge.h" #include "UdpTmTcBridge.h"
#include "../../objectmanager/SystemObject.h" #include "../../objectmanager/SystemObject.h"
@ -9,8 +9,11 @@
#include <vector> #include <vector>
/** /**
* @brief This class should be used with the UdpTmTcBridge to implement a UDP server * @brief This class can be used with the UdpTmTcBridge to implement a UDP server
* for receiving and sending PUS TMTC. * for receiving and sending PUS TMTC.
* @details
* This task is exclusively used to poll telecommands from a given socket and transfer them
* to the FSFW software bus. It used the blocking recvfrom call to do this.
*/ */
class UdpTcPollingTask: class UdpTcPollingTask:
public TcpIpBase, public TcpIpBase,
@ -22,7 +25,7 @@ public:
//! 0.5 default milliseconds timeout for now. //! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {0, 500}; static constexpr timeval DEFAULT_TIMEOUT = {0, 500};
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
size_t maxRecvSize = 0, double timeoutSeconds = -1); size_t maxRecvSize = 0, double timeoutSeconds = -1);
virtual~ UdpTcPollingTask(); virtual~ UdpTcPollingTask();
@ -45,8 +48,6 @@ private:
object_id_t tmtcBridgeId = objects::NO_OBJECT; object_id_t tmtcBridgeId = objects::NO_OBJECT;
UdpTmTcBridge* tmtcBridge = nullptr; UdpTmTcBridge* tmtcBridge = nullptr;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
//! See: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom
int receptionFlags = 0; int receptionFlags = 0;
std::vector<uint8_t> receptionBuffer; std::vector<uint8_t> receptionBuffer;
@ -57,4 +58,4 @@ private:
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
}; };
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */ #endif /* FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_ */

View File

@ -1,27 +1,26 @@
#include "UdpTmTcBridge.h"
#include "tcpipHelpers.h" #include "tcpipHelpers.h"
#include <fsfw/serviceinterface/ServiceInterface.h> #include "../../platform.h"
#include <fsfw/ipc/MutexGuard.h> #include "../../serviceinterface/ServiceInterface.h"
#include <fsfw/osal/common/UdpTmTcBridge.h> #include "../../ipc/MutexGuard.h"
#ifdef _WIN32
#ifdef PLATFORM_WIN
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(PLATFORM_UNIX)
#elif defined(__unix__)
#include <netdb.h> #include <netdb.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
//! Debugging preprocessor define. //! Debugging preprocessor define.
#ifndef FSFW_UDP_SEND_WIRETAPPING_ENABLED
#define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0 #define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0
#endif
const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort): std::string udpServerPort, object_id_t tmStoreId, object_id_t tcStoreId):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
if(udpServerPort == "") { if(udpServerPort == "") {
this->udpServerPort = DEFAULT_UDP_SERVER_PORT; this->udpServerPort = DEFAULT_UDP_SERVER_PORT;
@ -38,7 +37,7 @@ ReturnValue_t UdpTmTcBridge::initialize() {
ReturnValue_t result = TmTcBridge::initialize(); ReturnValue_t result = TmTcBridge::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::initialize: TmTcBridge initialization failed!" sif::error << "UdpTmTcBridge::initialize: TmTcBridge initialization failed!"
<< std::endl; << std::endl;
#endif #endif
return result; return result;
@ -54,10 +53,10 @@ ReturnValue_t UdpTmTcBridge::initialize() {
/* Tell the user that we could not find a usable */ /* Tell the user that we could not find a usable */
/* Winsock DLL. */ /* Winsock DLL. */
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: " << sif::error << "UdpTmTcBridge::UdpTmTcBridge: WSAStartup failed with error: " <<
err << std::endl; err << std::endl;
#else #else
sif::printError("TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: %d\n", sif::printError("UdpTmTcBridge::UdpTmTcBridge: WSAStartup failed with error: %d\n",
err); err);
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@ -78,19 +77,12 @@ ReturnValue_t UdpTmTcBridge::initialize() {
getaddrinfo to assign the address 0.0.0.0 (any address) */ getaddrinfo to assign the address 0.0.0.0 (any address) */
int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult); int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult);
if (retval != 0) { if (retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::GETADDRINFO_CALL);
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Retrieving address info failed!" <<
std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol); serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol);
if(serverSocket == INVALID_SOCKET) { if(serverSocket == INVALID_SOCKET) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Could not open UDP socket!" <<
std::endl;
#endif
freeaddrinfo(addrResult); freeaddrinfo(addrResult);
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL); tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@ -102,10 +94,6 @@ ReturnValue_t UdpTmTcBridge::initialize() {
retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen)); retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
if(retval != 0) { if(retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::TmTcUdpBridge: Could not bind "
"local port (" << udpServerPort << ") to server socket!" << std::endl;
#endif
freeaddrinfo(addrResult); freeaddrinfo(addrResult);
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL); tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;

View File

@ -1,24 +1,26 @@
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_ #ifndef FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_ #define FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_
#include "TcpIpBase.h" #include "TcpIpBase.h"
#include "../../platform.h"
#include "../../tmtcservices/TmTcBridge.h" #include "../../tmtcservices/TmTcBridge.h"
#ifdef _WIN32 #ifdef PLATFORM_WIN
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(PLATFORM_UNIX)
#elif defined(__unix__)
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#include <string> #include <string>
/** /**
* @brief This class should be used with the UdpTcPollingTask to implement a UDP server * @brief This class can be used with the UdpTcPollingTask to implement a UDP server
* for receiving and sending PUS TMTC. * for receiving and sending PUS TMTC.
* @details
* This bridge task will take care of sending telemetry back to a UDP client if a connection
* was established and store them in a FIFO if this was not done yet. It is also be the default
* destination for telecommands, but the telecommands will be relayed to a specified tcDestination
* directly.
*/ */
class UdpTmTcBridge: class UdpTmTcBridge:
public TmTcBridge, public TmTcBridge,
@ -29,7 +31,8 @@ public:
static const std::string DEFAULT_UDP_SERVER_PORT; static const std::string DEFAULT_UDP_SERVER_PORT;
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort = ""); std::string udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
object_id_t tcStoreId = objects::TC_STORE);
virtual~ UdpTmTcBridge(); virtual~ UdpTmTcBridge();
/** /**
@ -56,5 +59,5 @@ private:
MutexIF* mutex; MutexIF* mutex;
}; };
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */ #endif /* FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_ */

View File

@ -32,9 +32,18 @@ void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std:
else if(errorSrc == ErrorSources::RECVFROM_CALL) { else if(errorSrc == ErrorSources::RECVFROM_CALL) {
srcString = "recvfrom call"; srcString = "recvfrom call";
} }
else if(errorSrc == ErrorSources::SEND_CALL) {
srcString = "send call";
}
else if(errorSrc == ErrorSources::SENDTO_CALL) {
srcString = "sendto call";
}
else if(errorSrc == ErrorSources::GETADDRINFO_CALL) { else if(errorSrc == ErrorSources::GETADDRINFO_CALL) {
srcString = "getaddrinfo call"; srcString = "getaddrinfo call";
} }
else if(errorSrc == ErrorSources::SHUTDOWN_CALL) {
srcString = "shutdown call";
}
else { else {
srcString = "unknown call"; srcString = "unknown call";
} }

View File

@ -29,7 +29,9 @@ enum class ErrorSources {
RECVFROM_CALL, RECVFROM_CALL,
LISTEN_CALL, LISTEN_CALL,
ACCEPT_CALL, ACCEPT_CALL,
SENDTO_CALL SEND_CALL,
SENDTO_CALL,
SHUTDOWN_CALL
}; };
void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr, void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr,

View File

@ -1,10 +1,12 @@
#include "../../serviceinterface/ServiceInterface.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../timemanager/Clock.h" #include "../../timemanager/Clock.h"
#include "../../platform.h"
#include <chrono> #include <chrono>
#if defined(WIN32)
#if defined(PLATFORM_WIN)
#include <sysinfoapi.h> #include <sysinfoapi.h>
#elif defined(LINUX) #elif defined(PLATFORM_UNIX)
#include <fstream> #include <fstream>
#endif #endif
@ -46,7 +48,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
} }
ReturnValue_t Clock::getClock_timeval(timeval* time) { ReturnValue_t Clock::getClock_timeval(timeval* time) {
#if defined(WIN32) #if defined(PLATFORM_WIN)
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now); auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto epoch = now.time_since_epoch(); auto epoch = now.time_since_epoch();
@ -54,7 +56,7 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
auto fraction = now - secondsChrono; auto fraction = now - secondsChrono;
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(fraction).count(); time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(fraction).count();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX) #elif defined(PLATFORM_UNIX)
timespec timeUnix; timespec timeUnix;
int status = clock_gettime(CLOCK_REALTIME,&timeUnix); int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
if(status!=0){ if(status!=0){
@ -85,14 +87,14 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval Clock::getUptime() { timeval Clock::getUptime() {
timeval timeval; timeval timeval;
#if defined(WIN32) #if defined(PLATFORM_WIN)
auto uptime = std::chrono::milliseconds(GetTickCount64()); auto uptime = std::chrono::milliseconds(GetTickCount64());
auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime); auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime);
timeval.tv_sec = secondsChrono.count(); timeval.tv_sec = secondsChrono.count();
auto fraction = uptime - secondsChrono; auto fraction = uptime - secondsChrono;
timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>( timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count(); fraction).count();
#elif defined(LINUX) #elif defined(PLATFORM_UNIX)
double uptimeSeconds; double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds)
{ {
@ -119,7 +121,6 @@ ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
/* Do some magic with chrono (C++20!) */ /* Do some magic with chrono (C++20!) */
/* Right now, the library doesn't have the new features to get the required values yet. /* Right now, the library doesn't have the new features to get the required values yet.

View File

@ -1,4 +1,5 @@
#include "taskHelpers.h" #include "taskHelpers.h"
#include "../../platform.h"
#include "../../osal/host/FixedTimeslotTask.h" #include "../../osal/host/FixedTimeslotTask.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h" #include "../../osal/host/Mutex.h"
@ -9,10 +10,10 @@
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#if defined(WIN32) #if defined(PLATFORM_WIN)
#include <windows.h> #include <windows.h>
#include "../windows/winTaskHelpers.h" #include "../windows/winTaskHelpers.h"
#elif defined(LINUX) #elif defined(PLATFORM_UNIX)
#include <pthread.h> #include <pthread.h>
#endif #endif

View File

@ -5,6 +5,8 @@
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexGuard.h" #include "../../ipc/MutexGuard.h"
#include <cstring>
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
messageSize(maxMessageSize), messageDepth(messageDepth) { messageSize(maxMessageSize), messageDepth(messageDepth) {
queueLock = MutexFactory::instance()->createMutex(); queueLock = MutexFactory::instance()->createMutex();
@ -126,8 +128,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
} }
// TODO: Better returnvalue return MessageQueueIF::DESTINATION_INVALID;
return HasReturnvaluesIF::RETURN_FAILED;
} }
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) { if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
MutexGuard mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20); MutexGuard mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20);

View File

@ -217,15 +217,15 @@ private:
* @brief The class stores the queue id it got assigned. * @brief The class stores the queue id it got assigned.
* If initialization fails, the queue id is set to zero. * If initialization fails, the queue id is set to zero.
*/ */
MessageQueueId_t mqId = 0; MessageQueueId_t mqId = MessageQueueIF::NO_QUEUE;
size_t messageSize = 0; size_t messageSize = 0;
size_t messageDepth = 0; size_t messageDepth = 0;
MutexIF* queueLock; MutexIF* queueLock;
bool defaultDestinationSet = false; bool defaultDestinationSet = false;
MessageQueueId_t defaultDestination = 0; MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
MessageQueueId_t lastPartner = 0; MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
}; };
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */ #endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */

View File

@ -2,6 +2,7 @@
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include "taskHelpers.h" #include "taskHelpers.h"
#include "../../platform.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
@ -9,10 +10,10 @@
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#if defined(WIN32) #if defined(PLATFORM_WIN)
#include <processthreadsapi.h> #include <processthreadsapi.h>
#include <fsfw/osal/windows/winTaskHelpers.h> #include <fsfw/osal/windows/winTaskHelpers.h>
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -24,9 +25,9 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
// It is probably possible to set task priorities by using the native // It is probably possible to set task priorities by using the native
// task handles for Windows / Linux // task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
#if defined(_WIN32) #if defined(PLATFORM_WIN)
tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority); tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
#elif defined(__unix__) #elif defined(PLATFORM_UNIX)
// TODO: We could reuse existing code here. // TODO: We could reuse existing code here.
#endif #endif
tasks::insertTaskName(mainThread.get_id(), taskName); tasks::insertTaskName(mainThread.get_id(), taskName);

View File

@ -15,52 +15,49 @@ QueueMapManager::~QueueMapManager() {
} }
QueueMapManager* QueueMapManager::instance() { QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){ if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager(); mqManagerInstance = new QueueMapManager();
} }
return QueueMapManager::mqManagerInstance; return QueueMapManager::mqManagerInstance;
} }
ReturnValue_t QueueMapManager::addMessageQueue( ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* queueToInsert, MessageQueueId_t* id) { MessageQueueIF* queueToInsert, MessageQueueId_t* id) {
/* Not thread-safe, but it is assumed all message queues are created at software initialization MutexGuard lock(mapLock);
now. If this is to be made thread-safe in the future, it propably would be sufficient to lock uint32_t currentId = queueCounter++;
the increment operation here. */ auto returnPair = queueMap.emplace(currentId, queueToInsert);
uint32_t currentId = queueCounter++; if(not returnPair.second) {
auto returnPair = queueMap.emplace(currentId, queueToInsert); /* This should never happen for the atomic variable. */
if(not returnPair.second) {
/* This should never happen for the atomic variable. */
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "QueueMapManager::addMessageQueue This ID is already " sif::error << "QueueMapManager::addMessageQueue This ID is already "
"inside the map!" << std::endl; "inside the map!" << std::endl;
#else #else
sif::printError("QueueMapManager::addMessageQueue This ID is already " sif::printError("QueueMapManager::addMessageQueue This ID is already "
"inside the map!\n"); "inside the map!\n");
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
if (id != nullptr) { if (id != nullptr) {
*id = currentId; *id = currentId;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
MessageQueueIF* QueueMapManager::getMessageQueue( MessageQueueIF* QueueMapManager::getMessageQueue(
MessageQueueId_t messageQueueId) const { MessageQueueId_t messageQueueId) const {
MutexGuard(mapLock, MutexIF::TimeoutType::WAITING, 50); auto queueIter = queueMap.find(messageQueueId);
auto queueIter = queueMap.find(messageQueueId); if(queueIter != queueMap.end()) {
if(queueIter != queueMap.end()) { return queueIter->second;
return queueIter->second; }
} else {
else {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "QueueMapManager::getQueueHandle: The ID " << messageQueueId << sif::warning << "QueueMapManager::getQueueHandle: The ID " << messageQueueId <<
" does not exists in the map!" << std::endl; " does not exists in the map!" << std::endl;
#else #else
sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n", sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n",
messageQueueId); messageQueueId);
#endif #endif
return nullptr; }
} return nullptr;
} }

View File

@ -15,33 +15,36 @@ using QueueMap = std::unordered_map<MessageQueueId_t, MessageQueueIF*>;
*/ */
class QueueMapManager { class QueueMapManager {
public: public:
//! Returns the single instance of SemaphoreFactory.
static QueueMapManager* instance();
/**
* Insert a message queue into the map and returns a message queue ID //! Returns the single instance of QueueMapManager.
* @param queue The message queue to insert. static QueueMapManager* instance();
* @param id The passed value will be set unless a nullptr is passed
* @return /**
*/ * Insert a message queue into the map and returns a message queue ID
ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t* * @param queue The message queue to insert.
id = nullptr); * @param id The passed value will be set unless a nullptr is passed
/** * @return
* Get the message queue handle by providing a message queue ID. */
* @param messageQueueId ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t*
* @return id = nullptr);
*/ /**
MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const; * Get the message queue handle by providing a message queue ID. Returns nullptr
* if the queue ID is not contained inside the internal map.
* @param messageQueueId
* @return
*/
MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const;
private: private:
//! External instantiation is forbidden. //! External instantiation is forbidden. Constructor still required for singleton instantiation.
QueueMapManager(); QueueMapManager();
~QueueMapManager(); ~QueueMapManager();
uint32_t queueCounter = 0; uint32_t queueCounter = 0;
MutexIF* mapLock; MutexIF* mapLock;
QueueMap queueMap; QueueMap queueMap;
static QueueMapManager* mqManagerInstance; static QueueMapManager* mqManagerInstance;
}; };

View File

@ -50,8 +50,8 @@ void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t s
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString << sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
" | " << infoString << std::endl; " | " << infoString << std::endl;
#else #else
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString, sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString.c_str(),
errorSrcString, infoString); errorSrcString.c_str(), infoString.c_str());
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */

10
platform.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef FSFW_PLATFORM_H_
#define FSFW_PLATFORM_H_
#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define PLATFORM_UNIX
#elif defined(_WIN32)
#define PLATFORM_WIN
#endif
#endif /* FSFW_PLATFORM_H_ */

View File

@ -1,6 +1,7 @@
#include "Service17Test.h" #include "Service17Test.h"
#include <FSFWConfig.h>
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "../tmtcpacket/pus/TmPacketStored.h" #include "../tmtcpacket/pus/TmPacketStored.h"
@ -17,15 +18,25 @@ Service17Test::~Service17Test() {
ReturnValue_t Service17Test::handleRequest(uint8_t subservice) { ReturnValue_t Service17Test::handleRequest(uint8_t subservice) {
switch(subservice) { switch(subservice) {
case Subservice::CONNECTION_TEST: { case Subservice::CONNECTION_TEST: {
TmPacketStored connectionPacket(apid, serviceId, #if FSFW_USE_PUS_C_TELEMETRY == 0
TmPacketStoredPusA connectionPacket(apid, serviceId,
Subservice::CONNECTION_TEST_REPORT, packetSubCounter++); Subservice::CONNECTION_TEST_REPORT, packetSubCounter++);
#else
TmPacketStoredPusC connectionPacket(apid, serviceId,
Subservice::CONNECTION_TEST_REPORT, packetSubCounter++);
#endif
connectionPacket.sendPacket(requestQueue->getDefaultDestination(), connectionPacket.sendPacket(requestQueue->getDefaultDestination(),
requestQueue->getId()); requestQueue->getId());
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
case Subservice::EVENT_TRIGGER_TEST: { case Subservice::EVENT_TRIGGER_TEST: {
TmPacketStored connectionPacket(apid, serviceId, #if FSFW_USE_PUS_C_TELEMETRY == 0
TmPacketStoredPusA connectionPacket(apid, serviceId,
Subservice::CONNECTION_TEST_REPORT, packetSubCounter++); Subservice::CONNECTION_TEST_REPORT, packetSubCounter++);
#else
TmPacketStoredPusC connectionPacket(apid, serviceId,
Subservice::CONNECTION_TEST_REPORT, packetSubCounter++);
#endif
connectionPacket.sendPacket(requestQueue->getDefaultDestination(), connectionPacket.sendPacket(requestQueue->getDefaultDestination(),
requestQueue->getId()); requestQueue->getId());
triggerEvent(TEST, 1234, 5678); triggerEvent(TEST, 1234, 5678);

View File

@ -68,8 +68,13 @@ ReturnValue_t Service1TelecommandVerification::generateFailureReport(
message->getTcSequenceControl(), message->getStep(), message->getTcSequenceControl(), message->getStep(),
message->getErrorCode(), message->getParameter1(), message->getErrorCode(), message->getParameter1(),
message->getParameter2()); message->getParameter2());
TmPacketStored tmPacket(apid, serviceId, message->getReportId(), #if FSFW_USE_PUS_C_TELEMETRY == 0
TmPacketStoredPusA tmPacket(apid, serviceId, message->getReportId(),
packetSubCounter++, &report); packetSubCounter++, &report);
#else
TmPacketStoredPusC tmPacket(apid, serviceId, message->getReportId(),
packetSubCounter++, &report);
#endif
ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(),
tmQueue->getId()); tmQueue->getId());
return result; return result;
@ -79,8 +84,13 @@ ReturnValue_t Service1TelecommandVerification::generateSuccessReport(
PusVerificationMessage *message) { PusVerificationMessage *message) {
SuccessReport report(message->getReportId(),message->getTcPacketId(), SuccessReport report(message->getReportId(),message->getTcPacketId(),
message->getTcSequenceControl(),message->getStep()); message->getTcSequenceControl(),message->getStep());
TmPacketStored tmPacket(apid, serviceId, message->getReportId(), #if FSFW_USE_PUS_C_TELEMETRY == 0
TmPacketStoredPusA tmPacket(apid, serviceId, message->getReportId(),
packetSubCounter++, &report); packetSubCounter++, &report);
#else
TmPacketStoredPusC tmPacket(apid, serviceId, message->getReportId(),
packetSubCounter++, &report);
#endif
ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(),
tmQueue->getId()); tmQueue->getId());
return result; return result;

View File

@ -52,8 +52,13 @@ ReturnValue_t Service5EventReporting::generateEventReport(
{ {
EventReport report(message.getEventId(),message.getReporter(), EventReport report(message.getEventId(),message.getReporter(),
message.getParameter1(),message.getParameter2()); message.getParameter1(),message.getParameter2());
TmPacketStored tmPacket(PusServiceBase::apid, PusServiceBase::serviceId, #if FSFW_USE_PUS_C_TELEMETRY == 0
TmPacketStoredPusA tmPacket(PusServiceBase::apid, PusServiceBase::serviceId,
message.getSeverity(), packetSubCounter++, &report); message.getSeverity(), packetSubCounter++, &report);
#else
TmPacketStoredPusC tmPacket(PusServiceBase::apid, PusServiceBase::serviceId,
message.getSeverity(), packetSubCounter++, &report);
#endif
ReturnValue_t result = tmPacket.sendPacket( ReturnValue_t result = tmPacket.sendPacket(
requestQueue->getDefaultDestination(),requestQueue->getId()); requestQueue->getDefaultDestination(),requestQueue->getId());
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -1,72 +1,78 @@
#ifndef FSFW_RETURNVALUES_FWCLASSIDS_H_ #ifndef FSFW_RETURNVALUES_FWCLASSIDS_H_
#define FSFW_RETURNVALUES_FWCLASSIDS_H_ #define FSFW_RETURNVALUES_FWCLASSIDS_H_
#include <cstdint>
// The comment block at the end is used by the returnvalue exporter.
// It is recommended to add it as well for mission returnvalues
namespace CLASS_ID { namespace CLASS_ID {
enum { enum: uint8_t {
OPERATING_SYSTEM_ABSTRACTION = 1, //OS FW_CLASS_ID_START = 0, // [EXPORT] : [START]
OBJECT_MANAGER_IF, //OM OPERATING_SYSTEM_ABSTRACTION, //OS
DEVICE_HANDLER_BASE, //DHB OBJECT_MANAGER_IF, //OM
RMAP_CHANNEL, //RMP DEVICE_HANDLER_BASE, //DHB
POWER_SWITCH_IF, //PS RMAP_CHANNEL, //RMP
HAS_MEMORY_IF, //PP POWER_SWITCH_IF, //PS
DEVICE_STATE_MACHINE_BASE, //DSMB HAS_MEMORY_IF, //PP
DATA_SET_CLASS, //DPS DEVICE_STATE_MACHINE_BASE, //DSMB
POOL_RAW_ACCESS_CLASS, //DPR DATA_SET_CLASS, //DPS
CONTROLLER_BASE, //CTR POOL_RAW_ACCESS_CLASS, //DPR
SUBSYSTEM_BASE, //SB CONTROLLER_BASE, //CTR
MODE_STORE_IF, //MS SUBSYSTEM_BASE, //SB
SUBSYSTEM, //SS MODE_STORE_IF, //MS
HAS_MODES_IF, //HM SUBSYSTEM, //SS
COMMAND_MESSAGE, //CM HAS_MODES_IF, //HM
CCSDS_TIME_HELPER_CLASS, //TIM COMMAND_MESSAGE, //CM
ARRAY_LIST, //AL CCSDS_TIME_HELPER_CLASS, //TIM
ASSEMBLY_BASE, //AB ARRAY_LIST, //AL
MEMORY_HELPER, //MH ASSEMBLY_BASE, //AB
SERIALIZE_IF, //SE MEMORY_HELPER, //MH
FIXED_MAP, //FM SERIALIZE_IF, //SE
FIXED_MULTIMAP, //FMM FIXED_MAP, //FM
HAS_HEALTH_IF, //HHI FIXED_MULTIMAP, //FMM
FIFO_CLASS, //FF HAS_HEALTH_IF, //HHI
MESSAGE_PROXY, //MQP FIFO_CLASS, //FF
TRIPLE_REDUNDACY_CHECK, //TRC MESSAGE_PROXY, //MQP
TC_PACKET_CHECK, //TCC TRIPLE_REDUNDACY_CHECK, //TRC
PACKET_DISTRIBUTION, //TCD TC_PACKET_CHECK, //TCC
ACCEPTS_TELECOMMANDS_IF, //PUS PACKET_DISTRIBUTION, //TCD
DEVICE_SERVICE_BASE, //DSB ACCEPTS_TELECOMMANDS_IF, //PUS
COMMAND_SERVICE_BASE, //CSB DEVICE_SERVICE_BASE, //DSB
TM_STORE_BACKEND_IF, //TMB COMMAND_SERVICE_BASE, //CSB
TM_STORE_FRONTEND_IF, //TMF TM_STORE_BACKEND_IF, //TMB
STORAGE_AND_RETRIEVAL_SERVICE, //SR TM_STORE_FRONTEND_IF, //TMF
MATCH_TREE_CLASS, //MT STORAGE_AND_RETRIEVAL_SERVICE, //SR
EVENT_MANAGER_IF, //EV MATCH_TREE_CLASS, //MT
HANDLES_FAILURES_IF, //FDI EVENT_MANAGER_IF, //EV
DEVICE_HANDLER_IF, //DHI HANDLES_FAILURES_IF, //FDI
STORAGE_MANAGER_IF, //SM DEVICE_HANDLER_IF, //DHI
THERMAL_COMPONENT_IF, //TC STORAGE_MANAGER_IF, //SM
INTERNAL_ERROR_CODES, //IEC THERMAL_COMPONENT_IF, //TC
TRAP, //TRP INTERNAL_ERROR_CODES, //IEC
CCSDS_HANDLER_IF, //CCS TRAP, //TRP
PARAMETER_WRAPPER, //PAW CCSDS_HANDLER_IF, //CCS
HAS_PARAMETERS_IF, //HPA PARAMETER_WRAPPER, //PAW
ASCII_CONVERTER, //ASC HAS_PARAMETERS_IF, //HPA
POWER_SWITCHER, //POS ASCII_CONVERTER, //ASC
LIMITS_IF, //LIM POWER_SWITCHER, //POS
COMMANDS_ACTIONS_IF, //CF LIMITS_IF, //LIM
HAS_ACTIONS_IF, //HF COMMANDS_ACTIONS_IF, //CF
DEVICE_COMMUNICATION_IF, //DC HAS_ACTIONS_IF, //HF
BSP, //BSP DEVICE_COMMUNICATION_IF, //DC
TIME_STAMPER_IF, //TSI 53 BSP, //BSP
SGP4PROPAGATOR_CLASS, //SGP4 54 TIME_STAMPER_IF, //TSI
MUTEX_IF, //MUX 55 SGP4PROPAGATOR_CLASS, //SGP4
MESSAGE_QUEUE_IF,//MQI 56 MUTEX_IF, //MUX
SEMAPHORE_IF, //SPH 57 MESSAGE_QUEUE_IF,//MQI
LOCAL_POOL_OWNER_IF, //LPIF 58 SEMAPHORE_IF, //SPH
POOL_VARIABLE_IF, //PVA 59 LOCAL_POOL_OWNER_IF, //LPIF
HOUSEKEEPING_MANAGER, //HKM 60 POOL_VARIABLE_IF, //PVA
DLE_ENCODER, //DLEE 61 HOUSEKEEPING_MANAGER, //HKM
PUS_SERVICE_9, //PUS9 62 DLE_ENCODER, //DLEE
FILE_SYSTEM, //FILS 63 PUS_SERVICE_3, //PUS3
FW_CLASS_ID_COUNT //is actually count + 1 ! PUS_SERVICE_9, //PUS9
FILE_SYSTEM, //FILS
FW_CLASS_ID_COUNT // [EXPORT] : [END]
}; };
} }

View File

@ -19,7 +19,10 @@
class SerializeIF { class SerializeIF {
public: public:
enum class Endianness : uint8_t { enum class Endianness : uint8_t {
BIG, LITTLE, MACHINE BIG,
LITTLE,
MACHINE,
NETWORK = BIG // Added for convenience like htons on sockets
}; };
static const uint8_t INTERFACE_ID = CLASS_ID::SERIALIZE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::SERIALIZE_IF;

View File

@ -5,9 +5,9 @@
#include "serviceInterfaceDefintions.h" #include "serviceInterfaceDefintions.h"
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
#include <fsfw/serviceinterface/ServiceInterfaceStream.h> #include "ServiceInterfaceStream.h"
#else #else
#include <fsfw/serviceinterface/ServiceInterfacePrinter.h> #include "ServiceInterfacePrinter.h"
#endif #endif
#endif /* FSFW_SERVICEINTERFACE_SERVICEINTERFACE_H_ */ #endif /* FSFW_SERVICEINTERFACE_SERVICEINTERFACE_H_ */

View File

@ -1,7 +1,9 @@
#ifndef FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ #ifndef FSFW_TIMEMANAGER_TIMESTAMPERIF_H_
#define FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ #define FSFW_TIMEMANAGER_TIMESTAMPERIF_H_
#include <FSFWConfig.h>
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <FSFWConfig.h>
/** /**
* A class implementing this IF provides facilities to add a time stamp to the * A class implementing this IF provides facilities to add a time stamp to the
@ -16,8 +18,8 @@ public:
//! This is a mission-specific constant and determines the total //! This is a mission-specific constant and determines the total
//! size reserved for timestamps. //! size reserved for timestamps.
//! TODO: Default define in FSFWConfig ? static const uint8_t MISSION_TIMESTAMP_SIZE = fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE;
static const uint8_t MISSION_TIMESTAMP_SIZE = 8;
virtual ReturnValue_t addTimeStamp(uint8_t* buffer, virtual ReturnValue_t addTimeStamp(uint8_t* buffer,
const uint8_t maxSize) = 0; const uint8_t maxSize) = 0;
virtual ~TimeStamperIF() {} virtual ~TimeStamperIF() {}

View File

@ -4,5 +4,9 @@ target_sources(${LIB_FSFW_NAME}
TcPacketStored.cpp TcPacketStored.cpp
TmPacketBase.cpp TmPacketBase.cpp
TmPacketMinimal.cpp TmPacketMinimal.cpp
TmPacketStored.cpp TmPacketStoredPusA.cpp
TmPacketStoredPusC.cpp
TmPacketPusA.cpp
TmPacketPusC.cpp
TmPacketStoredBase.cpp
) )

View File

@ -3,119 +3,66 @@
#include "../../globalfunctions/CRC.h" #include "../../globalfunctions/CRC.h"
#include "../../globalfunctions/arrayprinter.h" #include "../../globalfunctions/arrayprinter.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManagerIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../timemanager/CCSDSTime.h" #include "../../timemanager/CCSDSTime.h"
#include <cstring> #include <cstring>
TimeStamperIF* TmPacketBase::timeStamper = nullptr; TimeStamperIF* TmPacketBase::timeStamper = nullptr;
object_id_t TmPacketBase::timeStamperId = 0; object_id_t TmPacketBase::timeStamperId = objects::NO_OBJECT;
TmPacketBase::TmPacketBase(uint8_t* setData) : TmPacketBase::TmPacketBase(uint8_t* setData):
SpacePacketBase(setData) { SpacePacketBase(setData) {
tmData = reinterpret_cast<TmPacketPointer*>(setData);
} }
TmPacketBase::~TmPacketBase() { TmPacketBase::~TmPacketBase() {
//Nothing to do. //Nothing to do.
} }
uint8_t TmPacketBase::getService() {
return tmData->data_field.service_type;
}
uint8_t TmPacketBase::getSubService() {
return tmData->data_field.service_subtype;
}
uint8_t* TmPacketBase::getSourceData() {
return &tmData->data;
}
uint16_t TmPacketBase::getSourceDataSize() { uint16_t TmPacketBase::getSourceDataSize() {
return getPacketDataLength() - sizeof(tmData->data_field) return getPacketDataLength() - getDataFieldSize() - CRC_SIZE + 1;
- CRC_SIZE + 1;
} }
uint16_t TmPacketBase::getErrorControl() { uint16_t TmPacketBase::getErrorControl() {
uint32_t size = getSourceDataSize() + CRC_SIZE; uint32_t size = getSourceDataSize() + CRC_SIZE;
uint8_t* p_to_buffer = &tmData->data; uint8_t* p_to_buffer = getSourceData();
return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1];
} }
void TmPacketBase::setErrorControl() { void TmPacketBase::setErrorControl() {
uint32_t full_size = getFullSize(); uint32_t full_size = getFullSize();
uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE);
uint32_t size = getSourceDataSize(); uint32_t size = getSourceDataSize();
getSourceData()[size] = (crc & 0XFF00) >> 8; // CRCH getSourceData()[size] = (crc & 0XFF00) >> 8; // CRCH
getSourceData()[size + 1] = (crc) & 0X00FF; // CRCL getSourceData()[size + 1] = (crc) & 0X00FF; // CRCL
} }
void TmPacketBase::setData(const uint8_t* p_Data) { ReturnValue_t TmPacketBase::getPacketTime(timeval* timestamp) const {
SpacePacketBase::setData(p_Data); size_t tempSize = 0;
tmData = (TmPacketPointer*) p_Data; return CCSDSTime::convertFromCcsds(timestamp, getPacketTimeRaw(),
&tempSize, getTimestampSize());
} }
void TmPacketBase::print() { void TmPacketBase::print() {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "TmPacketBase::print: " << std::endl; sif::debug << "TmPacketBase::print: " << std::endl;
#endif #endif
arrayprinter::print(getWholeData(), getFullSize()); arrayprinter::print(getWholeData(), getFullSize());
} }
bool TmPacketBase::checkAndSetStamper() { bool TmPacketBase::checkAndSetStamper() {
if (timeStamper == NULL) { if (timeStamper == NULL) {
timeStamper = objectManager->get<TimeStamperIF>(timeStamperId); timeStamper = objectManager->get<TimeStamperIF>(timeStamperId);
if (timeStamper == NULL) { if (timeStamper == NULL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmPacketBase::checkAndSetStamper: Stamper not found!" sif::warning << "TmPacketBase::checkAndSetStamper: Stamper not found!" << std::endl;
<< std::endl; #else
sif::printWarning("TmPacketBase::checkAndSetStamper: Stamper not found!\n");
#endif #endif
return false; return false;
} }
} }
return true; return true;
} }
ReturnValue_t TmPacketBase::getPacketTime(timeval* timestamp) const {
size_t tempSize = 0;
return CCSDSTime::convertFromCcsds(timestamp, tmData->data_field.time,
&tempSize, sizeof(tmData->data_field.time));
}
uint8_t* TmPacketBase::getPacketTimeRaw() const{
return tmData->data_field.time;
}
void TmPacketBase::initializeTmPacket(uint16_t apid, uint8_t service,
uint8_t subservice, uint8_t packetSubcounter) {
//Set primary header:
initSpacePacketHeader(false, true, apid);
//Set data Field Header:
//First, set to zero.
memset(&tmData->data_field, 0, sizeof(tmData->data_field));
// NOTE: In PUS-C, the PUS Version is 2 and specified for the first 4 bits.
// The other 4 bits of the first byte are the spacecraft time reference
// status. To change to PUS-C, set 0b00100000.
// Set CCSDS_secondary header flag to 0, version number to 001 and ack
// to 0000
tmData->data_field.version_type_ack = 0b00010000;
tmData->data_field.service_type = service;
tmData->data_field.service_subtype = subservice;
tmData->data_field.subcounter = packetSubcounter;
//Timestamp packet
if (checkAndSetStamper()) {
timeStamper->addTimeStamp(tmData->data_field.time,
sizeof(tmData->data_field.time));
}
}
void TmPacketBase::setSourceDataSize(uint16_t size) {
setPacketDataLength(size + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1);
}
size_t TmPacketBase::getTimestampSize() const {
return sizeof(tmData->data_field.time);
}

View File

@ -10,32 +10,6 @@ namespace Factory{
void setStaticFrameworkObjectIds(); void setStaticFrameworkObjectIds();
} }
/**
* This struct defines a byte-wise structured PUS TM Data Field Header.
* Any optional fields in the header must be added or removed here.
* Currently, no Destination field is present, but an eigth-byte representation
* for a time tag.
* @ingroup tmtcpackets
*/
struct PUSTmDataFieldHeader {
uint8_t version_type_ack;
uint8_t service_type;
uint8_t service_subtype;
uint8_t subcounter;
// uint8_t destination;
uint8_t time[TimeStamperIF::MISSION_TIMESTAMP_SIZE];
};
/**
* This struct defines the data structure of a PUS Telecommand Packet when
* accessed via a pointer.
* @ingroup tmtcpackets
*/
struct TmPacketPointer {
CCSDSPrimaryHeader primary;
PUSTmDataFieldHeader data_field;
uint8_t data;
};
/** /**
* This class is the basic data handler for any ECSS PUS Telemetry packet. * This class is the basic data handler for any ECSS PUS Telemetry packet.
@ -49,61 +23,83 @@ struct TmPacketPointer {
* @ingroup tmtcpackets * @ingroup tmtcpackets
*/ */
class TmPacketBase : public SpacePacketBase { class TmPacketBase : public SpacePacketBase {
friend void (Factory::setStaticFrameworkObjectIds)(); friend void (Factory::setStaticFrameworkObjectIds)();
public: public:
/**
* This constant defines the minimum size of a valid PUS Telemetry Packet.
*/
static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) +
sizeof(PUSTmDataFieldHeader) + 2);
//! Maximum size of a TM Packet in this mission.
//! TODO: Make this dependant on a config variable.
static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048;
//! First byte of secondary header for PUS-A packets.
//! TODO: Maybe also support PUS-C via config?
static const uint8_t VERSION_NUMBER_BYTE_PUS_A = 0b00010000;
/** //! Maximum size of a TM Packet in this mission.
* This is the default constructor. //! TODO: Make this dependant on a config variable.
* It sets its internal data pointer to the address passed and also static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048;
* forwards the data pointer to the parent SpacePacketBase class. //! First four bits of first byte of secondary header
* @param set_address The position where the packet data lies. static const uint8_t VERSION_NUMBER_BYTE = 0b00010000;
*/
TmPacketBase( uint8_t* setData );
/**
* This is the empty default destructor.
*/
virtual ~TmPacketBase();
/** /**
* This is a getter for the packet's PUS Service ID, which is the second * This is the default constructor.
* byte of the Data Field Header. * It sets its internal data pointer to the address passed and also
* @return The packet's PUS Service ID. * forwards the data pointer to the parent SpacePacketBase class.
*/ * @param set_address The position where the packet data lies.
uint8_t getService(); */
/** TmPacketBase( uint8_t* setData );
* This is a getter for the packet's PUS Service Subtype, which is the /**
* third byte of the Data Field Header. * This is the empty default destructor.
* @return The packet's PUS Service Subtype. */
*/ virtual ~TmPacketBase();
uint8_t getSubService();
/**
* This is a getter for a pointer to the packet's Source data.
*
* These are the bytes that follow after the Data Field Header. They form
* the packet's source data.
* @return A pointer to the PUS Source Data.
*/
uint8_t* getSourceData();
/**
* This method calculates the size of the PUS Source data field.
*
* It takes the information stored in the CCSDS Packet Data Length field
* and subtracts the Data Field Header size and the CRC size.
* @return The size of the PUS Source Data (without Error Control field)
*/
uint16_t getSourceDataSize();
/**
* This is a getter for the packet's PUS Service ID, which is the second
* byte of the Data Field Header.
* @return The packet's PUS Service ID.
*/
virtual uint8_t getService() = 0;
/**
* This is a getter for the packet's PUS Service Subtype, which is the
* third byte of the Data Field Header.
* @return The packet's PUS Service Subtype.
*/
virtual uint8_t getSubService() = 0;
/**
* This is a getter for a pointer to the packet's Source data.
*
* These are the bytes that follow after the Data Field Header. They form
* the packet's source data.
* @return A pointer to the PUS Source Data.
*/
virtual uint8_t* getSourceData() = 0;
/**
* This method calculates the size of the PUS Source data field.
*
* It takes the information stored in the CCSDS Packet Data Length field
* and subtracts the Data Field Header size and the CRC size.
* @return The size of the PUS Source Data (without Error Control field)
*/
virtual uint16_t getSourceDataSize() = 0;
/**
* Get size of data field which can differ based on implementation
* @return
*/
virtual uint16_t getDataFieldSize() = 0;
virtual size_t getPacketMinimumSize() const = 0;
/**
* Interprets the "time"-field in the secondary header and returns it in
* timeval format.
* @return Converted timestamp of packet.
*/
virtual ReturnValue_t getPacketTime(timeval* timestamp) const;
/**
* Returns a raw pointer to the beginning of the time field.
* @return Raw pointer to time field.
*/
virtual uint8_t* getPacketTimeRaw() const = 0;
virtual size_t getTimestampSize() const = 0;
/**
* This is a debugging helper method that prints the whole packet content
* to the screen.
*/
void print();
/** /**
* With this method, the Error Control Field is updated to match the * With this method, the Error Control Field is updated to match the
* current content of the packet. This method is not protected because * current content of the packet. This method is not protected because
@ -111,79 +107,24 @@ public:
* like the sequence count. * like the sequence count.
*/ */
void setErrorControl(); void setErrorControl();
/**
/** * This getter returns the Error Control Field of the packet.
* This getter returns the Error Control Field of the packet. *
* * The field is placed after any possible Source Data. If no
* The field is placed after any possible Source Data. If no * Source Data is present there's still an Error Control field. It is
* Source Data is present there's still an Error Control field. It is * supposed to be a 16bit-CRC.
* supposed to be a 16bit-CRC. * @return The PUS Error Control
* @return The PUS Error Control */
*/ uint16_t getErrorControl();
uint16_t getErrorControl();
/**
* This is a debugging helper method that prints the whole packet content
* to the screen.
*/
void print();
/**
* Interprets the "time"-field in the secondary header and returns it in
* timeval format.
* @return Converted timestamp of packet.
*/
ReturnValue_t getPacketTime(timeval* timestamp) const;
/**
* Returns a raw pointer to the beginning of the time field.
* @return Raw pointer to time field.
*/
uint8_t* getPacketTimeRaw() const;
size_t getTimestampSize() const;
protected: protected:
/**
* A pointer to a structure which defines the data structure of
* the packet's data.
*
* To be hardware-safe, all elements are of byte size.
*/
TmPacketPointer* tmData;
/**
* The timeStamper is responsible for adding a timestamp to the packet.
* It is initialized lazy.
*/
static TimeStamperIF* timeStamper;
//! The ID to use when looking for a time stamper.
static object_id_t timeStamperId;
/** /**
* Initializes the Tm Packet header. * The timeStamper is responsible for adding a timestamp to the packet.
* Does set the timestamp (to now), but not the error control field. * It is initialized lazy.
* @param apid APID used.
* @param service PUS Service
* @param subservice PUS Subservice
* @param packetSubcounter Additional subcounter used.
*/ */
void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, static TimeStamperIF* timeStamper;
uint8_t packetSubcounter); //! The ID to use when looking for a time stamper.
static object_id_t timeStamperId;
/**
* With this method, the packet data pointer can be redirected to another
* location.
*
* This call overwrites the parent's setData method to set both its
* @c tc_data pointer and the parent's @c data pointer.
*
* @param p_data A pointer to another PUS Telemetry Packet.
*/
void setData( const uint8_t* pData );
/**
* In case data was filled manually (almost never the case).
* @param size Size of source data (without CRC and data filed header!).
*/
void setSourceDataSize(uint16_t size);
/** /**
* Checks if a time stamper is available and tries to set it if not. * Checks if a time stamper is available and tries to set it if not.

View File

@ -0,0 +1,87 @@
#include "TmPacketPusA.h"
#include "TmPacketBase.h"
#include "../../globalfunctions/CRC.h"
#include "../../globalfunctions/arrayprinter.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/CCSDSTime.h"
#include <cstring>
TmPacketPusA::TmPacketPusA(uint8_t* setData) : TmPacketBase(setData) {
tmData = reinterpret_cast<TmPacketPointerPusA*>(setData);
}
TmPacketPusA::~TmPacketPusA() {
//Nothing to do.
}
uint8_t TmPacketPusA::getService() {
return tmData->data_field.service_type;
}
uint8_t TmPacketPusA::getSubService() {
return tmData->data_field.service_subtype;
}
uint8_t* TmPacketPusA::getSourceData() {
return &tmData->data;
}
uint16_t TmPacketPusA::getSourceDataSize() {
return getPacketDataLength() - sizeof(tmData->data_field)
- CRC_SIZE + 1;
}
void TmPacketPusA::setData(const uint8_t* p_Data) {
SpacePacketBase::setData(p_Data);
tmData = (TmPacketPointerPusA*) p_Data;
}
size_t TmPacketPusA::getPacketMinimumSize() const {
return TM_PACKET_MIN_SIZE;
}
uint16_t TmPacketPusA::getDataFieldSize() {
return sizeof(PUSTmDataFieldHeaderPusA);
}
uint8_t* TmPacketPusA::getPacketTimeRaw() const {
return tmData->data_field.time;
}
void TmPacketPusA::initializeTmPacket(uint16_t apid, uint8_t service,
uint8_t subservice, uint8_t packetSubcounter) {
//Set primary header:
initSpacePacketHeader(false, true, apid);
//Set data Field Header:
//First, set to zero.
memset(&tmData->data_field, 0, sizeof(tmData->data_field));
// NOTE: In PUS-C, the PUS Version is 2 and specified for the first 4 bits.
// The other 4 bits of the first byte are the spacecraft time reference
// status. To change to PUS-C, set 0b00100000.
// Set CCSDS_secondary header flag to 0, version number to 001 and ack
// to 0000
tmData->data_field.version_type_ack = 0b00010000;
tmData->data_field.service_type = service;
tmData->data_field.service_subtype = subservice;
tmData->data_field.subcounter = packetSubcounter;
//Timestamp packet
if (TmPacketBase::checkAndSetStamper()) {
timeStamper->addTimeStamp(tmData->data_field.time,
sizeof(tmData->data_field.time));
}
}
void TmPacketPusA::setSourceDataSize(uint16_t size) {
setPacketDataLength(size + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1);
}
size_t TmPacketPusA::getTimestampSize() const {
return sizeof(tmData->data_field.time);
}

View File

@ -0,0 +1,129 @@
#ifndef FSFW_TMTCPACKET_PUS_TMPACKETPUSA_H_
#define FSFW_TMTCPACKET_PUS_TMPACKETPUSA_H_
#include "TmPacketBase.h"
#include "../SpacePacketBase.h"
#include "../../timemanager/TimeStamperIF.h"
#include "../../timemanager/Clock.h"
#include "../../objectmanager/SystemObjectIF.h"
namespace Factory{
void setStaticFrameworkObjectIds();
}
/**
* This struct defines a byte-wise structured PUS TM Data Field Header.
* Any optional fields in the header must be added or removed here.
* Currently, no Destination field is present, but an eigth-byte representation
* for a time tag.
* @ingroup tmtcpackets
*/
struct PUSTmDataFieldHeaderPusA {
uint8_t version_type_ack;
uint8_t service_type;
uint8_t service_subtype;
uint8_t subcounter;
// uint8_t destination;
uint8_t time[TimeStamperIF::MISSION_TIMESTAMP_SIZE];
};
/**
* This struct defines the data structure of a PUS Telecommand Packet when
* accessed via a pointer.
* @ingroup tmtcpackets
*/
struct TmPacketPointerPusA {
CCSDSPrimaryHeader primary;
PUSTmDataFieldHeaderPusA data_field;
uint8_t data;
};
/**
* PUS A packet implementation
* @ingroup tmtcpackets
*/
class TmPacketPusA: public TmPacketBase {
friend void (Factory::setStaticFrameworkObjectIds)();
public:
/**
* This constant defines the minimum size of a valid PUS Telemetry Packet.
*/
static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) +
sizeof(PUSTmDataFieldHeaderPusA) + 2);
//! Maximum size of a TM Packet in this mission.
//! TODO: Make this dependant on a config variable.
static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048;
/**
* This is the default constructor.
* It sets its internal data pointer to the address passed and also
* forwards the data pointer to the parent SpacePacketBase class.
* @param set_address The position where the packet data lies.
*/
TmPacketPusA( uint8_t* setData );
/**
* This is the empty default destructor.
*/
virtual ~TmPacketPusA();
/* TmPacketBase implementations */
uint8_t getService() override;
uint8_t getSubService() override;
uint8_t* getSourceData() override;
uint16_t getSourceDataSize() override;
uint16_t getDataFieldSize() override;
/**
* Returns a raw pointer to the beginning of the time field.
* @return Raw pointer to time field.
*/
uint8_t* getPacketTimeRaw() const override;
size_t getTimestampSize() const override;
size_t getPacketMinimumSize() const override;
protected:
/**
* A pointer to a structure which defines the data structure of
* the packet's data.
*
* To be hardware-safe, all elements are of byte size.
*/
TmPacketPointerPusA* tmData;
/**
* Initializes the Tm Packet header.
* Does set the timestamp (to now), but not the error control field.
* @param apid APID used.
* @param service PUS Service
* @param subservice PUS Subservice
* @param packetSubcounter Additional subcounter used.
*/
void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice,
uint8_t packetSubcounter);
/**
* With this method, the packet data pointer can be redirected to another
* location.
*
* This call overwrites the parent's setData method to set both its
* @c tc_data pointer and the parent's @c data pointer.
*
* @param p_data A pointer to another PUS Telemetry Packet.
*/
void setData( const uint8_t* pData );
/**
* In case data was filled manually (almost never the case).
* @param size Size of source data (without CRC and data filed header!).
*/
void setSourceDataSize(uint16_t size);
/**
* Checks if a time stamper is available and tries to set it if not.
* @return Returns false if setting failed.
*/
bool checkAndSetStamper();
};
#endif /* FSFW_TMTCPACKET_PUS_TMPACKETPUSA_H_ */

View File

@ -0,0 +1,87 @@
#include "TmPacketPusC.h"
#include "TmPacketBase.h"
#include "../../globalfunctions/CRC.h"
#include "../../globalfunctions/arrayprinter.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/CCSDSTime.h"
#include <cstring>
TmPacketPusC::TmPacketPusC(uint8_t* setData) : TmPacketBase(setData) {
tmData = reinterpret_cast<TmPacketPointerPusC*>(setData);
}
TmPacketPusC::~TmPacketPusC() {
//Nothing to do.
}
uint8_t TmPacketPusC::getService() {
return tmData->dataField.serviceType;
}
uint8_t TmPacketPusC::getSubService() {
return tmData->dataField.serviceSubtype;
}
uint8_t* TmPacketPusC::getSourceData() {
return &tmData->data;
}
uint16_t TmPacketPusC::getSourceDataSize() {
return getPacketDataLength() - sizeof(tmData->dataField) - CRC_SIZE + 1;
}
void TmPacketPusC::setData(const uint8_t* p_Data) {
SpacePacketBase::setData(p_Data);
tmData = (TmPacketPointerPusC*) p_Data;
}
size_t TmPacketPusC::getPacketMinimumSize() const {
return TM_PACKET_MIN_SIZE;
}
uint16_t TmPacketPusC::getDataFieldSize() {
return sizeof(PUSTmDataFieldHeaderPusC);
}
uint8_t* TmPacketPusC::getPacketTimeRaw() const{
return tmData->dataField.time;
}
void TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service,
uint8_t subservice, uint16_t packetSubcounter, uint16_t destinationId,
uint8_t timeRefField) {
//Set primary header:
initSpacePacketHeader(false, true, apid);
//Set data Field Header:
//First, set to zero.
memset(&tmData->dataField, 0, sizeof(tmData->dataField));
/* Only account for last 4 bytes for time reference field */
timeRefField &= 0b1111;
tmData->dataField.versionTimeReferenceField = VERSION_NUMBER_BYTE | timeRefField;
tmData->dataField.serviceType = service;
tmData->dataField.serviceSubtype = subservice;
tmData->dataField.subcounterMsb = packetSubcounter << 8 & 0xff;
tmData->dataField.subcounterLsb = packetSubcounter & 0xff;
tmData->dataField.destinationIdMsb = destinationId << 8 & 0xff;
tmData->dataField.destinationIdLsb = destinationId & 0xff;
//Timestamp packet
if (TmPacketBase::checkAndSetStamper()) {
timeStamper->addTimeStamp(tmData->dataField.time,
sizeof(tmData->dataField.time));
}
}
void TmPacketPusC::setSourceDataSize(uint16_t size) {
setPacketDataLength(size + sizeof(PUSTmDataFieldHeaderPusC) + CRC_SIZE - 1);
}
size_t TmPacketPusC::getTimestampSize() const {
return sizeof(tmData->dataField.time);
}

View File

@ -0,0 +1,126 @@
#ifndef FSFW_TMTCPACKET_PUS_TMPACKETPUSC_H_
#define FSFW_TMTCPACKET_PUS_TMPACKETPUSC_H_
#include "TmPacketBase.h"
#include "../SpacePacketBase.h"
#include "../../timemanager/TimeStamperIF.h"
#include "../../timemanager/Clock.h"
#include "../../objectmanager/SystemObjectIF.h"
namespace Factory{
void setStaticFrameworkObjectIds();
}
/**
* This struct defines a byte-wise structured PUS TM Data Field Header.
* Any optional fields in the header must be added or removed here.
* Currently, no Destination field is present, but an eigth-byte representation
* for a time tag.
* @ingroup tmtcpackets
*/
struct PUSTmDataFieldHeaderPusC {
uint8_t versionTimeReferenceField;
uint8_t serviceType;
uint8_t serviceSubtype;
uint8_t subcounterMsb;
uint8_t subcounterLsb;
uint8_t destinationIdMsb;
uint8_t destinationIdLsb;
uint8_t time[TimeStamperIF::MISSION_TIMESTAMP_SIZE];
};
/**
* This struct defines the data structure of a PUS Telecommand Packet when
* accessed via a pointer.
* @ingroup tmtcpackets
*/
struct TmPacketPointerPusC {
CCSDSPrimaryHeader primary;
PUSTmDataFieldHeaderPusC dataField;
uint8_t data;
};
/**
* PUS A packet implementation
* @ingroup tmtcpackets
*/
class TmPacketPusC: public TmPacketBase {
friend void (Factory::setStaticFrameworkObjectIds)();
public:
/**
* This constant defines the minimum size of a valid PUS Telemetry Packet.
*/
static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) +
sizeof(PUSTmDataFieldHeaderPusC) + 2);
//! Maximum size of a TM Packet in this mission.
//! TODO: Make this dependant on a config variable.
static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048;
/**
* This is the default constructor.
* It sets its internal data pointer to the address passed and also
* forwards the data pointer to the parent SpacePacketBase class.
* @param set_address The position where the packet data lies.
*/
TmPacketPusC( uint8_t* setData );
/**
* This is the empty default destructor.
*/
virtual ~TmPacketPusC();
/* TmPacketBase implementations */
uint8_t getService() override;
uint8_t getSubService() override;
uint8_t* getSourceData() override;
uint16_t getSourceDataSize() override;
uint16_t getDataFieldSize() override;
/**
* Returns a raw pointer to the beginning of the time field.
* @return Raw pointer to time field.
*/
uint8_t* getPacketTimeRaw() const override;
size_t getTimestampSize() const override;
size_t getPacketMinimumSize() const override;
protected:
/**
* A pointer to a structure which defines the data structure of
* the packet's data.
*
* To be hardware-safe, all elements are of byte size.
*/
TmPacketPointerPusC* tmData;
/**
* Initializes the Tm Packet header.
* Does set the timestamp (to now), but not the error control field.
* @param apid APID used.
* @param service PUS Service
* @param subservice PUS Subservice
* @param packetSubcounter Additional subcounter used.
*/
void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice,
uint16_t packetSubcounter, uint16_t destinationId = 0, uint8_t timeRefField = 0);
/**
* With this method, the packet data pointer can be redirected to another
* location.
*
* This call overwrites the parent's setData method to set both its
* @c tc_data pointer and the parent's @c data pointer.
*
* @param p_data A pointer to another PUS Telemetry Packet.
*/
void setData( const uint8_t* pData );
/**
* In case data was filled manually (almost never the case).
* @param size Size of source data (without CRC and data filed header!).
*/
void setSourceDataSize(uint16_t size);
};
#endif /* FSFW_TMTCPACKET_PUS_TMPACKETPUSC_H_ */

View File

@ -1,147 +0,0 @@
#include "TmPacketStored.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tmtcservices/TmTcMessage.h"
#include <cstring>
StorageManagerIF *TmPacketStored::store = nullptr;
InternalErrorReporterIF *TmPacketStored::internalErrorReporter = nullptr;
TmPacketStored::TmPacketStored(store_address_t setAddress) :
TmPacketBase(nullptr), storeAddress(setAddress) {
setStoreAddress(storeAddress);
}
TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service,
uint8_t subservice, uint8_t packetSubcounter, const uint8_t *data,
uint32_t size, const uint8_t *headerData, uint32_t headerSize) :
TmPacketBase(NULL) {
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
if (not checkAndSetStore()) {
return;
}
uint8_t *pData = nullptr;
ReturnValue_t returnValue = store->getFreeElement(&storeAddress,
(TmPacketBase::TM_PACKET_MIN_SIZE + size + headerSize), &pData);
if (returnValue != store->RETURN_OK) {
checkAndReportLostTm();
return;
}
setData(pData);
initializeTmPacket(apid, service, subservice, packetSubcounter);
memcpy(getSourceData(), headerData, headerSize);
memcpy(getSourceData() + headerSize, data, size);
setPacketDataLength(
size + headerSize + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1);
}
TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service,
uint8_t subservice, uint8_t packetSubcounter, SerializeIF *content,
SerializeIF *header) :
TmPacketBase(NULL) {
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
if (not checkAndSetStore()) {
return;
}
size_t sourceDataSize = 0;
if (content != NULL) {
sourceDataSize += content->getSerializedSize();
}
if (header != NULL) {
sourceDataSize += header->getSerializedSize();
}
uint8_t *p_data = NULL;
ReturnValue_t returnValue = store->getFreeElement(&storeAddress,
(TmPacketBase::TM_PACKET_MIN_SIZE + sourceDataSize), &p_data);
if (returnValue != store->RETURN_OK) {
checkAndReportLostTm();
}
setData(p_data);
initializeTmPacket(apid, service, subservice, packetSubcounter);
uint8_t *putDataHere = getSourceData();
size_t size = 0;
if (header != NULL) {
header->serialize(&putDataHere, &size, sourceDataSize,
SerializeIF::Endianness::BIG);
}
if (content != NULL) {
content->serialize(&putDataHere, &size, sourceDataSize,
SerializeIF::Endianness::BIG);
}
setPacketDataLength(
sourceDataSize + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1);
}
store_address_t TmPacketStored::getStoreAddress() {
return storeAddress;
}
void TmPacketStored::deletePacket() {
store->deleteData(storeAddress);
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
setData(nullptr);
}
void TmPacketStored::setStoreAddress(store_address_t setAddress) {
storeAddress = setAddress;
const uint8_t* tempData = nullptr;
size_t tempSize;
if (not checkAndSetStore()) {
return;
}
ReturnValue_t status = store->getData(storeAddress, &tempData, &tempSize);
if (status == StorageManagerIF::RETURN_OK) {
setData(tempData);
} else {
setData(nullptr);
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
}
}
bool TmPacketStored::checkAndSetStore() {
if (store == nullptr) {
store = objectManager->get<StorageManagerIF>(objects::TM_STORE);
if (store == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmPacketStored::TmPacketStored: TM Store not found!"
<< std::endl;
#endif
return false;
}
}
return true;
}
ReturnValue_t TmPacketStored::sendPacket(MessageQueueId_t destination,
MessageQueueId_t sentFrom, bool doErrorReporting) {
if (getWholeData() == nullptr) {
//SHOULDDO: More decent code.
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage tmMessage(getStoreAddress());
ReturnValue_t result = MessageQueueSenderIF::sendMessage(destination,
&tmMessage, sentFrom);
if (result != HasReturnvaluesIF::RETURN_OK) {
deletePacket();
if (doErrorReporting) {
checkAndReportLostTm();
}
return result;
}
//SHOULDDO: In many cases, some counter is incremented for successfully sent packets. The check is often not done, but just incremented.
return HasReturnvaluesIF::RETURN_OK;
}
void TmPacketStored::checkAndReportLostTm() {
if (internalErrorReporter == nullptr) {
internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
}
if (internalErrorReporter != nullptr) {
internalErrorReporter->lostTm();
}
}

View File

@ -1,108 +1,13 @@
#ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ #ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_
#define FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ #define FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_
#include "TmPacketBase.h" #include <FSFWConfig.h>
#include "../../serialize/SerializeIF.h" #if FSFW_USE_PUS_C_TELEMETRY == 1
#include "../../storagemanager/StorageManagerIF.h" #include "TmPacketStoredPusC.h"
#include "../../internalError/InternalErrorReporterIF.h" #else
#include "../../ipc/MessageQueueSenderIF.h" #include "TmPacketStoredPusA.h"
#endif
/**
* This class generates a ECSS PUS Telemetry packet within a given
* intermediate storage.
* As most packets are passed between tasks with the help of a storage
* anyway, it seems logical to create a Packet-In-Storage access class
* which saves the user almost all storage handling operation.
* Packets can both be newly created with the class and be "linked" to
* packets in a store with the help of a storeAddress.
* @ingroup tmtcpackets
*/
class TmPacketStored : public TmPacketBase {
public:
/**
* This is a default constructor which does not set the data pointer.
* However, it does try to set the packet store.
*/
TmPacketStored( store_address_t setAddress );
/**
* With this constructor, new space is allocated in the packet store and
* a new PUS Telemetry Packet is created there.
* Packet Application Data passed in data is copied into the packet.
* The Application data is passed in two parts, first a header, then a
* data field. This allows building a Telemetry Packet from two separate
* data sources.
* @param apid Sets the packet's APID field.
* @param service Sets the packet's Service ID field.
* This specifies the source service.
* @param subservice Sets the packet's Service Subtype field.
* This specifies the source sub-service.
* @param packet_counter Sets the Packet counter field of this packet
* @param data The payload data to be copied to the
* Application Data Field
* @param size The amount of data to be copied.
* @param headerData The header Data of the Application field,
* will be copied in front of data
* @param headerSize The size of the headerDataF
*/
TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice,
uint8_t packet_counter = 0, const uint8_t* data = nullptr,
uint32_t size = 0, const uint8_t* headerData = nullptr,
uint32_t headerSize = 0);
/**
* Another ctor to directly pass structured content and header data to the
* packet to avoid additional buffers.
*/
TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice,
uint8_t packet_counter, SerializeIF* content,
SerializeIF* header = nullptr);
/**
* This is a getter for the current store address of the packet.
* @return The current store address. The (raw) value is
* @c StorageManagerIF::INVALID_ADDRESS if
* the packet is not linked.
*/
store_address_t getStoreAddress();
/**
* With this call, the packet is deleted.
* It removes itself from the store and sets its data pointer to NULL.
*/
void deletePacket();
/**
* With this call, a packet can be linked to another store. This is useful
* if the packet is a class member and used for more than one packet.
* @param setAddress The new packet id to link to.
*/
void setStoreAddress( store_address_t setAddress );
ReturnValue_t sendPacket( MessageQueueId_t destination,
MessageQueueId_t sentFrom, bool doErrorReporting = true );
private:
/**
* This is a pointer to the store all instances of the class use.
* If the store is not yet set (i.e. @c store is NULL), every constructor
* call tries to set it and throws an error message in case of failures.
* The default store is objects::TM_STORE.
*/
static StorageManagerIF* store;
static InternalErrorReporterIF *internalErrorReporter;
/**
* The address where the packet data of the object instance is stored.
*/
store_address_t storeAddress;
/**
* A helper method to check if a store is assigned to the class.
* If not, the method tries to retrieve the store from the global
* ObjectManager.
* @return @li @c true if the store is linked or could be created.
* @li @c false otherwise.
*/
bool checkAndSetStore();
void checkAndReportLostTm();
};
#endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ */ #endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ */

View File

@ -0,0 +1,94 @@
#include "TmPacketStoredBase.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tmtcservices/TmTcMessage.h"
#include <cstring>
StorageManagerIF *TmPacketStoredBase::store = nullptr;
InternalErrorReporterIF *TmPacketStoredBase::internalErrorReporter = nullptr;
TmPacketStoredBase::TmPacketStoredBase(store_address_t setAddress): storeAddress(setAddress) {
setStoreAddress(storeAddress);
}
TmPacketStoredBase::TmPacketStoredBase() {
}
TmPacketStoredBase::~TmPacketStoredBase() {
}
store_address_t TmPacketStoredBase::getStoreAddress() {
return storeAddress;
}
void TmPacketStoredBase::deletePacket() {
store->deleteData(storeAddress);
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
setDataPointer(nullptr);
}
void TmPacketStoredBase::setStoreAddress(store_address_t setAddress) {
storeAddress = setAddress;
const uint8_t* tempData = nullptr;
size_t tempSize;
if (not checkAndSetStore()) {
return;
}
ReturnValue_t status = store->getData(storeAddress, &tempData, &tempSize);
if (status == StorageManagerIF::RETURN_OK) {
setDataPointer(tempData);
} else {
setDataPointer(nullptr);
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
}
}
bool TmPacketStoredBase::checkAndSetStore() {
if (store == nullptr) {
store = objectManager->get<StorageManagerIF>(objects::TM_STORE);
if (store == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmPacketStored::TmPacketStored: TM Store not found!"
<< std::endl;
#endif
return false;
}
}
return true;
}
ReturnValue_t TmPacketStoredBase::sendPacket(MessageQueueId_t destination,
MessageQueueId_t sentFrom, bool doErrorReporting) {
if (getAllTmData() == nullptr) {
//SHOULDDO: More decent code.
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage tmMessage(getStoreAddress());
ReturnValue_t result = MessageQueueSenderIF::sendMessage(destination,
&tmMessage, sentFrom);
if (result != HasReturnvaluesIF::RETURN_OK) {
deletePacket();
if (doErrorReporting) {
checkAndReportLostTm();
}
return result;
}
//SHOULDDO: In many cases, some counter is incremented for successfully sent packets. The check is often not done, but just incremented.
return HasReturnvaluesIF::RETURN_OK;
}
void TmPacketStoredBase::checkAndReportLostTm() {
if (internalErrorReporter == nullptr) {
internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
}
if (internalErrorReporter != nullptr) {
internalErrorReporter->lostTm();
}
}

View File

@ -0,0 +1,89 @@
#ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTOREDBASE_H_
#define FSFW_TMTCPACKET_PUS_TMPACKETSTOREDBASE_H_
#include "TmPacketBase.h"
#include "TmPacketStoredBase.h"
#include <FSFWConfig.h>
#include "../../tmtcpacket/pus/TmPacketPusA.h"
#include "../../serialize/SerializeIF.h"
#include "../../storagemanager/StorageManagerIF.h"
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueSenderIF.h"
/**
* This class generates a ECSS PUS Telemetry packet within a given
* intermediate storage.
* As most packets are passed between tasks with the help of a storage
* anyway, it seems logical to create a Packet-In-Storage access class
* which saves the user almost all storage handling operation.
* Packets can both be newly created with the class and be "linked" to
* packets in a store with the help of a storeAddress.
* @ingroup tmtcpackets
*/
class TmPacketStoredBase {
public:
/**
* This is a default constructor which does not set the data pointer.
* However, it does try to set the packet store.
*/
TmPacketStoredBase( store_address_t setAddress );
TmPacketStoredBase();
virtual ~TmPacketStoredBase();
virtual uint8_t* getAllTmData() = 0;
virtual void setDataPointer(const uint8_t* newPointer) = 0;
/**
* This is a getter for the current store address of the packet.
* @return The current store address. The (raw) value is
* @c StorageManagerIF::INVALID_ADDRESS if
* the packet is not linked.
*/
store_address_t getStoreAddress();
/**
* With this call, the packet is deleted.
* It removes itself from the store and sets its data pointer to NULL.
*/
void deletePacket();
/**
* With this call, a packet can be linked to another store. This is useful
* if the packet is a class member and used for more than one packet.
* @param setAddress The new packet id to link to.
*/
void setStoreAddress(store_address_t setAddress);
ReturnValue_t sendPacket(MessageQueueId_t destination, MessageQueueId_t sentFrom,
bool doErrorReporting = true);
protected:
/**
* This is a pointer to the store all instances of the class use.
* If the store is not yet set (i.e. @c store is NULL), every constructor
* call tries to set it and throws an error message in case of failures.
* The default store is objects::TM_STORE.
*/
static StorageManagerIF* store;
static InternalErrorReporterIF *internalErrorReporter;
/**
* The address where the packet data of the object instance is stored.
*/
store_address_t storeAddress;
/**
* A helper method to check if a store is assigned to the class.
* If not, the method tries to retrieve the store from the global
* ObjectManager.
* @return @li @c true if the store is linked or could be created.
* @li @c false otherwise.
*/
bool checkAndSetStore();
void checkAndReportLostTm();
};
#endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTOREDBASE_H_ */

View File

@ -0,0 +1,79 @@
#include "TmPacketStoredPusA.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../tmtcservices/TmTcMessage.h"
#include <cstring>
TmPacketStoredPusA::TmPacketStoredPusA(store_address_t setAddress) :
TmPacketStoredBase(setAddress), TmPacketPusA(nullptr){
}
TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service,
uint8_t subservice, uint8_t packetSubcounter, const uint8_t *data,
uint32_t size, const uint8_t *headerData, uint32_t headerSize) :
TmPacketPusA(nullptr) {
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
if (not TmPacketStoredBase::checkAndSetStore()) {
return;
}
uint8_t *pData = nullptr;
ReturnValue_t returnValue = store->getFreeElement(&storeAddress,
(getPacketMinimumSize() + size + headerSize), &pData);
if (returnValue != store->RETURN_OK) {
TmPacketStoredBase::checkAndReportLostTm();
return;
}
setData(pData);
initializeTmPacket(apid, service, subservice, packetSubcounter);
memcpy(getSourceData(), headerData, headerSize);
memcpy(getSourceData() + headerSize, data, size);
setPacketDataLength(
size + headerSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1);
}
TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service,
uint8_t subservice, uint8_t packetSubcounter, SerializeIF *content,
SerializeIF *header) :
TmPacketPusA(nullptr) {
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
if (not TmPacketStoredBase::checkAndSetStore()) {
return;
}
size_t sourceDataSize = 0;
if (content != NULL) {
sourceDataSize += content->getSerializedSize();
}
if (header != NULL) {
sourceDataSize += header->getSerializedSize();
}
uint8_t *p_data = NULL;
ReturnValue_t returnValue = store->getFreeElement(&storeAddress,
(getPacketMinimumSize() + sourceDataSize), &p_data);
if (returnValue != store->RETURN_OK) {
TmPacketStoredBase::checkAndReportLostTm();
}
setData(p_data);
initializeTmPacket(apid, service, subservice, packetSubcounter);
uint8_t *putDataHere = getSourceData();
size_t size = 0;
if (header != NULL) {
header->serialize(&putDataHere, &size, sourceDataSize,
SerializeIF::Endianness::BIG);
}
if (content != NULL) {
content->serialize(&putDataHere, &size, sourceDataSize,
SerializeIF::Endianness::BIG);
}
setPacketDataLength(
sourceDataSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1);
}
uint8_t* TmPacketStoredPusA::getAllTmData() {
return getWholeData();
}
void TmPacketStoredPusA::setDataPointer(const uint8_t *newPointer) {
setData(newPointer);
}

View File

@ -0,0 +1,65 @@
#ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTORED_PUSA_H_
#define FSFW_TMTCPACKET_PUS_TMPACKETSTORED_PUSA_H_
#include "TmPacketStoredBase.h"
#include "TmPacketPusA.h"
#include <FSFWConfig.h>
/**
* This class generates a ECSS PUS A Telemetry packet within a given
* intermediate storage.
* As most packets are passed between tasks with the help of a storage
* anyway, it seems logical to create a Packet-In-Storage access class
* which saves the user almost all storage handling operation.
* Packets can both be newly created with the class and be "linked" to
* packets in a store with the help of a storeAddress.
* @ingroup tmtcpackets
*/
class TmPacketStoredPusA :
public TmPacketStoredBase,
public TmPacketPusA {
public:
/**
* This is a default constructor which does not set the data pointer.
* However, it does try to set the packet store.
*/
TmPacketStoredPusA( store_address_t setAddress );
/**
* With this constructor, new space is allocated in the packet store and
* a new PUS Telemetry Packet is created there.
* Packet Application Data passed in data is copied into the packet.
* The Application data is passed in two parts, first a header, then a
* data field. This allows building a Telemetry Packet from two separate
* data sources.
* @param apid Sets the packet's APID field.
* @param service Sets the packet's Service ID field.
* This specifies the source service.
* @param subservice Sets the packet's Service Subtype field.
* This specifies the source sub-service.
* @param packet_counter Sets the Packet counter field of this packet
* @param data The payload data to be copied to the
* Application Data Field
* @param size The amount of data to be copied.
* @param headerData The header Data of the Application field,
* will be copied in front of data
* @param headerSize The size of the headerDataF
*/
TmPacketStoredPusA( uint16_t apid, uint8_t service, uint8_t subservice,
uint8_t packet_counter = 0, const uint8_t* data = nullptr,
uint32_t size = 0, const uint8_t* headerData = nullptr,
uint32_t headerSize = 0);
/**
* Another ctor to directly pass structured content and header data to the
* packet to avoid additional buffers.
*/
TmPacketStoredPusA( uint16_t apid, uint8_t service, uint8_t subservice,
uint8_t packet_counter, SerializeIF* content,
SerializeIF* header = nullptr);
uint8_t* getAllTmData() override;
void setDataPointer(const uint8_t* newPointer) override;
};
#endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTORED_PUSA_H_ */

View File

@ -0,0 +1,80 @@
#include "TmPacketStoredPusC.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../tmtcservices/TmTcMessage.h"
#include <cstring>
TmPacketStoredPusC::TmPacketStoredPusC(store_address_t setAddress) :
TmPacketStoredBase(setAddress), TmPacketPusC(nullptr){
}
TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service,
uint8_t subservice, uint16_t packetSubcounter, const uint8_t *data,
uint32_t size, const uint8_t *headerData, uint32_t headerSize, uint16_t destinationId,
uint8_t timeRefField) :
TmPacketPusC(nullptr) {
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
if (not TmPacketStoredBase::checkAndSetStore()) {
return;
}
uint8_t *pData = nullptr;
ReturnValue_t returnValue = store->getFreeElement(&storeAddress,
(getPacketMinimumSize() + size + headerSize), &pData);
if (returnValue != store->RETURN_OK) {
TmPacketStoredBase::checkAndReportLostTm();
return;
}
setData(pData);
initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField);
memcpy(getSourceData(), headerData, headerSize);
memcpy(getSourceData() + headerSize, data, size);
setPacketDataLength(
size + headerSize + sizeof(PUSTmDataFieldHeaderPusC) + CRC_SIZE - 1);
}
TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service,
uint8_t subservice, uint16_t packetSubcounter, SerializeIF *content,
SerializeIF *header, uint16_t destinationId, uint8_t timeRefField) :
TmPacketPusC(nullptr) {
storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
if (not TmPacketStoredBase::checkAndSetStore()) {
return;
}
size_t sourceDataSize = 0;
if (content != NULL) {
sourceDataSize += content->getSerializedSize();
}
if (header != NULL) {
sourceDataSize += header->getSerializedSize();
}
uint8_t *p_data = NULL;
ReturnValue_t returnValue = store->getFreeElement(&storeAddress,
(getPacketMinimumSize() + sourceDataSize), &p_data);
if (returnValue != store->RETURN_OK) {
TmPacketStoredBase::checkAndReportLostTm();
}
setData(p_data);
initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField);
uint8_t *putDataHere = getSourceData();
size_t size = 0;
if (header != NULL) {
header->serialize(&putDataHere, &size, sourceDataSize,
SerializeIF::Endianness::BIG);
}
if (content != NULL) {
content->serialize(&putDataHere, &size, sourceDataSize,
SerializeIF::Endianness::BIG);
}
setPacketDataLength(
sourceDataSize + sizeof(PUSTmDataFieldHeaderPusC) + CRC_SIZE - 1);
}
uint8_t* TmPacketStoredPusC::getAllTmData() {
return getWholeData();
}
void TmPacketStoredPusC::setDataPointer(const uint8_t *newPointer) {
setData(newPointer);
}

View File

@ -0,0 +1,68 @@
#ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTOREDPUSC_H_
#define FSFW_TMTCPACKET_PUS_TMPACKETSTOREDPUSC_H_
#include <fsfw/tmtcpacket/pus/TmPacketPusC.h>
#include <fsfw/tmtcpacket/pus/TmPacketStoredBase.h>
/**
* This class generates a ECSS PUS C Telemetry packet within a given
* intermediate storage.
* As most packets are passed between tasks with the help of a storage
* anyway, it seems logical to create a Packet-In-Storage access class
* which saves the user almost all storage handling operation.
* Packets can both be newly created with the class and be "linked" to
* packets in a store with the help of a storeAddress.
* @ingroup tmtcpackets
*/
class TmPacketStoredPusC:
public TmPacketStoredBase,
public TmPacketPusC {
public:
/**
* This is a default constructor which does not set the data pointer.
* However, it does try to set the packet store.
*/
TmPacketStoredPusC( store_address_t setAddress );
/**
* With this constructor, new space is allocated in the packet store and
* a new PUS Telemetry Packet is created there.
* Packet Application Data passed in data is copied into the packet.
* The Application data is passed in two parts, first a header, then a
* data field. This allows building a Telemetry Packet from two separate
* data sources.
* @param apid Sets the packet's APID field.
* @param service Sets the packet's Service ID field.
* This specifies the source service.
* @param subservice Sets the packet's Service Subtype field.
* This specifies the source sub-service.
* @param packet_counter Sets the Packet counter field of this packet
* @param data The payload data to be copied to the
* Application Data Field
* @param size The amount of data to be copied.
* @param headerData The header Data of the Application field,
* will be copied in front of data
* @param headerSize The size of the headerDataF
* @param destinationId Destination ID containing the application process ID as specified
* by PUS C
* @param timeRefField 4 bit time reference field as specified by PUS C
*/
TmPacketStoredPusC( uint16_t apid, uint8_t service, uint8_t subservice,
uint16_t packetCounter = 0, const uint8_t* data = nullptr,
uint32_t size = 0, const uint8_t* headerData = nullptr,
uint32_t headerSize = 0, uint16_t destinationId = 0, uint8_t timeRefField = 0);
/**
* Another ctor to directly pass structured content and header data to the
* packet to avoid additional buffers.
*/
TmPacketStoredPusC( uint16_t apid, uint8_t service, uint8_t subservice,
uint16_t packetCounter, SerializeIF* content,
SerializeIF* header = nullptr, uint16_t destinationId = 0, uint8_t timeRefField = 0);
uint8_t* getAllTmData() override;
void setDataPointer(const uint8_t* newPointer) override;
};
#endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTOREDPUSC_H_ */

View File

@ -1,6 +1,7 @@
#include "AcceptsTelemetryIF.h" #include "AcceptsTelemetryIF.h"
#include "CommandingServiceBase.h" #include "CommandingServiceBase.h"
#include "TmTcMessage.h" #include "TmTcMessage.h"
#include <FSFWConfig.h>
#include "../tcdistribution/PUSDistributorIF.h" #include "../tcdistribution/PUSDistributorIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
@ -293,8 +294,13 @@ void CommandingServiceBase::handleRequestQueue() {
ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
const uint8_t* data, size_t dataLen, const uint8_t* headerData, const uint8_t* data, size_t dataLen, const uint8_t* headerData,
size_t headerSize) { size_t headerSize) {
TmPacketStored tmPacketStored(this->apid, this->service, subservice, #if FSFW_USE_PUS_C_TELEMETRY == 0
TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, data, dataLen, headerData, headerSize); this->tmPacketCounter, data, dataLen, headerData, headerSize);
#else
TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, data, dataLen, headerData, headerSize);
#endif
ReturnValue_t result = tmPacketStored.sendPacket( ReturnValue_t result = tmPacketStored.sendPacket(
requestQueue->getDefaultDestination(), requestQueue->getId()); requestQueue->getDefaultDestination(), requestQueue->getId());
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
@ -311,8 +317,13 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
size_t size = 0; size_t size = 0;
SerializeAdapter::serialize(&objectId, &pBuffer, &size, SerializeAdapter::serialize(&objectId, &pBuffer, &size,
sizeof(object_id_t), SerializeIF::Endianness::BIG); sizeof(object_id_t), SerializeIF::Endianness::BIG);
TmPacketStored tmPacketStored(this->apid, this->service, subservice, #if FSFW_USE_PUS_C_TELEMETRY == 0
TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, data, dataLen, buffer, size); this->tmPacketCounter, data, dataLen, buffer, size);
#else
TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, data, dataLen, buffer, size);
#endif
ReturnValue_t result = tmPacketStored.sendPacket( ReturnValue_t result = tmPacketStored.sendPacket(
requestQueue->getDefaultDestination(), requestQueue->getId()); requestQueue->getDefaultDestination(), requestQueue->getId());
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
@ -324,8 +335,13 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice,
SerializeIF* content, SerializeIF* header) { SerializeIF* content, SerializeIF* header) {
TmPacketStored tmPacketStored(this->apid, this->service, subservice, #if FSFW_USE_PUS_C_TELEMETRY == 0
TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, content, header); this->tmPacketCounter, content, header);
#else
TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice,
this->tmPacketCounter, content, header);
#endif
ReturnValue_t result = tmPacketStored.sendPacket( ReturnValue_t result = tmPacketStored.sendPacket(
requestQueue->getDefaultDestination(), requestQueue->getId()); requestQueue->getDefaultDestination(), requestQueue->getId());
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {

View File

@ -183,8 +183,11 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) {
if(tmFifo->full()) { if(tmFifo->full()) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "TmTcBridge::storeDownlinkData: TM downlink max. number " sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
<< "of stored packet IDs reached! " << std::endl; "of stored packet IDs reached!" << std::endl;
#else
sif::printWarning("TmTcBridge::storeDownlinkData: TM downlink max. number "
"of stored packet IDs reached!\n");
#endif #endif
if(overwriteOld) { if(overwriteOld) {
tmFifo->retrieve(&storeId); tmFifo->retrieve(&storeId);

View File

@ -150,8 +150,7 @@ protected:
void printData(uint8_t * data, size_t dataLen); void printData(uint8_t * data, size_t dataLen);
/** /**
* This fifo can be used to store downlink data * This FIFO can be used to store downlink data which can not be sent at the moment.
* which can not be sent at the moment.
*/ */
DynamicFIFO<store_address_t>* tmFifo = nullptr; DynamicFIFO<store_address_t>* tmFifo = nullptr;
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;

View File

@ -21,7 +21,7 @@ TmTcMessage::TmTcMessage(store_address_t storeId) {
this->setStorageId(storeId); this->setStorageId(storeId);
} }
size_t TmTcMessage::getMinimumMessageSize() { size_t TmTcMessage::getMinimumMessageSize() const {
return this->HEADER_SIZE + sizeof(store_address_t); return this->HEADER_SIZE + sizeof(store_address_t);
} }

View File

@ -18,7 +18,7 @@ protected:
* @brief This call always returns the same fixed size of the message. * @brief This call always returns the same fixed size of the message.
* @return Returns HEADER_SIZE + @c sizeof(store_address_t). * @return Returns HEADER_SIZE + @c sizeof(store_address_t).
*/ */
size_t getMinimumMessageSize(); size_t getMinimumMessageSize() const override;
public: public:
/** /**
* @brief In the default constructor, only the message_size is set. * @brief In the default constructor, only the message_size is set.

View File

@ -0,0 +1,3 @@
target_sources(${TARGET_NAME} PRIVATE
PusTmTest.cpp
)

View File

@ -0,0 +1,3 @@

View File

@ -15,8 +15,8 @@ namespace objects {
PUS_DISTRIBUTOR = 11, PUS_DISTRIBUTOR = 11,
TM_FUNNEL = 12, TM_FUNNEL = 12,
UDP_BRIDGE = 15, TCPIP_BRIDGE = 15,
UDP_POLLING_TASK = 16, TCPIP_HELPER = 16,
TEST_ECHO_COM_IF = 20, TEST_ECHO_COM_IF = 20,
TEST_DEVICE = 21, TEST_DEVICE = 21,

View File

@ -1,6 +1,6 @@
#include "CatchFactory.h"
#include <fsfw/datapoollocal/LocalDataPoolManager.h> #include <fsfw/datapoollocal/LocalDataPoolManager.h>
#include <fsfw/devicehandlers/DeviceHandlerBase.h> #include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include "CatchFactory.h"
#include <fsfw/events/EventManager.h> #include <fsfw/events/EventManager.h>
#include <fsfw/health/HealthTable.h> #include <fsfw/health/HealthTable.h>
@ -74,7 +74,7 @@ void Factory::setStaticFrameworkObjectIds() {
DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
TmPacketStored::timeStamperId = objects::NO_OBJECT; TmPacketBase::timeStamperId = objects::NO_OBJECT;
} }