Compare commits
377 Commits
42720e6f7d
...
ASTP_1.1.0
Author | SHA1 | Date | |
---|---|---|---|
b00bfe4bda | |||
2b2899e100 | |||
b52644dd2a | |||
1015cdbe88 | |||
cae69d5400 | |||
47af5260a2 | |||
1e380fe562 | |||
bd7c13ff7e
|
|||
2684e82c7f | |||
66d1d14ae3 | |||
5f9a6bb155 | |||
8a5a3c0243 | |||
2ccc0dbb00
|
|||
cfbdb10a55 | |||
ee89a2f00d
|
|||
dbfcf8b271 | |||
717971f69c
|
|||
b0a69d4c9d | |||
ecb03b8a6d
|
|||
b1f6252e30 | |||
05edb7a00c | |||
0cde65f5a1
|
|||
fbbc640f4d | |||
03e1a3e945 | |||
cc5c8ca698 | |||
996fbf134e | |||
1c7c532ef6 | |||
41e3a6b54b | |||
aa1bfcbb96 | |||
0f484abcaa | |||
c371cf4851 | |||
ad191409f4 | |||
398250c959 | |||
4b248740f3 | |||
21d213f35f | |||
105a498b93 | |||
0a0c5592f3 | |||
aa33ff2f48 | |||
3076c423c0 | |||
5f27fe6392 | |||
af99303eac | |||
1d2dabb4b4 | |||
eead2a8a49
|
|||
a7068acca7 | |||
99b007f37e | |||
7cf4aa0d5a | |||
b1e3a1b2b5 | |||
56d2af9d25 | |||
dadba69272 | |||
40a8c9a495 | |||
8dc66784a8 | |||
d0f37b851b | |||
1b6759020a | |||
537a30a4de | |||
a993872884 | |||
d700fb551c | |||
73bae057bd | |||
589e64fc46 | |||
1630682548 | |||
4b095eea89 | |||
fb7b059137 | |||
bc151983b5 | |||
40b2979ce8 | |||
7030d3e108 | |||
41cb8cb8ae | |||
75adf52d28 | |||
0157681471 | |||
b6b144bcdb | |||
145dd33fb1 | |||
50fac22f54 | |||
8b83541264 | |||
57699cccb7 | |||
33e7c635c5 | |||
070c3f3bbf | |||
3891014340 | |||
c3be4cdee6 | |||
6b9747ee0b | |||
ad820fbe99 | |||
722a7b3240 | |||
442b9370ae | |||
54e60f4ddc | |||
e961f3f038 | |||
c9836abf03 | |||
404c3821e6 | |||
567699954c | |||
43d4953e4a | |||
e6059812b5 | |||
f0a7b1cad2 | |||
e46615e830 | |||
e7ac2c7009 | |||
95c6a24437 | |||
237ba8112b | |||
aab3fd828b | |||
46cfe7452a | |||
e6868464bf | |||
e15f03fb0a | |||
59e7f0caae | |||
a2deac3441 | |||
5eadcaf10d | |||
2bf5a972e1 | |||
5d2c62e75d | |||
5ac68f731e | |||
7fa0443725 | |||
f4cb63c53c | |||
0cde6f317d | |||
2737bc390c | |||
07ba05b209 | |||
f3d9fb645e | |||
e9adaf672f | |||
fc4e65b2fc | |||
36030ef87c | |||
b7060a9c78 | |||
e147d5a4f5 | |||
a8c0d96c39 | |||
ed27d388d5 | |||
e2ae9756f3 | |||
c07672f9b4 | |||
6db2efc20d | |||
94062c67d3 | |||
9e0146f579 | |||
d3423b30b0 | |||
58a532fc4d | |||
ac027e3ff2 | |||
ff6b4134a5 | |||
5847081a24 | |||
0bc124fd21 | |||
1e9c789287 | |||
b06113993c | |||
4fa56a2f1d | |||
a320e3e1ef | |||
4095be449a | |||
d20f0c5da1 | |||
9496ed42e2 | |||
14027e449c | |||
1626b266d7 | |||
d27f49c968 | |||
a6dd2d5dcb | |||
8293e6b0c7 | |||
d81c6f40fb | |||
5b23b928cf | |||
cd016c8281 | |||
e1c91f82b7 | |||
9d0155d9ae
|
|||
d807998f4d | |||
8b17c40aa6 | |||
d7d24bd9aa | |||
c1d30aad13 | |||
126def219b | |||
08b9e92d25 | |||
86431c854b | |||
f3530d3c7e | |||
0a76c5b0b5 | |||
6ede3f9ba2 | |||
097244bf8b | |||
5c9b1769c1 | |||
2f511523cb | |||
9f83739771 | |||
054de9781b | |||
20e7fe6cb1 | |||
f8cd8e1e7d | |||
818634755d | |||
413ff0d1b9 | |||
87fee9bd0e | |||
5273ffa721 | |||
e7c00b5633 | |||
f2ab07c782 | |||
ff33a1274d | |||
e7cfd324ae | |||
52b549b97c | |||
cac9a0eecd | |||
56d43f5b49 | |||
10e7e42388 | |||
fc34e7fd75 | |||
18a9729c75 | |||
763347f203 | |||
1ff52e43a0 | |||
6a40b8244d | |||
7f1cbaef23 | |||
3356ccc9d4 | |||
4fd443f70b | |||
06631d06a5
|
|||
9244a96e7b | |||
03ef63302b
|
|||
3f91803422 | |||
5759c2cbe6 | |||
c50796b785 | |||
a0caa92a8a | |||
a91139be76 | |||
fee2ac0eb9 | |||
2878f21c93 | |||
4caf906d96 | |||
b38e9ede0c | |||
17b3672330 | |||
629814bc9b
|
|||
4fb792447e
|
|||
40dae8c961 | |||
9e1f3ee585 | |||
e851d8a46c | |||
0038c1dc53 | |||
1a3bb5bada | |||
e45b8bc739 | |||
dcd72d421e | |||
cc8c3aef3d | |||
0055d34d9a | |||
a2ba3181b9 | |||
864621ee37 | |||
54ff8f9341 | |||
e4efc01e34 | |||
c455fc1417 | |||
d792679d49 | |||
9352e15405 | |||
38a5e7e618 | |||
1cceda8e63 | |||
0c342ad7fc | |||
524e50a6dd | |||
8c4381eca6 | |||
29a05eb113 | |||
17adb2cc3e | |||
534b4850df | |||
7b29583f8f | |||
a66fc53396 | |||
5471030c32 | |||
1af7870b15 | |||
1cbeb54b8d | |||
0ec83afa13 | |||
153c44601b
|
|||
e6a8371d4a | |||
64efb8ec7f | |||
c8b2b3a038 | |||
6873d2b847 | |||
91c3692f6d | |||
69788e1279 | |||
ec69076652 | |||
a62bda97a0 | |||
32f0131973 | |||
9784d5123b | |||
ea8d887a6b | |||
29cebab790 | |||
03095776f1
|
|||
bad9f67c39 | |||
98add88d14 | |||
e1b595d620 | |||
770356f8b6 | |||
62e409a9f2 | |||
39940823d1 | |||
4479a2628d | |||
b09119cd8d | |||
10bc568560 | |||
6e09e29ec2 | |||
43fb05ac5d | |||
e832487081 | |||
01acbaa270 | |||
cf8a9996a7 | |||
a8b5fec725 | |||
fc7e401ddc | |||
ed186b04df | |||
f906605097 | |||
9a2fbefc9f | |||
07f1216316 | |||
4faa5b0685 | |||
ae1dab1fce | |||
9a5f717169 | |||
d7d52439d7 | |||
321de4e46b | |||
2635ec3d56 | |||
3f7915fe49 | |||
f87a10891a | |||
f4ac5c3844 | |||
922f145ffa | |||
9731127eaf | |||
5124f314f4 | |||
4bb078c451 | |||
547538fbc5 | |||
06d34efa74 | |||
b786b53c35 | |||
e50d0738ab | |||
01d0bd6c64 | |||
5676969fe3 | |||
5d93cf12f7 | |||
438049bb80 | |||
6e6fb62b3c | |||
7b8928ef47 | |||
924ea420a9 | |||
fbe860c6a5 | |||
8b266aa542 | |||
5144cbd789 | |||
720ce59680 | |||
f1ffa88e07 | |||
d4b26825af | |||
7e249db15e | |||
83e7dbb1f0 | |||
2e417c787d | |||
316310e993 | |||
6db0725aa4 | |||
e0d39b1feb | |||
d9a0a4f2ea | |||
b8c7a65709 | |||
d3c3a9147a | |||
40cc3c383b | |||
d92a20a669 | |||
c1f4ae08fb | |||
2b84ab018c | |||
9e881b6a16 | |||
905d525aa2 | |||
e6a1a7cc2d | |||
dd367bf083 | |||
8f4ab6d7ed | |||
b30a3aaa38 | |||
efb7c8760a | |||
bddd8720b2 | |||
00d9a4f3ed | |||
f988271be4 | |||
38d929c2a8 | |||
b4594e6f43 | |||
6e12f08965 | |||
2dd2d8f133 | |||
10c3483fe5 | |||
e799e45198 | |||
23e3f2f34f | |||
9ee1bd15c4 | |||
cbeb78f089 | |||
6983ddc3e0 | |||
80aab5f461 | |||
43ddb44573 | |||
9f8a345e35 | |||
3ff5484415 | |||
7322a7d0f5 | |||
0e76333d33 | |||
c234da6f07 | |||
8930be9f32 | |||
32996338a0 | |||
2736ebbd19 | |||
dea2205908 | |||
d1a256cbf6 | |||
509945c323 | |||
435c6e6410 | |||
3429918f5e | |||
f2da31239c | |||
3a75be2683 | |||
aa9d7b2226 | |||
eea482b438 | |||
3a90578780 | |||
1d818294e4 | |||
581832e4f4 | |||
9e559658a7 | |||
b1c532078e | |||
37ac579f51 | |||
aaceac81af | |||
d781c6fcec | |||
bdd9889718 | |||
a5f44b8580 | |||
d1265a55b4 | |||
b542ed5c03 | |||
8b42132cbe | |||
b1670decf7 | |||
1d3d2be853 | |||
d4ab2c6cdb | |||
1c021651d7 | |||
3175883346 | |||
4d403b40c9 | |||
f6afa36b1c | |||
0c77ce4dcf | |||
4c11b2f660 | |||
614d1ccb7c | |||
e3c44fd27f | |||
078116c7be | |||
b5a14bb9df | |||
86577f4b80 | |||
d625642abc | |||
951eb40e96 | |||
538dec7062 | |||
8f17d6623a | |||
0585ef9051 | |||
0da95b75a2 | |||
32b289cbec | |||
a4ca61d834 | |||
b41eb518e7 |
13
CHANGELOG
13
CHANGELOG
@@ -1,3 +1,16 @@
|
||||
## Changes from ASTP 1.0.0 to 1.1.0
|
||||
|
||||
### PUS
|
||||
|
||||
- Added PUS C support
|
||||
|
||||
### Configuration
|
||||
|
||||
- Additional configuration option fsfwconfig::FSFW_MAX_TM_PACKET_SIZE which
|
||||
need to be specified in FSFWConfig.h
|
||||
|
||||
|
||||
|
||||
## Changes from ASTP 0.0.1 to 1.0.0
|
||||
|
||||
### Host OSAL
|
||||
|
@@ -1,5 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
option(FSFW_GENERATE_SECTIONS
|
||||
"Generate function and data sections. Required to remove unused code" ON
|
||||
)
|
||||
|
||||
if(FSFW_GENERATE_SECTIONS)
|
||||
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
||||
endif()
|
||||
|
||||
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
||||
# Options to exclude parts of the FSFW from compilation.
|
||||
option(FSFW_USE_RMAP "Compile with RMAP" ON)
|
||||
@@ -10,6 +18,13 @@ add_library(${LIB_FSFW_NAME})
|
||||
|
||||
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)
|
||||
message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS")
|
||||
# Assume host OS and autodetermine from OS_FSFW
|
||||
@@ -26,15 +41,22 @@ if(NOT OS_FSFW)
|
||||
|
||||
endif()
|
||||
|
||||
set(FSFW_OSAL_DEFINITION FSFW_HOST)
|
||||
|
||||
if(${OS_FSFW} STREQUAL host)
|
||||
set(OS_FSFW_NAME "Host")
|
||||
elseif(${OS_FSFW} STREQUAL linux)
|
||||
set(OS_FSFW_NAME "Linux")
|
||||
set(FSFW_OSAL_DEFINITION FSFW_LINUX)
|
||||
elseif(${OS_FSFW} STREQUAL freertos)
|
||||
set(OS_FSFW_NAME "FreeRTOS")
|
||||
target_link_libraries(${LIB_FSFW_NAME} ${LIB_OS_NAME})
|
||||
set(FSFW_OSAL_DEFINITION FSFW_FREERTOS)
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||
${LIB_OS_NAME}
|
||||
)
|
||||
elseif(${OS_FSFW} STREQUAL rtems)
|
||||
set(OS_FSFW_NAME "RTEMS")
|
||||
set(FSFW_OSAL_DEFINITION FSFW_RTEMS)
|
||||
else()
|
||||
message(WARNING
|
||||
"Invalid operating system for FSFW specified! Setting to host.."
|
||||
@@ -43,6 +65,14 @@ else()
|
||||
set(OS_FSFW "host")
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${LIB_FSFW_NAME} PRIVATE
|
||||
${FSFW_OSAL_DEFINITION}
|
||||
)
|
||||
|
||||
target_compile_definitions(${LIB_FSFW_NAME} INTERFACE
|
||||
${FSFW_OSAL_DEFINITION}
|
||||
)
|
||||
|
||||
message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.")
|
||||
|
||||
add_subdirectory(action)
|
||||
@@ -88,6 +118,7 @@ add_subdirectory(timemanager)
|
||||
add_subdirectory(tmstorage)
|
||||
add_subdirectory(tmtcpacket)
|
||||
add_subdirectory(tmtcservices)
|
||||
add_subdirectory(unittest)
|
||||
|
||||
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
|
||||
# If this is not given, we include the default configuration and emit a warning.
|
||||
@@ -107,6 +138,21 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATHS})
|
||||
if(IS_ABSOLUTE ${INCLUDE_PATH})
|
||||
set(CURR_ABS_INC_PATH "${INCLUDE_PATH}")
|
||||
else()
|
||||
get_filename_component(CURR_ABS_INC_PATH
|
||||
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERBOSE)
|
||||
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
|
||||
endif()
|
||||
|
||||
list(APPEND FSFW_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
|
||||
endforeach()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if(NOT DEFINED FSFW_WARNING_FLAGS)
|
||||
set(FSFW_WARNING_FLAGS
|
||||
@@ -117,7 +163,20 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
-Wno-psabi
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
if(FSFW_GENERATE_SECTIONS)
|
||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
||||
"-ffunction-sections"
|
||||
"-fdata-sections"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(FSFW_REMOVE_UNUSED_CODE)
|
||||
target_link_options(${LIB_FSFW_NAME} PRIVATE
|
||||
"Wl,--gc-sections"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
|
||||
list(APPEND WARNING_FLAGS "-Wshadow=local")
|
||||
endif()
|
||||
@@ -132,6 +191,7 @@ endif()
|
||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${FSFW_CONFIG_PATH_ABSOLUTE}
|
||||
${FSFW_ADD_INC_PATHS_ABS}
|
||||
)
|
||||
|
||||
# Includes path required to compile FSFW itself as well
|
||||
@@ -140,9 +200,14 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${FSFW_CONFIG_PATH_ABSOLUTE}
|
||||
${FSFW_ADD_INC_PATHS_ABS}
|
||||
)
|
||||
|
||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
||||
${FSFW_WARNING_FLAGS}
|
||||
${COMPILER_FLAGS}
|
||||
)
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||
${FSFW_ADDITIONAL_LINK_LIBS}
|
||||
)
|
7
FSFW.h
Normal file
7
FSFW.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef FSFW_FSFW_H_
|
||||
#define FSFW_FSFW_H_
|
||||
|
||||
#include "FSFWConfig.h"
|
||||
|
||||
|
||||
#endif /* FSFW_FSFW_H_ */
|
@@ -3,9 +3,9 @@
|
||||
|
||||
const char* const FSFW_VERSION_NAME = "ASTP";
|
||||
|
||||
#define FSFW_VERSION 0
|
||||
#define FSFW_SUBVERSION 0
|
||||
#define FSFW_REVISION 1
|
||||
#define FSFW_VERSION 1
|
||||
#define FSFW_SUBVERSION 0
|
||||
#define FSFW_REVISION 0
|
||||
|
||||
|
||||
|
||||
|
11
README.md
11
README.md
@@ -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>
|
||||
[2. Core components](doc/README-core.md#top) <br>
|
||||
[3. OSAL overview](doc/README-osal.md#top) <br>
|
||||
[4. PUS services](doc/README-pus.md#top) <br>
|
||||
[5. Device Handler overview](doc/README-devicehandlers.md#top) <br>
|
||||
[6. Controller overview](doc/README-controllers.md#top) <br>
|
||||
[7. Local Data Pools](doc/README-localpools.md#top) <br>
|
||||
[3. Configuration](doc/README-config.md#top) <br>
|
||||
[4. OSAL overview](doc/README-osal.md#top) <br>
|
||||
[5. PUS services](doc/README-pus.md#top) <br>
|
||||
[6. Device Handler overview](doc/README-devicehandlers.md#top) <br>
|
||||
[7. Controller overview](doc/README-controllers.md#top) <br>
|
||||
[8. Local Data Pools](doc/README-localpools.md#top) <br>
|
||||
|
||||
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#include "HasActionsIF.h"
|
||||
|
||||
#include "../ipc/MessageQueueSenderIF.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include "../serviceinterface/ServiceInterface.h"
|
||||
|
||||
ActionHelper::ActionHelper(HasActionsIF* setOwner,
|
||||
@@ -25,7 +25,7 @@ ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
|
||||
}
|
||||
|
||||
ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
|
||||
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
@@ -147,11 +147,6 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
ipcStore->deleteData(storeAddress);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* We don't need to report the objectId, as we receive REQUESTED data before the completion
|
||||
success message. True aperiodic replies need to be reported with another dedicated message. */
|
||||
ActionMessage::setDataReply(&reply, replyId, storeAddress);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#include "ActionMessage.h"
|
||||
#include "HasActionsIF.h"
|
||||
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include "../storagemanager/StorageManagerIF.h"
|
||||
|
||||
ActionMessage::ActionMessage() {
|
||||
@@ -69,7 +69,7 @@ void ActionMessage::clear(CommandMessage* message) {
|
||||
switch(message->getCommand()) {
|
||||
case EXECUTE_ACTION:
|
||||
case DATA_REPLY: {
|
||||
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
||||
StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
|
||||
objects::IPC_STORE);
|
||||
if (ipcStore != NULL) {
|
||||
ipcStore->deleteData(getStoreId(message));
|
||||
|
@@ -2,7 +2,8 @@
|
||||
#include "CommandActionHelper.h"
|
||||
#include "CommandsActionsIF.h"
|
||||
#include "HasActionsIF.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
|
||||
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) :
|
||||
owner(setOwner), queueToUse(NULL), ipcStore(
|
||||
@@ -14,7 +15,7 @@ CommandActionHelper::~CommandActionHelper() {
|
||||
|
||||
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
|
||||
ActionId_t actionId, SerializeIF *data) {
|
||||
HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo);
|
||||
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == NULL) {
|
||||
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||
}
|
||||
@@ -40,7 +41,7 @@ ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
|
||||
// if (commandCount != 0) {
|
||||
// return CommandsFunctionsIF::ALREADY_COMMANDING;
|
||||
// }
|
||||
HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo);
|
||||
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == NULL) {
|
||||
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||
}
|
||||
@@ -66,7 +67,7 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId,
|
||||
}
|
||||
|
||||
ReturnValue_t CommandActionHelper::initialize() {
|
||||
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
@@ -17,6 +17,9 @@ SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
|
||||
SharedRingBuffer::~SharedRingBuffer() {
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
}
|
||||
|
||||
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
|
||||
this->fifoDepth = fifoDepth;
|
||||
|
@@ -26,6 +26,18 @@ public:
|
||||
*/
|
||||
SharedRingBuffer(object_id_t objectId, const size_t size,
|
||||
bool overwriteOld, size_t maxExcessBytes);
|
||||
/**
|
||||
* This constructor takes an external buffer with the specified size.
|
||||
* @param buffer
|
||||
* @param size
|
||||
* @param overwriteOld
|
||||
* If the ring buffer is overflowing at a write operartion, the oldest data
|
||||
* will be overwritten.
|
||||
*/
|
||||
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
|
||||
bool overwriteOld, size_t maxExcessBytes);
|
||||
|
||||
virtual~ SharedRingBuffer();
|
||||
|
||||
/**
|
||||
* @brief This function can be used to add an optional FIFO to the class
|
||||
@@ -37,16 +49,7 @@ public:
|
||||
*/
|
||||
void setToUseReceiveSizeFIFO(size_t fifoDepth);
|
||||
|
||||
/**
|
||||
* This constructor takes an external buffer with the specified size.
|
||||
* @param buffer
|
||||
* @param size
|
||||
* @param overwriteOld
|
||||
* If the ring buffer is overflowing at a write operartion, the oldest data
|
||||
* will be overwritten.
|
||||
*/
|
||||
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
|
||||
bool overwriteOld, size_t maxExcessBytes);
|
||||
|
||||
|
||||
/**
|
||||
* Unless a read-only constant value is read, all operations on the
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include "../subsystem/SubsystemBase.h"
|
||||
#include "../ipc/QueueFactory.h"
|
||||
#include "../action/HasActionsIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
|
||||
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||
size_t commandQueueDepth) :
|
||||
@@ -25,7 +26,7 @@ ReturnValue_t ControllerBase::initialize() {
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
|
||||
SubsystemBase *parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == nullptr) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
@@ -66,6 +66,10 @@ protected:
|
||||
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) 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;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -19,7 +19,8 @@ class VirtualChannelReception;
|
||||
class DataLinkLayer : public CCSDSReturnValuesIF {
|
||||
public:
|
||||
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 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
|
||||
|
@@ -1,10 +1,13 @@
|
||||
#include "MapPacketExtraction.h"
|
||||
|
||||
#include "../ipc/QueueFactory.h"
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../storagemanager/StorageManagerIF.h"
|
||||
#include "../tmtcpacket/SpacePacketBase.h"
|
||||
#include "../tmtcservices/AcceptsTelecommandsIF.h"
|
||||
#include "../tmtcservices/TmTcMessage.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
MapPacketExtraction::MapPacketExtraction(uint8_t setMapId,
|
||||
@@ -131,9 +134,9 @@ void MapPacketExtraction::clearBuffers() {
|
||||
}
|
||||
|
||||
ReturnValue_t MapPacketExtraction::initialize() {
|
||||
packetStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
||||
AcceptsTelecommandsIF* distributor = objectManager->get<
|
||||
AcceptsTelecommandsIF>(packetDestination);
|
||||
packetStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
AcceptsTelecommandsIF* distributor = ObjectManager::instance()->
|
||||
get<AcceptsTelecommandsIF>(packetDestination);
|
||||
if ((packetStore != NULL) && (distributor != NULL)) {
|
||||
tcQueueId = distributor->getRequestQueue();
|
||||
return RETURN_OK;
|
||||
|
@@ -7,7 +7,7 @@ HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) :
|
||||
}
|
||||
|
||||
HkSwitchHelper::~HkSwitchHelper() {
|
||||
// TODO Auto-generated destructor stub
|
||||
QueueFactory::instance()->deleteMessageQueue(actionQueue);
|
||||
}
|
||||
|
||||
ReturnValue_t HkSwitchHelper::initialize() {
|
||||
|
@@ -64,11 +64,11 @@ ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType,
|
||||
}
|
||||
else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "DataSet::read(): Call made in wrong position. Don't forget to commit"
|
||||
" member datasets!" << std::endl;
|
||||
sif::warning << "PoolDataSetBase::read: Call made in wrong position. Don't forget to "
|
||||
"commit member datasets!" << std::endl;
|
||||
#else
|
||||
sif::printError("DataSet::read(): Call made in wrong position. Don't forget to commit"
|
||||
" member datasets!\n");
|
||||
sif::printWarning("PoolDataSetBase::read: Call made in wrong position. Don't forget to "
|
||||
"commit member datasets!\n");
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
result = SET_WAS_ALREADY_READ;
|
||||
}
|
||||
|
@@ -34,7 +34,8 @@ class LocalPoolObjectBase;
|
||||
* can be retrieved using the object manager, provided the target object is a SystemObject.
|
||||
* For example, the following line of code can be used to retrieve the interface
|
||||
*
|
||||
* HasLocalDataPoolIF* poolIF = objectManager->get<HasLocalDataPoolIF>(objects::SOME_OBJECT);
|
||||
* HasLocalDataPoolIF* poolIF = ObjectManager::instance()->
|
||||
* get<HasLocalDataPoolIF>(objects::SOME_OBJECT);
|
||||
* if(poolIF != nullptr) {
|
||||
* doSomething()
|
||||
* }
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@
|
||||
#include "internal/HasLocalDpIFUserAttorney.h"
|
||||
|
||||
#include "../serviceinterface/ServiceInterface.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include "../globalfunctions/bitutility.h"
|
||||
#include "../datapoollocal/LocalDataPoolManager.h"
|
||||
#include "../housekeeping/PeriodicHousekeepingHelper.h"
|
||||
@@ -45,7 +46,7 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner,
|
||||
LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray,
|
||||
const size_t maxNumberOfVariables):
|
||||
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
|
||||
HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(
|
||||
HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get<HasLocalDataPoolIF>(
|
||||
sid.objectId);
|
||||
if(hkOwner != nullptr) {
|
||||
AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
|
||||
|
@@ -4,7 +4,7 @@
|
||||
#include "HasLocalDataPoolIF.h"
|
||||
#include "internal/HasLocalDpIFUserAttorney.h"
|
||||
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
|
||||
|
||||
LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner,
|
||||
@@ -43,7 +43,7 @@ LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId,
|
||||
"which is the NO_PARAMETER value!\n");
|
||||
#endif
|
||||
}
|
||||
HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(poolOwner);
|
||||
HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get<HasLocalDataPoolIF>(poolOwner);
|
||||
if(hkOwner == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "LocalPoolVariable: The supplied pool owner did not implement the correct "
|
||||
|
@@ -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
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if(NOT FSFW_CONFIG_PATH)
|
||||
set(FSFW_CONFIG_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
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()
|
||||
|
||||
# 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()
|
||||
|
@@ -7,27 +7,30 @@
|
||||
//! Used to determine whether C++ ostreams are used which can increase
|
||||
//! the binary size significantly. If this is disabled,
|
||||
//! the C stdio functions can be used alternatively
|
||||
#define FSFW_CPP_OSTREAM_ENABLED 1
|
||||
#define FSFW_CPP_OSTREAM_ENABLED 1
|
||||
|
||||
//! More FSFW related printouts depending on level. Useful for development.
|
||||
#define FSFW_VERBOSE_LEVEL 1
|
||||
#define FSFW_VERBOSE_LEVEL 1
|
||||
|
||||
//! Can be used to completely disable printouts, even the C stdio ones.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 0 && FSFW_VERBOSE_LEVEL == 0
|
||||
#define FSFW_DISABLE_PRINTOUT 0
|
||||
#define FSFW_DISABLE_PRINTOUT 0
|
||||
#endif
|
||||
|
||||
#define FSFW_USE_PUS_C_TELEMETRY 1
|
||||
#define FSFW_USE_PUS_C_TELECOMMANDS 1
|
||||
|
||||
//! Can be used to disable the ANSI color sequences for C stdio.
|
||||
#define FSFW_COLORED_OUTPUT 1
|
||||
#define FSFW_COLORED_OUTPUT 1
|
||||
|
||||
//! If FSFW_OBJ_EVENT_TRANSLATION is set to one,
|
||||
//! additional output which requires the translation files translateObjects
|
||||
//! and translateEvents (and their compiled source files)
|
||||
#define FSFW_OBJ_EVENT_TRANSLATION 0
|
||||
#define FSFW_OBJ_EVENT_TRANSLATION 0
|
||||
|
||||
#if FSFW_OBJ_EVENT_TRANSLATION == 1
|
||||
//! Specify whether info events are printed too.
|
||||
#define FSFW_DEBUG_INFO 1
|
||||
#define FSFW_DEBUG_INFO 1
|
||||
#include "objects/translateObjects.h"
|
||||
#include "events/translateEvents.h"
|
||||
#else
|
||||
@@ -35,15 +38,22 @@
|
||||
|
||||
//! When using the newlib nano library, C99 support for stdio facilities
|
||||
//! will not be provided. This define should be set to 1 if this is the case.
|
||||
#define FSFW_NO_C99_IO 1
|
||||
#define FSFW_NO_C99_IO 1
|
||||
|
||||
//! Specify whether a special mode store is used for Subsystem components.
|
||||
#define FSFW_USE_MODESTORE 0
|
||||
#define FSFW_USE_MODESTORE 0
|
||||
|
||||
//! Defines if the real time scheduler for linux should be used.
|
||||
//! If set to 0, this will also disable priority settings for linux
|
||||
//! as most systems will not allow to set nice values without privileges
|
||||
//! For embedded linux system set this to 1.
|
||||
//! If set to 1 the binary needs "cap_sys_nice=eip" privileges to run
|
||||
#define FSFW_USE_REALTIME_FOR_LINUX 1
|
||||
|
||||
namespace fsfwconfig {
|
||||
//! Default timestamp size. The default timestamp will be an eight byte CDC
|
||||
//! short timestamp.
|
||||
static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8;
|
||||
|
||||
//! Default timestamp size. The default timestamp will be an seven byte CDC short timestamp.
|
||||
static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 7;
|
||||
|
||||
//! Configure the allocated pool sizes for the event manager.
|
||||
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
|
||||
@@ -52,11 +62,14 @@ static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
|
||||
|
||||
//! Defines the FIFO depth of each commanding service base which
|
||||
//! also determines how many commands a CSB service can handle in one cycle
|
||||
//! simulataneously. This will increase the required RAM for
|
||||
//! simultaneously. This will increase the required RAM for
|
||||
//! each CSB service !
|
||||
static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6;
|
||||
|
||||
static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124;
|
||||
|
||||
static constexpr size_t FSFW_MAX_TM_PACKET_SIZE = 2048;
|
||||
|
||||
}
|
||||
|
||||
#endif /* CONFIG_FSFWCONFIG_H_ */
|
||||
|
@@ -24,6 +24,13 @@
|
||||
* 1. check logic when active-> checkChildrenStateOn
|
||||
* 2. transition logic to change the mode -> commandChildren
|
||||
*
|
||||
* Important:
|
||||
*
|
||||
* The implementation must call registerChild(object_id_t child)
|
||||
* for all commanded children during initialization.
|
||||
* The implementation must call the initialization function of the base class.
|
||||
* (This will call the function in SubsystemBase)
|
||||
*
|
||||
*/
|
||||
class AssemblyBase: public SubsystemBase {
|
||||
public:
|
||||
@@ -41,9 +48,6 @@ public:
|
||||
virtual ~AssemblyBase();
|
||||
|
||||
protected:
|
||||
|
||||
// SHOULDDO: Change that OVERWRITE_HEALTH may be returned
|
||||
// (or return internalState directly?)
|
||||
/**
|
||||
* Command children to reach [mode,submode] combination
|
||||
* Can be done by setting #commandsOutstanding correctly,
|
||||
@@ -68,6 +72,18 @@ protected:
|
||||
virtual ReturnValue_t checkChildrenStateOn(Mode_t wantedMode,
|
||||
Submode_t wantedSubmode) = 0;
|
||||
|
||||
/**
|
||||
* Check whether a combination of mode and submode is valid.
|
||||
*
|
||||
* Ground Controller like precise return values from HasModesIF.
|
||||
* So, please return any of them.
|
||||
*
|
||||
* @param mode The targeted mode
|
||||
* @param submode The targeted submmode
|
||||
* @return Any information why this combination is invalid from HasModesIF
|
||||
* like HasModesIF::INVALID_SUBMODE.
|
||||
* On success return HasReturnvaluesIF::RETURN_OK
|
||||
*/
|
||||
virtual ReturnValue_t isModeCombinationValid(Mode_t mode,
|
||||
Submode_t submode) = 0;
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#include "ChildHandlerBase.h"
|
||||
#include "../subsystem/SubsystemBase.h"
|
||||
#include "../subsystem/SubsystemBase.h"
|
||||
|
||||
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId,
|
||||
object_id_t deviceCommunication, CookieIF * cookie,
|
||||
@@ -30,7 +29,7 @@ ReturnValue_t ChildHandlerBase::initialize() {
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
|
||||
SubsystemBase *parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == NULL) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
@@ -119,7 +119,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
return result;
|
||||
}
|
||||
|
||||
communicationInterface = objectManager->get<DeviceCommunicationIF>(
|
||||
communicationInterface = ObjectManager::instance()->get<DeviceCommunicationIF>(
|
||||
deviceCommunicationId);
|
||||
if (communicationInterface == nullptr) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
|
||||
@@ -136,7 +136,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
return result;
|
||||
}
|
||||
|
||||
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
IPCStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (IPCStore == nullptr) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
|
||||
ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up");
|
||||
@@ -144,8 +144,8 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
}
|
||||
|
||||
if(rawDataReceiverId != objects::NO_OBJECT) {
|
||||
AcceptsDeviceResponsesIF *rawReceiver = objectManager->get<
|
||||
AcceptsDeviceResponsesIF>(rawDataReceiverId);
|
||||
AcceptsDeviceResponsesIF *rawReceiver = ObjectManager::instance()->
|
||||
get<AcceptsDeviceResponsesIF>(rawDataReceiverId);
|
||||
|
||||
if (rawReceiver == nullptr) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_ERROR,
|
||||
@@ -164,7 +164,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
}
|
||||
|
||||
if(powerSwitcherId != objects::NO_OBJECT) {
|
||||
powerSwitcher = objectManager->get<PowerSwitchIF>(powerSwitcherId);
|
||||
powerSwitcher = ObjectManager::instance()->get<PowerSwitchIF>(powerSwitcherId);
|
||||
if (powerSwitcher == nullptr) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_ERROR,
|
||||
"initialize", ObjectManagerIF::CHILD_INIT_FAILED,
|
||||
@@ -226,16 +226,15 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::decrementDeviceReplyMap() {
|
||||
for (std::map<DeviceCommandId_t, DeviceReplyInfo>::iterator iter =
|
||||
deviceReplyMap.begin(); iter != deviceReplyMap.end(); iter++) {
|
||||
if (iter->second.delayCycles != 0) {
|
||||
iter->second.delayCycles--;
|
||||
if (iter->second.delayCycles == 0) {
|
||||
if (iter->second.periodic) {
|
||||
iter->second.delayCycles = iter->second.maxDelayCycles;
|
||||
for (std::pair<const DeviceCommandId_t, DeviceReplyInfo>& replyPair: deviceReplyMap) {
|
||||
if (replyPair.second.delayCycles != 0) {
|
||||
replyPair.second.delayCycles--;
|
||||
if (replyPair.second.delayCycles == 0) {
|
||||
if (replyPair.second.periodic) {
|
||||
replyPair.second.delayCycles = replyPair.second.maxDelayCycles;
|
||||
}
|
||||
replyToReply(iter, TIMEOUT);
|
||||
missedReply(iter->first);
|
||||
replyToReply(replyPair.first, replyPair.second, TIMEOUT);
|
||||
missedReply(replyPair.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -308,11 +307,11 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
if (currentUptime - timeoutStart >= childTransitionDelay) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_VERBOSE_LEVEL >= 1 && FSFW_OBJ_EVENT_TRANSLATION == 0
|
||||
char printout[60];
|
||||
sprintf(printout, "Transition timeout (%lu) occured !",
|
||||
static_cast<unsigned long>(childTransitionDelay));
|
||||
/* Very common configuration error, so print it */
|
||||
/* Common configuration error for development, so print it */
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "doStateMachine",
|
||||
RETURN_FAILED, printout);
|
||||
#endif
|
||||
@@ -456,6 +455,15 @@ ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceComm
|
||||
}
|
||||
}
|
||||
|
||||
size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId){
|
||||
DeviceReplyIter iter = deviceReplyMap.find(commandId);
|
||||
if(iter != deviceReplyMap.end()) {
|
||||
return iter->second.replyLen;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply,
|
||||
uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic) {
|
||||
auto replyIter = deviceReplyMap.find(deviceReply);
|
||||
@@ -575,17 +583,28 @@ void DeviceHandlerBase::replyToCommand(ReturnValue_t status,
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter,
|
||||
void DeviceHandlerBase::replyToReply(const DeviceCommandId_t command, DeviceReplyInfo& replyInfo,
|
||||
ReturnValue_t status) {
|
||||
// No need to check if iter exists, as this is checked by callers.
|
||||
// If someone else uses the method, add check.
|
||||
if (iter->second.command == deviceCommandMap.end()) {
|
||||
if (replyInfo.command == deviceCommandMap.end()) {
|
||||
//Is most likely periodic reply. Silent return.
|
||||
return;
|
||||
}
|
||||
DeviceCommandInfo* info = &replyInfo.command->second;
|
||||
if (info == nullptr){
|
||||
printWarningOrError(sif::OutputTypes::OUT_ERROR,
|
||||
"replyToReply", HasReturnvaluesIF::RETURN_FAILED,
|
||||
"Command pointer not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->expectedReplies > 0){
|
||||
// Check before to avoid underflow
|
||||
info->expectedReplies--;
|
||||
}
|
||||
// Check if more replies are expected. If so, do nothing.
|
||||
DeviceCommandInfo* info = &(iter->second.command->second);
|
||||
if (--info->expectedReplies == 0) {
|
||||
if (info->expectedReplies == 0) {
|
||||
// Check if it was transition or internal command.
|
||||
// Don't send any replies in that case.
|
||||
if (info->sendReplyTo != NO_COMMANDER) {
|
||||
@@ -593,7 +612,7 @@ void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter,
|
||||
if(status == HasReturnvaluesIF::RETURN_OK) {
|
||||
success = true;
|
||||
}
|
||||
actionHelper.finish(success, info->sendReplyTo, iter->first, status);
|
||||
actionHelper.finish(success, info->sendReplyTo, command, status);
|
||||
}
|
||||
info->isExecuting = false;
|
||||
}
|
||||
@@ -646,16 +665,12 @@ void DeviceHandlerBase::doGetWrite() {
|
||||
void DeviceHandlerBase::doSendRead() {
|
||||
ReturnValue_t result;
|
||||
|
||||
size_t requestLen = 0;
|
||||
size_t replyLen = 0;
|
||||
if(cookieInfo.pendingCommand != deviceCommandMap.end()) {
|
||||
DeviceReplyIter iter = deviceReplyMap.find(
|
||||
cookieInfo.pendingCommand->first);
|
||||
if(iter != deviceReplyMap.end()) {
|
||||
requestLen = iter->second.replyLen;
|
||||
}
|
||||
replyLen = getNextReplyLength(cookieInfo.pendingCommand->first);
|
||||
}
|
||||
|
||||
result = communicationInterface->requestReceiveMessage(comCookie, requestLen);
|
||||
result = communicationInterface->requestReceiveMessage(comCookie, replyLen);
|
||||
|
||||
if (result == RETURN_OK) {
|
||||
cookieInfo.state = COOKIE_READ_SENT;
|
||||
@@ -796,7 +811,7 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData,
|
||||
replyRawReplyIfnotWiretapped(receivedData, foundLen);
|
||||
triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId);
|
||||
}
|
||||
replyToReply(iter, result);
|
||||
replyToReply(iter->first, iter->second, result);
|
||||
}
|
||||
else {
|
||||
/* Other completion failure messages are created by timeout.
|
||||
@@ -1491,7 +1506,7 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
|
||||
if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) {
|
||||
errorPrint = "Initialization error";
|
||||
}
|
||||
if(errorCode == HasReturnvaluesIF::RETURN_FAILED) {
|
||||
else if(errorCode == HasReturnvaluesIF::RETURN_FAILED) {
|
||||
if(errorType == sif::OutputTypes::OUT_WARNING) {
|
||||
errorPrint = "Generic Warning";
|
||||
}
|
||||
@@ -1503,6 +1518,9 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
|
||||
errorPrint = "Unknown error";
|
||||
}
|
||||
}
|
||||
if(functionName == nullptr) {
|
||||
functionName = "unknown function";
|
||||
}
|
||||
|
||||
if(errorType == sif::OutputTypes::OUT_WARNING) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@@ -1511,18 +1529,18 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
|
||||
std::dec << std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
|
||||
this->getObjectId(), errorPrint);
|
||||
functionName, this->getObjectId(), errorPrint);
|
||||
#endif
|
||||
}
|
||||
else if(errorType == sif::OutputTypes::OUT_ERROR) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "DeviceHandlerBase::" << functionName << ": Object ID "
|
||||
sif::error << "DeviceHandlerBase::" << functionName << ": Object ID 0x"
|
||||
<< std::hex << std::setw(8) << std::setfill('0')
|
||||
<< this->getObjectId() << " | " << errorPrint << std::dec
|
||||
<< std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
|
||||
this->getObjectId(), errorPrint);
|
||||
functionName, this->getObjectId(), errorPrint);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -471,13 +471,27 @@ protected:
|
||||
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand,
|
||||
uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet = nullptr,
|
||||
size_t replyLen = 0, bool periodic = false);
|
||||
|
||||
/**
|
||||
* @brief A simple command to add a command to the commandList.
|
||||
* @brief A simple command to add a command to the commandList.
|
||||
* @param deviceCommand The command to add
|
||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||
* - @c RETURN_FAILED else.
|
||||
*/
|
||||
ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand);
|
||||
|
||||
/**
|
||||
* @brief This function returns the reply length of the next reply to read.
|
||||
*
|
||||
* @param deviceCommand The command which triggered the device reply.
|
||||
*
|
||||
* @details The default implementation assumes only one reply is triggered by the command. In
|
||||
* case the command triggers multiple replies (e.g. one acknowledgment, one data,
|
||||
* and one execution status reply), this function can be overwritten to get the
|
||||
* reply length of the next reply to read.
|
||||
*/
|
||||
virtual size_t getNextReplyLength(DeviceCommandId_t deviceCommand);
|
||||
|
||||
/**
|
||||
* @brief This is a helper method to facilitate updating entries
|
||||
* in the reply map.
|
||||
@@ -653,7 +667,7 @@ protected:
|
||||
static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0);
|
||||
static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1);
|
||||
|
||||
static const MessageQueueId_t NO_COMMANDER = 0;
|
||||
static const MessageQueueId_t NO_COMMANDER = MessageQueueIF::NO_QUEUE;
|
||||
|
||||
//! Pointer to the raw packet that will be sent.
|
||||
uint8_t *rawPacket = nullptr;
|
||||
@@ -953,7 +967,7 @@ protected:
|
||||
* - NO_REPLY_EXPECTED if there was no reply found. This is not an
|
||||
* error case as many commands do not expect a reply.
|
||||
*/
|
||||
virtual ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator cmd,
|
||||
virtual ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator command,
|
||||
uint8_t expectedReplies = 1, bool useAlternateId = false,
|
||||
DeviceCommandId_t alternateReplyID = 0);
|
||||
|
||||
@@ -1181,7 +1195,8 @@ private:
|
||||
* @foundLen the length of the packet
|
||||
*/
|
||||
void handleReply(const uint8_t *data, DeviceCommandId_t id, uint32_t foundLen);
|
||||
void replyToReply(DeviceReplyMap::iterator iter, ReturnValue_t status);
|
||||
void replyToReply(const DeviceCommandId_t command, DeviceReplyInfo& replyInfo,
|
||||
ReturnValue_t status);
|
||||
|
||||
/**
|
||||
* Build and send a command to the device.
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "DeviceHandlerFailureIsolation.h"
|
||||
|
||||
#include "../devicehandlers/DeviceHandlerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include "../modes/HasModesIF.h"
|
||||
#include "../health/HealthTableIF.h"
|
||||
#include "../power/Fuse.h"
|
||||
@@ -175,7 +176,7 @@ ReturnValue_t DeviceHandlerFailureIsolation::initialize() {
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
ConfirmsFailuresIF* power = objectManager->get<ConfirmsFailuresIF>(
|
||||
ConfirmsFailuresIF* power = ObjectManager::instance()->get<ConfirmsFailuresIF>(
|
||||
powerConfirmationId);
|
||||
if (power != nullptr) {
|
||||
powerConfirmation = power->getEventReceptionQueue();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#include "DeviceHandlerMessage.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
|
||||
store_address_t DeviceHandlerMessage::getStoreAddress(
|
||||
const CommandMessage* message) {
|
||||
@@ -70,7 +70,7 @@ void DeviceHandlerMessage::clear(CommandMessage* message) {
|
||||
case REPLY_RAW_COMMAND:
|
||||
case REPLY_RAW_REPLY:
|
||||
case REPLY_DIRECT_COMMAND_DATA: {
|
||||
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
||||
StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
|
||||
objects::IPC_STORE);
|
||||
if (ipcStore != nullptr) {
|
||||
ipcStore->deleteData(getStoreAddress(message));
|
||||
|
@@ -16,9 +16,9 @@ ReturnValue_t HealthDevice::performOperation(uint8_t opCode) {
|
||||
CommandMessage command;
|
||||
ReturnValue_t result = commandQueue->receiveMessage(&command);
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
healthHelper.handleHealthCommand(&command);
|
||||
result = healthHelper.handleHealthCommand(&command);
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t HealthDevice::initialize() {
|
||||
|
@@ -1,12 +1,30 @@
|
||||
|
||||
## Configuring the FSFW
|
||||
Configuring the FSFW
|
||||
======
|
||||
|
||||
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
|
||||
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
|
||||
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_EVENTMGMR_RANGEMATCHERS = 120;
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
|
@@ -19,8 +19,9 @@ A nullptr check of the returning Pointer must be done. This function is based on
|
||||
```cpp
|
||||
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.
|
||||
By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards.
|
||||
* A typical way to create all objects on startup is a handing a static produce function to the
|
||||
ObjectManager on creation. By calling objectManager->initialize() the produce function will be
|
||||
called and all SystemObjects will be initialized afterwards.
|
||||
|
||||
### Event Manager
|
||||
|
||||
@@ -36,14 +37,19 @@ By calling objectManager->initialize() the produce function will be called and a
|
||||
|
||||
### Stores
|
||||
|
||||
* The message based communication can only exchange a few bytes of information inside the message itself. Therefore, additional information can
|
||||
be exchanged with Stores. With this, only the 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.
|
||||
* The message based communication can only exchange a few bytes of information inside the message
|
||||
itself. Therefore, additional information can be exchanged with Stores. With this, only the
|
||||
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
|
||||
|
||||
### 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.
|
||||
* 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
|
||||
* The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the
|
||||
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
|
||||
|
||||
|
@@ -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 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.
|
||||
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.
|
||||
The fsfw uses run-time type information but exceptions are not allowed.
|
||||
Dynamic Allocation after initialization is discouraged and different solutions are provided in the
|
||||
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.
|
||||
Returnvalues must be unique. For this the function HasReturnvaluesIF::makeReturnCode or the Macro MAKE_RETURN can be used.
|
||||
The CLASS_ID is a unique id for that type of object. See returnvalues/FwClassIds.
|
||||
Functions should return a defined `ReturnValue_t` to signal to the caller that something has
|
||||
gone wrong. Returnvalues must be unique. For this the function `HasReturnvaluesIF::makeReturnCode`
|
||||
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 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
|
||||
[core component section](doc/README-core.md#top):
|
||||
|
||||
1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks with fixed timeslots
|
||||
2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID 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.
|
||||
1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks
|
||||
with fixed timeslots
|
||||
2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID
|
||||
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
|
||||
4. EventManager: This module allows routing of events generated by `SystemObjects`
|
||||
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.
|
||||
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.
|
||||
Every object that needs own EventIds has to get a 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.
|
||||
Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT.
|
||||
This works analog to the returnvalues. Every object that needs own EventIds has to get a
|
||||
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.
|
||||
|
||||
### Internal Communication
|
||||
# Internal Communication
|
||||
|
||||
Components communicate mostly over Message through Queues.
|
||||
Those queues are created by calling the singleton QueueFactory::instance()->create().
|
||||
Components communicate mostly via Messages through Queues.
|
||||
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 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.
|
||||
|
||||
#### 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.
|
||||
If Space Packets are used, a timestamper must be created.
|
||||
An example can be found in the timemanager folder, this uses CCSDSTime::CDS_short.
|
||||
The FSFW provides some components to facilitate TMTC handling via the PUS commands.
|
||||
For example, a UDP or TCP PUS server socket can be opened on a specific port using the
|
||||
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.
|
||||
The idea is, to have a software counterpart of every physical device to provide a simple mode, health and commanding interface.
|
||||
By separating the underlying Communication Interface with DeviceCommunicationIF, a device handler (DH) can be tested on different hardware.
|
||||
The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction.
|
||||
Device Handlers can be created by overriding `DeviceHandlerBase`.
|
||||
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).
|
||||
The idea is, to have a software counterpart of every physical device to provide a simple mode,
|
||||
health and commanding interface. By separating the underlying Communication Interface with
|
||||
`DeviceCommunicationIF`, a device handler (DH) can be tested on different hardware.
|
||||
The DH has mechanisms to monitor the communication with the physical device which allow
|
||||
for FDIR reaction. Device Handlers can be created by implementing `DeviceHandlerBase`.
|
||||
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.
|
||||
On-board Mode Management is implement in hierarchy system.
|
||||
The two interfaces `HasModesIF` and `HasHealthIF` provide access for commanding and monitoring
|
||||
of components. On-board Mode Management is implement in hierarchy system.
|
||||
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.
|
||||
Assemblies share a common core with the next level which are the Subsystems.
|
||||
The next layer are Assemblies. Those assemblies act as a component which handle
|
||||
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.
|
||||
The definitions contain transition and target tables which contain the DH, 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.
|
||||
Those Assemblies are intended to act as auto-generated components from a database which describes
|
||||
the subsystem modes. The definitions contain transition and target tables which contain the DH,
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
|
||||
## 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)
|
||||
|
@@ -1,8 +1,6 @@
|
||||
#include "EventManager.h"
|
||||
#include "EventMessage.h"
|
||||
|
||||
#include <FSFWConfig.h>
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../ipc/QueueFactory.h"
|
||||
#include "../ipc/MutexFactory.h"
|
||||
|
||||
@@ -115,53 +113,6 @@ ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener,
|
||||
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() {
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
}
|
||||
@@ -175,3 +126,85 @@ void EventManager::setMutexTimeout(MutexIF::TimeoutType timeoutType,
|
||||
this->timeoutType = timeoutType;
|
||||
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 << " reported event with ID " << message->getEventId() << std::endl;
|
||||
sif::debug << translateEvents(message->getEvent()) << " | " <<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 << " reported event with ID " << message->getEventId() << std::endl;
|
||||
sif::debug << translateEvents(message->getEvent()) << " | " <<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 */
|
||||
|
@@ -3,9 +3,9 @@
|
||||
|
||||
#include "EventManagerIF.h"
|
||||
#include "eventmatching/EventMatchTree.h"
|
||||
#include "FSFWConfig.h"
|
||||
|
||||
#include <FSFWConfig.h>
|
||||
|
||||
#include "../serviceinterface/ServiceInterface.h"
|
||||
#include "../objectmanager/SystemObject.h"
|
||||
#include "../storagemanager/LocalPool.h"
|
||||
#include "../tasks/ExecutableObjectIF.h"
|
||||
@@ -67,6 +67,7 @@ protected:
|
||||
|
||||
#if FSFW_OBJ_EVENT_TRANSLATION == 1
|
||||
void printEvent(EventMessage *message);
|
||||
void printUtility(sif::OutputTypes printType, EventMessage* message);
|
||||
#endif
|
||||
|
||||
void lockMutex();
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "EventMessage.h"
|
||||
#include "eventmatching/eventmatching.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include "../ipc/MessageQueueSenderIF.h"
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
#include "../serviceinterface/ServiceInterface.h"
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
static void triggerEvent(EventMessage* message,
|
||||
MessageQueueId_t sentFrom = 0) {
|
||||
if (eventmanagerQueue == MessageQueueIF::NO_QUEUE) {
|
||||
EventManagerIF *eventmanager = objectManager->get<EventManagerIF>(
|
||||
EventManagerIF *eventmanager = ObjectManager::instance()->get<EventManagerIF>(
|
||||
objects::EVENT_MANAGER);
|
||||
if (eventmanager == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
|
@@ -109,6 +109,6 @@ bool EventMessage::isClearedEventMessage() {
|
||||
return getEvent() == INVALID_EVENT;
|
||||
}
|
||||
|
||||
size_t EventMessage::getMinimumMessageSize() {
|
||||
size_t EventMessage::getMinimumMessageSize() const {
|
||||
return EVENT_MESSAGE_SIZE;
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@ public:
|
||||
|
||||
protected:
|
||||
static const Event INVALID_EVENT = 0;
|
||||
virtual size_t getMinimumMessageSize();
|
||||
virtual size_t getMinimumMessageSize() const override;
|
||||
|
||||
};
|
||||
|
||||
|
@@ -1,30 +1,37 @@
|
||||
#ifndef FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
|
||||
#define FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace SUBSYSTEM_ID {
|
||||
enum {
|
||||
MEMORY = 22,
|
||||
OBSW = 26,
|
||||
CDH = 28,
|
||||
TCS_1 = 59,
|
||||
PCDU_1 = 42,
|
||||
PCDU_2 = 43,
|
||||
HEATER = 50,
|
||||
T_SENSORS = 52,
|
||||
FDIR = 70,
|
||||
FDIR_1 = 71,
|
||||
FDIR_2 = 72,
|
||||
HK = 73,
|
||||
SYSTEM_MANAGER = 74,
|
||||
SYSTEM_MANAGER_1 = 75,
|
||||
SYSTEM_1 = 79,
|
||||
PUS_SERVICE_1 = 80,
|
||||
PUS_SERVICE_9 = 89,
|
||||
PUS_SERVICE_17 = 97,
|
||||
FW_SUBSYSTEM_ID_RANGE
|
||||
enum: uint8_t {
|
||||
MEMORY = 22,
|
||||
OBSW = 26,
|
||||
CDH = 28,
|
||||
TCS_1 = 59,
|
||||
PCDU_1 = 42,
|
||||
PCDU_2 = 43,
|
||||
HEATER = 50,
|
||||
T_SENSORS = 52,
|
||||
FDIR = 70,
|
||||
FDIR_1 = 71,
|
||||
FDIR_2 = 72,
|
||||
HK = 73,
|
||||
SYSTEM_MANAGER = 74,
|
||||
SYSTEM_MANAGER_1 = 75,
|
||||
SYSTEM_1 = 79,
|
||||
PUS_SERVICE_1 = 80,
|
||||
PUS_SERVICE_2 = 82,
|
||||
PUS_SERVICE_3 = 83,
|
||||
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_ */
|
||||
|
@@ -3,7 +3,7 @@
|
||||
#include "../health/HasHealthIF.h"
|
||||
#include "../health/HealthMessage.h"
|
||||
#include "../ipc/QueueFactory.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
|
||||
FailureIsolationBase::FailureIsolationBase(object_id_t owner,
|
||||
object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) :
|
||||
@@ -18,7 +18,7 @@ FailureIsolationBase::~FailureIsolationBase() {
|
||||
}
|
||||
|
||||
ReturnValue_t FailureIsolationBase::initialize() {
|
||||
EventManagerIF* manager = objectManager->get<EventManagerIF>(
|
||||
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(
|
||||
objects::EVENT_MANAGER);
|
||||
if (manager == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@@ -36,7 +36,7 @@ ReturnValue_t FailureIsolationBase::initialize() {
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
owner = objectManager->get<HasHealthIF>(ownerId);
|
||||
owner = ObjectManager::instance()->get<HasHealthIF>(ownerId);
|
||||
if (owner == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FailureIsolationBase::intialize: Owner object "
|
||||
@@ -46,7 +46,7 @@ ReturnValue_t FailureIsolationBase::initialize() {
|
||||
}
|
||||
}
|
||||
if (faultTreeParent != objects::NO_OBJECT) {
|
||||
ConfirmsFailuresIF* parentIF = objectManager->get<ConfirmsFailuresIF>(
|
||||
ConfirmsFailuresIF* parentIF = ObjectManager::instance()->get<ConfirmsFailuresIF>(
|
||||
faultTreeParent);
|
||||
if (parentIF == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
|
@@ -60,7 +60,7 @@ void arrayprinter::printHex(const uint8_t *data, size_t size,
|
||||
#else
|
||||
// General format: 0x01, 0x02, 0x03 so it is number of chars times 6
|
||||
// plus line break plus small safety margin.
|
||||
char printBuffer[(size + 1) * 7 + 1];
|
||||
char printBuffer[(size + 1) * 7 + 1] = {};
|
||||
size_t currentPos = 0;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
// To avoid buffer overflows.
|
||||
@@ -103,7 +103,7 @@ void arrayprinter::printDec(const uint8_t *data, size_t size,
|
||||
#else
|
||||
// General format: 32, 243, -12 so it is number of chars times 5
|
||||
// plus line break plus small safety margin.
|
||||
char printBuffer[(size + 1) * 5 + 1];
|
||||
char printBuffer[(size + 1) * 5 + 1] = {};
|
||||
size_t currentPos = 0;
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
// To avoid buffer overflows.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#include "HealthHelper.h"
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../serviceinterface/ServiceInterface.h"
|
||||
|
||||
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) :
|
||||
objectId(objectId), owner(owner) {
|
||||
@@ -37,8 +37,8 @@ void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) {
|
||||
}
|
||||
|
||||
ReturnValue_t HealthHelper::initialize() {
|
||||
healthTable = objectManager->get<HealthTableIF>(objects::HEALTH_TABLE);
|
||||
eventSender = objectManager->get<EventReportingProxyIF>(objectId);
|
||||
healthTable = ObjectManager::instance()->get<HealthTableIF>(objects::HEALTH_TABLE);
|
||||
eventSender = ObjectManager::instance()->get<EventReportingProxyIF>(objectId);
|
||||
|
||||
if (healthTable == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
|
@@ -68,14 +68,30 @@ void HealthTable::printAll(uint8_t* pointer, size_t maxSize) {
|
||||
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
||||
size_t size = 0;
|
||||
uint16_t count = healthMap.size();
|
||||
SerializeAdapter::serialize(&count,
|
||||
ReturnValue_t result = SerializeAdapter::serialize(&count,
|
||||
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "HealthTable::printAll: Serialization of health table failed" << std::endl;
|
||||
#else
|
||||
sif::printWarning("HealthTable::printAll: Serialization of health table failed\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return;
|
||||
}
|
||||
for (const auto& health: healthMap) {
|
||||
SerializeAdapter::serialize(&health.first,
|
||||
result = SerializeAdapter::serialize(&health.first,
|
||||
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return;
|
||||
}
|
||||
uint8_t healthValue = health.second;
|
||||
SerializeAdapter::serialize(&healthValue, &pointer, &size,
|
||||
result = SerializeAdapter::serialize(&healthValue, &pointer, &size,
|
||||
maxSize, SerializeIF::Endianness::BIG);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +102,7 @@ ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) {
|
||||
mapIterator = healthMap.begin();
|
||||
}
|
||||
if (mapIterator == healthMap.end()) {
|
||||
result = HasReturnvaluesIF::RETURN_FAILED;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
*value = *mapIterator;
|
||||
mapIterator++;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include "HousekeepingMessage.h"
|
||||
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include <cstring>
|
||||
|
||||
HousekeepingMessage::~HousekeepingMessage() {}
|
||||
@@ -161,7 +161,7 @@ void HousekeepingMessage::clear(CommandMessage* message) {
|
||||
case(UPDATE_SNAPSHOT_VARIABLE): {
|
||||
store_address_t storeId;
|
||||
getHkDataReply(message, &storeId);
|
||||
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
||||
StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
|
||||
objects::IPC_STORE);
|
||||
if (ipcStore != nullptr) {
|
||||
ipcStore->deleteData(storeId);
|
||||
|
@@ -3,19 +3,20 @@
|
||||
#include "../ipc/QueueFactory.h"
|
||||
#include "../ipc/MutexFactory.h"
|
||||
#include "../serviceinterface/ServiceInterface.h"
|
||||
#include "../datapool/PoolReadGuard.h"
|
||||
|
||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId,
|
||||
uint32_t messageQueueDepth): SystemObject(setObjectId),
|
||||
commandQueue(QueueFactory::instance()->
|
||||
createMessageQueue(messageQueueDepth)),
|
||||
poolManager(this, commandQueue),
|
||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||
internalErrorDataset(this) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
commandQueue(QueueFactory::instance()->
|
||||
createMessageQueue(messageQueueDepth)),
|
||||
poolManager(this, commandQueue),
|
||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||
internalErrorDataset(this) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
|
||||
InternalErrorReporter::~InternalErrorReporter() {
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
}
|
||||
|
||||
void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
|
||||
@@ -23,126 +24,128 @@ void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
|
||||
}
|
||||
|
||||
ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
||||
internalErrorDataset.read(timeoutType, timeoutMs);
|
||||
CommandMessage message;
|
||||
ReturnValue_t result = commandQueue->receiveMessage(&message);
|
||||
if(result != MessageQueueIF::EMPTY) {
|
||||
poolManager.handleHousekeepingMessage(&message);
|
||||
}
|
||||
|
||||
uint32_t newQueueHits = getAndResetQueueHits();
|
||||
uint32_t newTmHits = getAndResetTmHits();
|
||||
uint32_t newStoreHits = getAndResetStoreHits();
|
||||
uint32_t newQueueHits = getAndResetQueueHits();
|
||||
uint32_t newTmHits = getAndResetTmHits();
|
||||
uint32_t newStoreHits = getAndResetStoreHits();
|
||||
|
||||
#if FSFW_VERBOSE_LEVEL == 1
|
||||
if(diagnosticPrintout) {
|
||||
if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
if(diagnosticPrintout) {
|
||||
if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "InternalErrorReporter::performOperation: Errors "
|
||||
<< "occured!" << std::endl;
|
||||
sif::debug << "Queue errors: " << newQueueHits << std::endl;
|
||||
sif::debug << "TM errors: " << newTmHits << std::endl;
|
||||
sif::debug << "Store errors: " << newStoreHits << std::endl;
|
||||
sif::debug << "InternalErrorReporter::performOperation: Errors "
|
||||
<< "occured!" << std::endl;
|
||||
sif::debug << "Queue errors: " << newQueueHits << std::endl;
|
||||
sif::debug << "TM errors: " << newTmHits << std::endl;
|
||||
sif::debug << "Store errors: " << newStoreHits << std::endl;
|
||||
#else
|
||||
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
|
||||
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
|
||||
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
|
||||
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
|
||||
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
|
||||
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
|
||||
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
|
||||
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internalErrorDataset.queueHits.value += newQueueHits;
|
||||
internalErrorDataset.storeHits.value += newStoreHits;
|
||||
internalErrorDataset.tmHits.value += newTmHits;
|
||||
internalErrorDataset.setValidity(true, true);
|
||||
internalErrorDataset.commit(timeoutType, timeoutMs);
|
||||
{
|
||||
PoolReadGuard readGuard(&internalErrorDataset);
|
||||
if(readGuard.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
|
||||
internalErrorDataset.queueHits.value += newQueueHits;
|
||||
internalErrorDataset.storeHits.value += newStoreHits;
|
||||
internalErrorDataset.tmHits.value += newTmHits;
|
||||
internalErrorDataset.setValidity(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
poolManager.performHkOperation();
|
||||
|
||||
CommandMessage message;
|
||||
ReturnValue_t result = commandQueue->receiveMessage(&message);
|
||||
if(result != MessageQueueIF::EMPTY) {
|
||||
poolManager.handleHousekeepingMessage(&message);
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
poolManager.performHkOperation();
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void InternalErrorReporter::queueMessageNotSent() {
|
||||
incrementQueueHits();
|
||||
incrementQueueHits();
|
||||
}
|
||||
|
||||
void InternalErrorReporter::lostTm() {
|
||||
incrementTmHits();
|
||||
incrementTmHits();
|
||||
}
|
||||
|
||||
uint32_t InternalErrorReporter::getAndResetQueueHits() {
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = queueHits;
|
||||
queueHits = 0;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = queueHits;
|
||||
queueHits = 0;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t InternalErrorReporter::getQueueHits() {
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = queueHits;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = queueHits;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
}
|
||||
|
||||
void InternalErrorReporter::incrementQueueHits() {
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
queueHits++;
|
||||
mutex->unlockMutex();
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
queueHits++;
|
||||
mutex->unlockMutex();
|
||||
}
|
||||
|
||||
uint32_t InternalErrorReporter::getAndResetTmHits() {
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = tmHits;
|
||||
tmHits = 0;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = tmHits;
|
||||
tmHits = 0;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t InternalErrorReporter::getTmHits() {
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = tmHits;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = tmHits;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
}
|
||||
|
||||
void InternalErrorReporter::incrementTmHits() {
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
tmHits++;
|
||||
mutex->unlockMutex();
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
tmHits++;
|
||||
mutex->unlockMutex();
|
||||
}
|
||||
|
||||
void InternalErrorReporter::storeFull() {
|
||||
incrementStoreHits();
|
||||
incrementStoreHits();
|
||||
}
|
||||
|
||||
uint32_t InternalErrorReporter::getAndResetStoreHits() {
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = storeHits;
|
||||
storeHits = 0;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = storeHits;
|
||||
storeHits = 0;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t InternalErrorReporter::getStoreHits() {
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = storeHits;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = storeHits;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
}
|
||||
|
||||
void InternalErrorReporter::incrementStoreHits() {
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
storeHits++;
|
||||
mutex->unlockMutex();
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
storeHits++;
|
||||
mutex->unlockMutex();
|
||||
}
|
||||
|
||||
object_id_t InternalErrorReporter::getObjectId() const {
|
||||
@@ -155,14 +158,11 @@ MessageQueueId_t InternalErrorReporter::getCommandQueue() const {
|
||||
|
||||
ReturnValue_t InternalErrorReporter::initializeLocalDataPool(
|
||||
localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
|
||||
localDataPoolMap.emplace(errorPoolIds::TM_HITS,
|
||||
new PoolEntry<uint32_t>());
|
||||
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS,
|
||||
new PoolEntry<uint32_t>());
|
||||
localDataPoolMap.emplace(errorPoolIds::STORE_HITS,
|
||||
new PoolEntry<uint32_t>());
|
||||
poolManager.subscribeForPeriodicPacket(internalErrorSid, false,
|
||||
getPeriodicOperationFrequency(), true);
|
||||
localDataPoolMap.emplace(errorPoolIds::TM_HITS, new PoolEntry<uint32_t>());
|
||||
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, new PoolEntry<uint32_t>());
|
||||
localDataPoolMap.emplace(errorPoolIds::STORE_HITS, new PoolEntry<uint32_t>());
|
||||
poolManager.subscribeForPeriodicPacket(internalErrorSid, false, getPeriodicOperationFrequency(),
|
||||
true);
|
||||
internalErrorDataset.setValidity(true, true);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
@@ -192,9 +192,9 @@ ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() {
|
||||
}
|
||||
|
||||
void InternalErrorReporter::setMutexTimeout(MutexIF::TimeoutType timeoutType,
|
||||
uint32_t timeoutMs) {
|
||||
this->timeoutType = timeoutType;
|
||||
this->timeoutMs = timeoutMs;
|
||||
uint32_t timeoutMs) {
|
||||
this->timeoutType = timeoutType;
|
||||
this->timeoutMs = timeoutMs;
|
||||
}
|
||||
|
||||
LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() {
|
||||
|
@@ -17,77 +17,78 @@
|
||||
* All functions were kept virtual so this class can be extended easily
|
||||
* to store custom internal errors (e.g. communication interface errors).
|
||||
*/
|
||||
class InternalErrorReporter: public SystemObject,
|
||||
public ExecutableObjectIF,
|
||||
public InternalErrorReporterIF,
|
||||
public HasLocalDataPoolIF {
|
||||
class InternalErrorReporter:
|
||||
public SystemObject,
|
||||
public ExecutableObjectIF,
|
||||
public InternalErrorReporterIF,
|
||||
public HasLocalDataPoolIF {
|
||||
public:
|
||||
|
||||
InternalErrorReporter(object_id_t setObjectId,
|
||||
uint32_t messageQueueDepth = 5);
|
||||
InternalErrorReporter(object_id_t setObjectId,
|
||||
uint32_t messageQueueDepth = 5);
|
||||
|
||||
/**
|
||||
* Enable diagnostic printout. Please note that this feature will
|
||||
* only work if DEBUG has been supplied to the build defines.
|
||||
* @param enable
|
||||
*/
|
||||
void setDiagnosticPrintout(bool enable);
|
||||
/**
|
||||
* Enable diagnostic printout. Please note that this feature will
|
||||
* only work if DEBUG has been supplied to the build defines.
|
||||
* @param enable
|
||||
*/
|
||||
void setDiagnosticPrintout(bool enable);
|
||||
|
||||
void setMutexTimeout(MutexIF::TimeoutType timeoutType,
|
||||
uint32_t timeoutMs);
|
||||
void setMutexTimeout(MutexIF::TimeoutType timeoutType,
|
||||
uint32_t timeoutMs);
|
||||
|
||||
virtual ~InternalErrorReporter();
|
||||
virtual ~InternalErrorReporter();
|
||||
|
||||
virtual object_id_t getObjectId() const override;
|
||||
virtual MessageQueueId_t getCommandQueue() const override;
|
||||
virtual ReturnValue_t initializeLocalDataPool(
|
||||
localpool::DataPool& localDataPoolMap,
|
||||
localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) override;
|
||||
virtual dur_millis_t getPeriodicOperationFrequency() const override;
|
||||
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
|
||||
LocalDataPoolManager* getHkManagerHandle() override;
|
||||
LocalDataPoolManager* getHkManagerHandle() override;
|
||||
|
||||
virtual ReturnValue_t initialize() override;
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
virtual void queueMessageNotSent();
|
||||
virtual void queueMessageNotSent();
|
||||
|
||||
virtual void lostTm();
|
||||
virtual void lostTm();
|
||||
|
||||
virtual void storeFull();
|
||||
virtual void storeFull();
|
||||
|
||||
virtual void setTaskIF(PeriodicTaskIF* task) override;
|
||||
virtual void setTaskIF(PeriodicTaskIF* task) override;
|
||||
protected:
|
||||
MessageQueueIF* commandQueue;
|
||||
LocalDataPoolManager poolManager;
|
||||
MessageQueueIF* commandQueue;
|
||||
LocalDataPoolManager poolManager;
|
||||
|
||||
PeriodicTaskIF* executingTask = nullptr;
|
||||
PeriodicTaskIF* executingTask = nullptr;
|
||||
|
||||
MutexIF* mutex = nullptr;
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
uint32_t timeoutMs = 20;
|
||||
MutexIF* mutex = nullptr;
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
uint32_t timeoutMs = 20;
|
||||
|
||||
sid_t internalErrorSid;
|
||||
InternalErrorDataset internalErrorDataset;
|
||||
sid_t internalErrorSid;
|
||||
InternalErrorDataset internalErrorDataset;
|
||||
|
||||
bool diagnosticPrintout = true;
|
||||
bool diagnosticPrintout = true;
|
||||
|
||||
uint32_t queueHits = 0;
|
||||
uint32_t tmHits = 0;
|
||||
uint32_t storeHits = 0;
|
||||
uint32_t queueHits = 0;
|
||||
uint32_t tmHits = 0;
|
||||
uint32_t storeHits = 0;
|
||||
|
||||
uint32_t getAndResetQueueHits();
|
||||
uint32_t getQueueHits();
|
||||
void incrementQueueHits();
|
||||
uint32_t getAndResetQueueHits();
|
||||
uint32_t getQueueHits();
|
||||
void incrementQueueHits();
|
||||
|
||||
uint32_t getAndResetTmHits();
|
||||
uint32_t getTmHits();
|
||||
void incrementTmHits();
|
||||
uint32_t getAndResetTmHits();
|
||||
uint32_t getTmHits();
|
||||
void incrementTmHits();
|
||||
|
||||
uint32_t getAndResetStoreHits();
|
||||
uint32_t getStoreHits();
|
||||
void incrementStoreHits();
|
||||
uint32_t getAndResetStoreHits();
|
||||
uint32_t getStoreHits();
|
||||
void incrementStoreHits();
|
||||
|
||||
};
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include "CommandMessageCleaner.h"
|
||||
|
||||
#include "../memory/GenericFileSystemMessage.h"
|
||||
#include "../devicehandlers/DeviceHandlerMessage.h"
|
||||
#include "../health/HealthMessage.h"
|
||||
#include "../memory/MemoryMessage.h"
|
||||
@@ -42,6 +43,9 @@ void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) {
|
||||
case messagetypes::HOUSEKEEPING:
|
||||
HousekeepingMessage::clear(message);
|
||||
break;
|
||||
case messagetypes::FILE_SYSTEM_MESSAGE:
|
||||
GenericFileSystemMessage::clear(message);
|
||||
break;
|
||||
default:
|
||||
messagetypes::clearMissionMessage(message);
|
||||
break;
|
||||
|
@@ -22,12 +22,12 @@ public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF;
|
||||
//! No new messages on the queue
|
||||
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);
|
||||
//! 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);
|
||||
//! Returned if the target destination is invalid.
|
||||
static constexpr ReturnValue_t DESTINVATION_INVALID = MAKE_RETURN_CODE(4);
|
||||
//! [EXPORT] : [COMMENT] Returned if the target destination is invalid.
|
||||
static constexpr ReturnValue_t DESTINATION_INVALID = MAKE_RETURN_CODE(4);
|
||||
|
||||
virtual ~MessageQueueIF() {}
|
||||
/**
|
||||
|
@@ -86,3 +86,7 @@ size_t MessageQueueMessage::getMaximumMessageSize() const {
|
||||
return this->MAX_MESSAGE_SIZE;
|
||||
}
|
||||
|
||||
size_t MessageQueueMessage::getMaximumDataSize() const {
|
||||
return this->MAX_DATA_SIZE;
|
||||
}
|
||||
|
||||
|
@@ -139,6 +139,7 @@ public:
|
||||
virtual void setMessageSize(size_t messageSize) override;
|
||||
virtual size_t getMinimumMessageSize() const override;
|
||||
virtual size_t getMaximumMessageSize() const override;
|
||||
virtual size_t getMaximumDataSize() const override;
|
||||
|
||||
/**
|
||||
* @brief This is a debug method that prints the content.
|
||||
|
@@ -72,6 +72,7 @@ public:
|
||||
virtual void setMessageSize(size_t messageSize) = 0;
|
||||
virtual size_t getMinimumMessageSize() const = 0;
|
||||
virtual size_t getMaximumMessageSize() const = 0;
|
||||
virtual size_t getMaximumDataSize() const = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
target_sources(${LIB_FSFW_NAME}
|
||||
PRIVATE
|
||||
MemoryHelper.cpp
|
||||
MemoryMessage.cpp
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
MemoryHelper.cpp
|
||||
MemoryMessage.cpp
|
||||
GenericFileSystemMessage.cpp
|
||||
)
|
161
memory/GenericFileSystemMessage.cpp
Normal file
161
memory/GenericFileSystemMessage.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#include "GenericFileSystemMessage.h"
|
||||
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include "../storagemanager/StorageManagerIF.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();
|
||||
}
|
||||
|
||||
ReturnValue_t GenericFileSystemMessage::clear(CommandMessage* message) {
|
||||
switch(message->getCommand()) {
|
||||
case(CMD_CREATE_FILE):
|
||||
case(CMD_DELETE_FILE):
|
||||
case(CMD_CREATE_DIRECTORY):
|
||||
case(CMD_REPORT_FILE_ATTRIBUTES):
|
||||
case(REPLY_REPORT_FILE_ATTRIBUTES):
|
||||
case(CMD_LOCK_FILE):
|
||||
case(CMD_UNLOCK_FILE):
|
||||
case(CMD_COPY_FILE):
|
||||
case(REPLY_READ_FROM_FILE):
|
||||
case(CMD_READ_FROM_FILE):
|
||||
case(CMD_APPEND_TO_FILE):
|
||||
case(CMD_FINISH_APPEND_TO_FILE):
|
||||
case(REPLY_READ_FINISHED_STOP):
|
||||
case(REPLY_FINISH_APPEND): {
|
||||
store_address_t storeId = GenericFileSystemMessage::getStoreId(message);
|
||||
auto ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if(ipcStore == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return ipcStore->deleteData(storeId);
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
115
memory/GenericFileSystemMessage.h
Normal file
115
memory/GenericFileSystemMessage.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#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);
|
||||
|
||||
static ReturnValue_t clear(CommandMessage* message);
|
||||
|
||||
};
|
||||
|
||||
#endif /* MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_ */
|
@@ -2,9 +2,9 @@
|
||||
#include "MemoryMessage.h"
|
||||
|
||||
#include "../globalfunctions/CRC.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include "../serialize/EndianConverter.h"
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../serviceinterface/ServiceInterface.h"
|
||||
|
||||
MemoryHelper::MemoryHelper(HasMemoryIF* workOnThis,
|
||||
MessageQueueIF* useThisQueue):
|
||||
@@ -187,7 +187,7 @@ ReturnValue_t MemoryHelper::initialize(MessageQueueIF* queueToUse_) {
|
||||
}
|
||||
|
||||
ReturnValue_t MemoryHelper::initialize() {
|
||||
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore != nullptr) {
|
||||
return RETURN_OK;
|
||||
} else {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include "MemoryMessage.h"
|
||||
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
|
||||
uint32_t MemoryMessage::getAddress(const CommandMessage* message) {
|
||||
return message->getParameter();
|
||||
@@ -44,7 +44,7 @@ void MemoryMessage::clear(CommandMessage* message) {
|
||||
switch (message->getCommand()) {
|
||||
case CMD_MEMORY_LOAD:
|
||||
case REPLY_MEMORY_DUMP: {
|
||||
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
||||
StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
|
||||
objects::IPC_STORE);
|
||||
if (ipcStore != NULL) {
|
||||
ipcStore->deleteData(getStoreID(message));
|
||||
|
@@ -1,13 +1,8 @@
|
||||
/**
|
||||
* @file LimitViolationReporter.cpp
|
||||
* @brief This file defines the LimitViolationReporter class.
|
||||
* @date 17.07.2014
|
||||
* @author baetz
|
||||
*/
|
||||
#include "LimitViolationReporter.h"
|
||||
#include "MonitoringIF.h"
|
||||
#include "ReceivesMonitoringReportsIF.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include "../serialize/SerializeAdapter.h"
|
||||
|
||||
ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF* data) {
|
||||
@@ -16,7 +11,7 @@ ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF
|
||||
return result;
|
||||
}
|
||||
store_address_t storeId;
|
||||
uint8_t* dataTarget = NULL;
|
||||
uint8_t* dataTarget = nullptr;
|
||||
size_t maxSize = data->getSerializedSize();
|
||||
if (maxSize > MonitoringIF::VIOLATION_REPORT_MAX_SIZE) {
|
||||
return MonitoringIF::INVALID_SIZE;
|
||||
@@ -38,16 +33,16 @@ ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF
|
||||
|
||||
ReturnValue_t LimitViolationReporter::checkClassLoaded() {
|
||||
if (reportQueue == 0) {
|
||||
ReceivesMonitoringReportsIF* receiver = objectManager->get<
|
||||
ReceivesMonitoringReportsIF* receiver = ObjectManager::instance()->get<
|
||||
ReceivesMonitoringReportsIF>(reportingTarget);
|
||||
if (receiver == NULL) {
|
||||
if (receiver == nullptr) {
|
||||
return ObjectManagerIF::NOT_FOUND;
|
||||
}
|
||||
reportQueue = receiver->getCommandQueue();
|
||||
}
|
||||
if (ipcStore == NULL) {
|
||||
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore == NULL) {
|
||||
if (ipcStore == nullptr) {
|
||||
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
@@ -56,5 +51,5 @@ ReturnValue_t LimitViolationReporter::checkClassLoaded() {
|
||||
|
||||
//Lazy initialization.
|
||||
MessageQueueId_t LimitViolationReporter::reportQueue = 0;
|
||||
StorageManagerIF* LimitViolationReporter::ipcStore = NULL;
|
||||
StorageManagerIF* LimitViolationReporter::ipcStore = nullptr;
|
||||
object_id_t LimitViolationReporter::reportingTarget = 0;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#include "MonitoringMessage.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
|
||||
MonitoringMessage::~MonitoringMessage() {
|
||||
}
|
||||
@@ -25,7 +25,7 @@ void MonitoringMessage::clear(CommandMessage* message) {
|
||||
message->setCommand(CommandMessage::CMD_NONE);
|
||||
switch (message->getCommand()) {
|
||||
case MonitoringMessage::LIMIT_VIOLATION_REPORT: {
|
||||
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
||||
StorageManagerIF *ipcStore = ObjectManager::instance()->get<StorageManagerIF>(
|
||||
objects::IPC_STORE);
|
||||
if (ipcStore != NULL) {
|
||||
ipcStore->deleteData(getStoreId(message));
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#include "MonitoringIF.h"
|
||||
|
||||
#include "../datapoollocal/localPoolDefinitions.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
#include "../serialize/SerialBufferAdapter.h"
|
||||
#include "../serialize/SerialFixedArrayListAdapter.h"
|
||||
#include "../serialize/SerializeElement.h"
|
||||
@@ -71,7 +71,7 @@ private:
|
||||
}
|
||||
bool checkAndSetStamper() {
|
||||
if (timeStamper == nullptr) {
|
||||
timeStamper = objectManager->get<TimeStamperIF>( timeStamperId );
|
||||
timeStamper = ObjectManager::instance()->get<TimeStamperIF>( timeStamperId );
|
||||
if ( timeStamper == nullptr ) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MonitoringReportContent::checkAndSetStamper: "
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#include "../datapool/PIDReaderList.h"
|
||||
#include "../health/HealthTableIF.h"
|
||||
#include "../parameters/HasParametersIF.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "../objectmanager/ObjectManager.h"
|
||||
|
||||
|
||||
//SHOULDDO: This is by far not perfect. Could be merged with new Monitor classes. But still, it's over-engineering.
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
ReturnValue_t initialize() {
|
||||
healthTable = objectManager->get<HealthTableIF>(objects::HEALTH_TABLE);
|
||||
healthTable = ObjectManager::instance()->get<HealthTableIF>(objects::HEALTH_TABLE);
|
||||
if (healthTable == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
@@ -6,11 +6,23 @@
|
||||
#endif
|
||||
#include <cstdlib>
|
||||
|
||||
ObjectManager::ObjectManager( void (*setProducer)() ):
|
||||
produceObjects(setProducer) {
|
||||
//There's nothing special to do in the constructor.
|
||||
ObjectManager* ObjectManager::objManagerInstance = nullptr;
|
||||
|
||||
ObjectManager* ObjectManager::instance() {
|
||||
if(objManagerInstance == nullptr) {
|
||||
objManagerInstance = new ObjectManager();
|
||||
}
|
||||
return objManagerInstance;
|
||||
}
|
||||
|
||||
void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc, void *factoryArgs) {
|
||||
this->objectFactoryFunction = objFactoryFunc;
|
||||
this->factoryArgs = factoryArgs;
|
||||
}
|
||||
|
||||
|
||||
ObjectManager::ObjectManager() {}
|
||||
|
||||
|
||||
ObjectManager::~ObjectManager() {
|
||||
for (auto const& iter : objectList) {
|
||||
@@ -28,10 +40,13 @@ ReturnValue_t ObjectManager::insert( object_id_t id, SystemObjectIF* object) {
|
||||
return this->RETURN_OK;
|
||||
} else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "ObjectManager::insert: Object id " << std::hex
|
||||
<< static_cast<uint32_t>(id) << std::dec
|
||||
<< " is already in use!" << std::endl;
|
||||
sif::error << "Terminating program." << std::endl;
|
||||
sif::error << "ObjectManager::insert: Object ID " << std::hex <<
|
||||
static_cast<uint32_t>(id) << std::dec << " is already in use!" << std::endl;
|
||||
sif::error << "Terminating program" << std::endl;
|
||||
#else
|
||||
sif::printError("ObjectManager::insert: Object ID 0x%08x is already in use!\n",
|
||||
static_cast<unsigned int>(id));
|
||||
sif::printError("Terminating program");
|
||||
#endif
|
||||
//This is very severe and difficult to handle in other places.
|
||||
std::exit(INSERTION_FAILED);
|
||||
@@ -66,12 +81,8 @@ SystemObjectIF* ObjectManager::getSystemObject( object_id_t id ) {
|
||||
}
|
||||
}
|
||||
|
||||
ObjectManager::ObjectManager() : produceObjects(nullptr) {
|
||||
|
||||
}
|
||||
|
||||
void ObjectManager::initialize() {
|
||||
if(produceObjects == nullptr) {
|
||||
if(objectFactoryFunction == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "ObjectManager::initialize: Passed produceObjects "
|
||||
"functions is nullptr!" << std::endl;
|
||||
@@ -80,7 +91,7 @@ void ObjectManager::initialize() {
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
this->produceObjects();
|
||||
objectFactoryFunction(factoryArgs);
|
||||
ReturnValue_t result = RETURN_FAILED;
|
||||
uint32_t errorCount = 0;
|
||||
for (auto const& it : objectList) {
|
||||
@@ -108,9 +119,9 @@ void ObjectManager::initialize() {
|
||||
result = it.second->checkObjectConnections();
|
||||
if ( result != RETURN_OK ) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "ObjectManager::ObjectManager: Object " << std::hex <<
|
||||
(int) it.first << " connection check failed with code 0x"
|
||||
<< result << std::dec << std::endl;
|
||||
sif::error << "ObjectManager::ObjectManager: Object 0x" << std::hex <<
|
||||
(int) it.first << " connection check failed with code 0x" << result <<
|
||||
std::dec << std::endl;
|
||||
#endif
|
||||
errorCount++;
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include "SystemObjectIF.h"
|
||||
#include <map>
|
||||
|
||||
|
||||
/**
|
||||
* @brief This class implements a global object manager.
|
||||
* @details This manager handles a list of available objects with system-wide
|
||||
@@ -19,44 +20,59 @@
|
||||
* @author Bastian Baetz
|
||||
*/
|
||||
class ObjectManager : public ObjectManagerIF {
|
||||
private:
|
||||
//comparison?
|
||||
/**
|
||||
* @brief This is the map of all initialized objects in the manager.
|
||||
* @details Objects in the List must inherit the SystemObjectIF.
|
||||
*/
|
||||
std::map<object_id_t, SystemObjectIF*> objectList;
|
||||
protected:
|
||||
SystemObjectIF* getSystemObject( object_id_t id );
|
||||
/**
|
||||
* @brief This attribute is initialized with the factory function
|
||||
* that creates new objects.
|
||||
* @details The function is called if an object was requested with
|
||||
* getSystemObject, but not found in objectList.
|
||||
* @param The id of the object to be created.
|
||||
* @return Returns a pointer to the newly created object or NULL.
|
||||
*/
|
||||
void (*produceObjects)();
|
||||
public:
|
||||
/**
|
||||
* @brief Apart from setting the producer function, nothing special
|
||||
* happens in the constructor.
|
||||
* @param setProducer A pointer to a factory function.
|
||||
*/
|
||||
ObjectManager( void (*produce)() );
|
||||
ObjectManager();
|
||||
/**
|
||||
* @brief In the class's destructor, all objects in the list are deleted.
|
||||
*/
|
||||
// SHOULDDO: If, for some reason, deleting an ObjectManager instance is
|
||||
// required, check if this works.
|
||||
virtual ~ObjectManager( void );
|
||||
ReturnValue_t insert( object_id_t id, SystemObjectIF* object );
|
||||
ReturnValue_t remove( object_id_t id );
|
||||
void initialize();
|
||||
void printList();
|
||||
|
||||
using produce_function_t = void (*) (void* args);
|
||||
|
||||
/**
|
||||
* Returns the single instance of TaskFactory.
|
||||
* The implementation of #instance is found in its subclasses.
|
||||
* Thus, we choose link-time variability of the instance.
|
||||
*/
|
||||
static ObjectManager* instance();
|
||||
|
||||
void setObjectFactoryFunction(produce_function_t prodFunc, void* args);
|
||||
|
||||
template <typename T> T* get( object_id_t id );
|
||||
|
||||
/**
|
||||
* @brief In the class's destructor, all objects in the list are deleted.
|
||||
*/
|
||||
virtual ~ObjectManager();
|
||||
ReturnValue_t insert(object_id_t id, SystemObjectIF* object) override;
|
||||
ReturnValue_t remove(object_id_t id) override;
|
||||
void initialize() override;
|
||||
void printList() override;
|
||||
|
||||
protected:
|
||||
SystemObjectIF* getSystemObject(object_id_t id) override;
|
||||
/**
|
||||
* @brief This attribute is initialized with the factory function
|
||||
* that creates new objects.
|
||||
* @details The function is called if an object was requested with
|
||||
* getSystemObject, but not found in objectList.
|
||||
* @param The id of the object to be created.
|
||||
* @return Returns a pointer to the newly created object or NULL.
|
||||
*/
|
||||
produce_function_t objectFactoryFunction = nullptr;
|
||||
void* factoryArgs = nullptr;
|
||||
|
||||
private:
|
||||
ObjectManager();
|
||||
|
||||
/**
|
||||
* @brief This is the map of all initialized objects in the manager.
|
||||
* @details Objects in the List must inherit the SystemObjectIF.
|
||||
*/
|
||||
std::map<object_id_t, SystemObjectIF*> objectList;
|
||||
static ObjectManager* objManagerInstance;
|
||||
};
|
||||
|
||||
|
||||
// Documentation can be found in the class method declaration above
|
||||
template <typename T>
|
||||
T* ObjectManager::get( object_id_t id ) {
|
||||
SystemObjectIF* temp = this->getSystemObject(id);
|
||||
return dynamic_cast<T*>(temp);
|
||||
}
|
||||
|
||||
#endif /* FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ */
|
||||
|
@@ -4,15 +4,15 @@
|
||||
#include "frameworkObjects.h"
|
||||
#include "SystemObjectIF.h"
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../serviceinterface/ServiceInterface.h"
|
||||
|
||||
/**
|
||||
* @brief This class provides an interface to the global object manager.
|
||||
* @details This manager handles a list of available objects with system-wide
|
||||
* relevance, such as device handlers, and TM/TC services. They can be
|
||||
* inserted, removed and retrieved from the list. On getting the
|
||||
* object, the call checks if the object implements the requested
|
||||
* interface.
|
||||
* @details
|
||||
* This manager handles a list of available objects with system-wide relevance, such as device
|
||||
* handlers, and TM/TC services. They can be inserted, removed and retrieved from the list.
|
||||
* On getting the object, the call checks if the object implements the requested interface.
|
||||
* This interface does not specify a getter function because templates can't be used in interfaces.
|
||||
* @author Bastian Baetz
|
||||
* @ingroup system_objects
|
||||
*/
|
||||
@@ -21,7 +21,8 @@ public:
|
||||
static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF;
|
||||
static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 );
|
||||
static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 );
|
||||
static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); //!< Can be used if the initialization of a SystemObject failed.
|
||||
//!< Can be used if the initialization of a SystemObject failed.
|
||||
static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 );
|
||||
static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 );
|
||||
|
||||
protected:
|
||||
@@ -49,22 +50,11 @@ public:
|
||||
* @li RETURN_OK in case the object was successfully inserted
|
||||
*/
|
||||
virtual ReturnValue_t insert( object_id_t id, SystemObjectIF* object ) = 0;
|
||||
/**
|
||||
* @brief With the get call, interfaces of an object can be retrieved in
|
||||
* a type-safe manner.
|
||||
* @details With the template-based call, the object list is searched with the
|
||||
* getSystemObject method and afterwards it is checked, if the object
|
||||
* implements the requested interface (with a dynamic_cast).
|
||||
* @param id The object id of the requested object.
|
||||
* @return The method returns a pointer to an object implementing the
|
||||
* requested interface, or NULL.
|
||||
*/
|
||||
template <typename T> T* get( object_id_t id );
|
||||
/**
|
||||
* @brief With this call, an object is removed from the list.
|
||||
* @param id The object id of the object to be removed.
|
||||
* @return \li NOT_FOUND in case the object was not found
|
||||
* \li RETURN_OK in case the object was successfully removed
|
||||
* @return @li NOT_FOUND in case the object was not found
|
||||
* @li RETURN_OK in case the object was successfully removed
|
||||
*/
|
||||
virtual ReturnValue_t remove( object_id_t id ) = 0;
|
||||
virtual void initialize() = 0;
|
||||
@@ -75,24 +65,4 @@ public:
|
||||
virtual void printList() = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief This is the forward declaration of the global objectManager instance.
|
||||
*/
|
||||
// SHOULDDO: maybe put this in the glob namespace to explicitely mark it global?
|
||||
extern ObjectManagerIF *objectManager;
|
||||
|
||||
/*Documentation can be found in the class method declaration above.*/
|
||||
template <typename T>
|
||||
T* ObjectManagerIF::get( object_id_t id ) {
|
||||
if(objectManager == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "ObjectManagerIF: Global object manager has not "
|
||||
"been initialized yet!" << std::endl;
|
||||
#endif
|
||||
}
|
||||
SystemObjectIF* temp = this->getSystemObject(id);
|
||||
return dynamic_cast<T*>(temp);
|
||||
}
|
||||
|
||||
#endif /* OBJECTMANAGERIF_H_ */
|
||||
|
@@ -4,18 +4,14 @@
|
||||
|
||||
SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) :
|
||||
objectId(setObjectId), registered(doRegister) {
|
||||
if (registered) {
|
||||
if(objectManager != nullptr) {
|
||||
objectManager->insert(objectId, this);
|
||||
}
|
||||
}
|
||||
if (registered) {
|
||||
ObjectManager::instance()->insert(objectId, this);
|
||||
}
|
||||
}
|
||||
|
||||
SystemObject::~SystemObject() {
|
||||
if (registered) {
|
||||
if(objectManager != nullptr) {
|
||||
objectManager->remove(objectId);
|
||||
}
|
||||
ObjectManager::instance()->remove(objectId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,8 +1,9 @@
|
||||
#ifndef 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 {
|
||||
enum framework_objects: object_id_t {
|
||||
FSFW_OBJECTS_START = 0x53000000,
|
||||
@@ -16,6 +17,7 @@ enum framework_objects: object_id_t {
|
||||
PUS_SERVICE_17_TEST = 0x53000017,
|
||||
PUS_SERVICE_20_PARAMETERS = 0x53000020,
|
||||
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
|
||||
PUS_SERVICE_201_HEALTH = 0x53000201,
|
||||
|
||||
//Generic IDs for IPC, modes, health, events
|
||||
HEALTH_TABLE = 0x53010000,
|
||||
|
@@ -1,35 +1,34 @@
|
||||
# Check the OS_FSFW variable
|
||||
if(${OS_FSFW} STREQUAL "freertos")
|
||||
add_subdirectory(FreeRTOS)
|
||||
add_subdirectory(FreeRTOS)
|
||||
elseif(${OS_FSFW} STREQUAL "rtems")
|
||||
add_subdirectory(rtems)
|
||||
add_subdirectory(rtems)
|
||||
elseif(${OS_FSFW} STREQUAL "linux")
|
||||
add_subdirectory(linux)
|
||||
add_subdirectory(linux)
|
||||
elseif(${OS_FSFW} STREQUAL "host")
|
||||
add_subdirectory(host)
|
||||
if (WIN32)
|
||||
add_subdirectory(windows)
|
||||
elseif(UNIX)
|
||||
target_sources(${LIB_FSFW_NAME}
|
||||
PUBLIC
|
||||
linux/TcUnixUdpPollingTask.cpp
|
||||
linux/TmTcUnixUdpBridge.cpp
|
||||
)
|
||||
endif ()
|
||||
add_subdirectory(host)
|
||||
if (WIN32)
|
||||
add_subdirectory(windows)
|
||||
elseif(UNIX)
|
||||
# We still need to pull in some Linux specific sources
|
||||
target_sources(${LIB_FSFW_NAME} PUBLIC
|
||||
linux/tcpipHelpers.cpp
|
||||
)
|
||||
endif ()
|
||||
|
||||
else()
|
||||
|
||||
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
|
||||
# Not set. Assumuing this is a host build, try to determine host OS
|
||||
if (WIN32)
|
||||
add_subdirectory(host)
|
||||
add_subdirectory(windows)
|
||||
elseif (UNIX)
|
||||
add_subdirectory(linux)
|
||||
else ()
|
||||
# MacOS or other OSes have not been tested yet / are not supported.
|
||||
message(FATAL_ERROR "The host OS could not be determined! Aborting.")
|
||||
endif()
|
||||
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
|
||||
# Not set. Assumuing this is a host build, try to determine host OS
|
||||
if (WIN32)
|
||||
add_subdirectory(host)
|
||||
add_subdirectory(windows)
|
||||
elseif (UNIX)
|
||||
add_subdirectory(linux)
|
||||
else ()
|
||||
# MacOS or other OSes have not been tested yet / are not supported.
|
||||
message(FATAL_ERROR "The host OS could not be determined! Aborting.")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
|
@@ -15,6 +15,7 @@ target_sources(${LIB_FSFW_NAME}
|
||||
TaskFactory.cpp
|
||||
Timekeeper.cpp
|
||||
TaskManagement.cpp
|
||||
QueueMapManager.cpp
|
||||
)
|
||||
|
||||
# FreeRTOS is required to link the FSFW now. It is recommended to compile
|
||||
|
@@ -111,7 +111,7 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
||||
|
||||
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
|
||||
timeval* to) {
|
||||
struct tm time_tm;
|
||||
struct tm time_tm = {};
|
||||
|
||||
time_tm.tm_year = from->year - 1900;
|
||||
time_tm.tm_mon = from->month - 1;
|
||||
@@ -134,71 +134,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
||||
/ 3600.;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
|
||||
//SHOULDDO: works not for dates in the past (might have less leap seconds)
|
||||
if (timeMutex == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
uint16_t leapSeconds;
|
||||
ReturnValue_t result = getLeapSeconds(&leapSeconds);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
timeval leapSeconds_timeval = { 0, 0 };
|
||||
leapSeconds_timeval.tv_sec = leapSeconds;
|
||||
|
||||
//initial offset between UTC and TAI
|
||||
timeval UTCtoTAI1972 = { 10, 0 };
|
||||
|
||||
timeval TAItoTT = { 32, 184000 };
|
||||
|
||||
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
|
||||
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
leapSeconds = leapSeconds_;
|
||||
|
||||
result = timeMutex->unlockMutex();
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
||||
if (timeMutex == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
*leapSeconds_ = leapSeconds;
|
||||
|
||||
result = timeMutex->unlockMutex();
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::checkOrCreateClockMutex() {
|
||||
if (timeMutex == NULL) {
|
||||
MutexFactory* mutexFactory = MutexFactory::instance();
|
||||
if (mutexFactory == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
timeMutex = mutexFactory->createMutex();
|
||||
if (timeMutex == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "FixedTimeslotTask.h"
|
||||
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
|
||||
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
|
||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
|
||||
@@ -66,8 +67,7 @@ ReturnValue_t FixedTimeslotTask::startTask() {
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
|
||||
uint32_t slotTimeMs, int8_t executionStep) {
|
||||
ExecutableObjectIF* handler =
|
||||
objectManager->get<ExecutableObjectIF>(componentId);
|
||||
ExecutableObjectIF* handler = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
|
||||
if (handler != nullptr) {
|
||||
pst.addSlot(componentId, slotTimeMs, executionStep, handler, this);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
|
@@ -1,74 +1,73 @@
|
||||
#include "MessageQueue.h"
|
||||
#include "../../objectmanager/ObjectManagerIF.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "QueueMapManager.h"
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
#include "../../serviceinterface/ServiceInterface.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):
|
||||
maxMessageSize(maxMessageSize) {
|
||||
handle = xQueueCreate(messageDepth, maxMessageSize);
|
||||
maxMessageSize(maxMessageSize) {
|
||||
handle = xQueueCreate(messageDepth, maxMessageSize);
|
||||
if (handle == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
if (handle == nullptr) {
|
||||
sif::error << "MessageQueue::MessageQueue:"
|
||||
<< " Creation failed." << std::endl;
|
||||
sif::error << "Specified Message Depth: " << messageDepth
|
||||
<< std::endl;
|
||||
sif::error << "Specified Maximum Message Size: "
|
||||
<< maxMessageSize << std::endl;
|
||||
|
||||
}
|
||||
sif::error << "MessageQueue::MessageQueue: Creation failed" << std::endl;
|
||||
sif::error << "Specified Message Depth: " << messageDepth << std::endl;
|
||||
sif::error << "Specified Maximum Message Size: " << maxMessageSize << std::endl;
|
||||
#else
|
||||
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
|
||||
}
|
||||
QueueMapManager::instance()->addMessageQueue(handle, &queueId);
|
||||
}
|
||||
|
||||
MessageQueue::~MessageQueue() {
|
||||
if (handle != nullptr) {
|
||||
vQueueDelete(handle);
|
||||
}
|
||||
if (handle != nullptr) {
|
||||
vQueueDelete(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageQueue::switchSystemContext(CallContext callContext) {
|
||||
this->callContext = callContext;
|
||||
this->callContext = callContext;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message, bool ignoreFault) {
|
||||
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
|
||||
MessageQueueMessageIF* message, bool ignoreFault) {
|
||||
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
|
||||
return sendToDefaultFrom(message, this->getId());
|
||||
return sendToDefaultFrom(message, this->getId());
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||
return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault);
|
||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||
return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault);
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
|
||||
if (this->lastPartner != MessageQueueIF::NO_QUEUE) {
|
||||
return sendMessageFrom(this->lastPartner, message, this->getId());
|
||||
} else {
|
||||
return NO_REPLY_PARTNER;
|
||||
}
|
||||
if (this->lastPartner != MessageQueueIF::NO_QUEUE) {
|
||||
return sendMessageFrom(this->lastPartner, message, this->getId());
|
||||
} else {
|
||||
return NO_REPLY_PARTNER;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
||||
bool ignoreFault) {
|
||||
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault,
|
||||
callContext);
|
||||
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
||||
bool ignoreFault) {
|
||||
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault,
|
||||
callContext);
|
||||
}
|
||||
|
||||
QueueHandle_t MessageQueue::getNativeQueueHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) {
|
||||
if (result != pdPASS) {
|
||||
if (not ignoreFault) {
|
||||
InternalErrorReporterIF* internalErrorReporter = objectManager->
|
||||
get<InternalErrorReporterIF>(
|
||||
objects::INTERNAL_ERROR_REPORTER);
|
||||
InternalErrorReporterIF* internalErrorReporter = ObjectManager::instance()->
|
||||
get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||
if (internalErrorReporter != nullptr) {
|
||||
internalErrorReporter->queueMessageNotSent();
|
||||
}
|
||||
@@ -79,51 +78,51 @@ ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t* receivedFrom) {
|
||||
ReturnValue_t status = this->receiveMessage(message);
|
||||
if(status == HasReturnvaluesIF::RETURN_OK) {
|
||||
*receivedFrom = this->lastPartner;
|
||||
}
|
||||
return status;
|
||||
MessageQueueId_t* receivedFrom) {
|
||||
ReturnValue_t status = this->receiveMessage(message);
|
||||
if(status == HasReturnvaluesIF::RETURN_OK) {
|
||||
*receivedFrom = this->lastPartner;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||
BaseType_t result = xQueueReceive(handle,reinterpret_cast<void*>(
|
||||
message->getBuffer()), 0);
|
||||
if (result == pdPASS){
|
||||
this->lastPartner = message->getSender();
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
} else {
|
||||
return MessageQueueIF::EMPTY;
|
||||
}
|
||||
BaseType_t result = xQueueReceive(handle,reinterpret_cast<void*>(
|
||||
message->getBuffer()), 0);
|
||||
if (result == pdPASS){
|
||||
this->lastPartner = message->getSender();
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
} else {
|
||||
return MessageQueueIF::EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getLastPartner() const {
|
||||
return lastPartner;
|
||||
return lastPartner;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||
//TODO FreeRTOS does not support flushing partially
|
||||
//Is always successful
|
||||
xQueueReset(handle);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
//TODO FreeRTOS does not support flushing partially
|
||||
//Is always successful
|
||||
xQueueReset(handle);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getId() const {
|
||||
return reinterpret_cast<MessageQueueId_t>(handle);
|
||||
return queueId;
|
||||
}
|
||||
|
||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
||||
defaultDestinationSet = true;
|
||||
this->defaultDestination = defaultDestination;
|
||||
defaultDestinationSet = true;
|
||||
this->defaultDestination = defaultDestination;
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getDefaultDestination() const {
|
||||
return defaultDestination;
|
||||
return defaultDestination;
|
||||
}
|
||||
|
||||
bool MessageQueue::isDefaultDestinationSet() const {
|
||||
return defaultDestinationSet;
|
||||
return defaultDestinationSet;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,30 +130,25 @@ bool MessageQueue::isDefaultDestinationSet() const {
|
||||
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
||||
bool ignoreFault, CallContext callContext) {
|
||||
BaseType_t result = pdFALSE;
|
||||
QueueHandle_t destination = nullptr;
|
||||
BaseType_t result = pdFALSE;
|
||||
if(sendTo == MessageQueueIF::NO_QUEUE) {
|
||||
return MessageQueueIF::DESTINATION_INVALID;
|
||||
}
|
||||
|
||||
if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) {
|
||||
return MessageQueueIF::DESTINVATION_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);
|
||||
|
||||
|
||||
if(callContext == CallContext::TASK) {
|
||||
result = xQueueSendToBack(destination,
|
||||
static_cast<const void*>(message->getBuffer()), 0);
|
||||
result = xQueueSendToBack(destination, static_cast<const void*>(message->getBuffer()), 0);
|
||||
}
|
||||
else {
|
||||
/* If the call context is from an interrupt,
|
||||
* request a context switch if a higher priority task
|
||||
* was blocked by the interrupt. */
|
||||
/* If the call context is from an interrupt, request a context switch if a higher priority
|
||||
task was blocked by the interrupt. */
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
result = xQueueSendFromISR(reinterpret_cast<QueueHandle_t>(sendTo),
|
||||
static_cast<const void*>(message->getBuffer()),
|
||||
result = xQueueSendFromISR(destination, static_cast<const void*>(message->getBuffer()),
|
||||
&xHigherPriorityTaskWoken);
|
||||
if(xHigherPriorityTaskWoken == pdTRUE) {
|
||||
TaskManagement::requestContextSwitch(callContext);
|
||||
|
@@ -11,11 +11,6 @@
|
||||
#include <freertos/queue.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
|
||||
* message queue messages.
|
||||
@@ -40,112 +35,116 @@
|
||||
* @ingroup message_queue
|
||||
*/
|
||||
class MessageQueue : public MessageQueueIF {
|
||||
friend class MessageQueueSenderIF;
|
||||
friend class MessageQueueSenderIF;
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor initializes and configures the message queue.
|
||||
* @details
|
||||
* By making use of the according operating system call, a message queue
|
||||
* is created and initialized. The message depth - the maximum number of
|
||||
* messages to be buffered - may be set with the help of a parameter,
|
||||
* whereas the message size is automatically set to the maximum message
|
||||
* queue message size. The operating system sets the message queue id, or
|
||||
* in case of failure, it is set to zero.
|
||||
* @param message_depth
|
||||
* The number of messages to be buffered before passing an error to the
|
||||
* sender. Default is three.
|
||||
* @param max_message_size
|
||||
* With this parameter, the maximum message size can be adjusted.
|
||||
* This should be left default.
|
||||
*/
|
||||
MessageQueue( size_t messageDepth = 3,
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE );
|
||||
/**
|
||||
* @brief The constructor initializes and configures the message queue.
|
||||
* @details
|
||||
* By making use of the according operating system call, a message queue
|
||||
* is created and initialized. The message depth - the maximum number of
|
||||
* messages to be buffered - may be set with the help of a parameter,
|
||||
* whereas the message size is automatically set to the maximum message
|
||||
* queue message size. The operating system sets the message queue id, or
|
||||
* in case of failure, it is set to zero.
|
||||
* @param message_depth
|
||||
* The number of messages to be buffered before passing an error to the
|
||||
* sender. Default is three.
|
||||
* @param max_message_size
|
||||
* With this parameter, the maximum message size can be adjusted.
|
||||
* This should be left default.
|
||||
*/
|
||||
MessageQueue( size_t messageDepth = 3,
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE );
|
||||
|
||||
/** Copying message queues forbidden */
|
||||
MessageQueue(const MessageQueue&) = delete;
|
||||
MessageQueue& operator=(const MessageQueue&) = delete;
|
||||
/** Copying message queues forbidden */
|
||||
MessageQueue(const MessageQueue&) = delete;
|
||||
MessageQueue& operator=(const MessageQueue&) = delete;
|
||||
|
||||
/**
|
||||
* @brief The destructor deletes the formerly created message queue.
|
||||
* @details This is accomplished by using the delete call provided
|
||||
* by the operating system.
|
||||
*/
|
||||
virtual ~MessageQueue();
|
||||
/**
|
||||
* @brief The destructor deletes the formerly created message queue.
|
||||
* @details This is accomplished by using the delete call provided
|
||||
* by the operating system.
|
||||
*/
|
||||
virtual ~MessageQueue();
|
||||
|
||||
/**
|
||||
* This function is used to switch the call context. This has to be called
|
||||
* if a message is sent or received from an ISR!
|
||||
* @param callContext
|
||||
*/
|
||||
void switchSystemContext(CallContext callContext);
|
||||
/**
|
||||
* This function is used to switch the call context. This has to be called
|
||||
* if a message is sent or received from an ISR!
|
||||
* @param callContext
|
||||
*/
|
||||
void switchSystemContext(CallContext callContext);
|
||||
|
||||
/** MessageQueueIF implementation */
|
||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message, bool ignoreFault = false) override;
|
||||
/** MessageQueueIF implementation */
|
||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message, bool ignoreFault = false) override;
|
||||
|
||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
||||
|
||||
ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false) override;
|
||||
ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false) override;
|
||||
|
||||
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false) override;
|
||||
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false) override;
|
||||
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t *receivedFrom) override;
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t *receivedFrom) override;
|
||||
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||
|
||||
ReturnValue_t flush(uint32_t* count) override;
|
||||
ReturnValue_t flush(uint32_t* count) override;
|
||||
|
||||
MessageQueueId_t getLastPartner() const override;
|
||||
MessageQueueId_t getLastPartner() const override;
|
||||
|
||||
MessageQueueId_t getId() const override;
|
||||
MessageQueueId_t getId() const override;
|
||||
|
||||
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
||||
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
||||
|
||||
MessageQueueId_t getDefaultDestination() const override;
|
||||
MessageQueueId_t getDefaultDestination() const override;
|
||||
|
||||
bool isDefaultDestinationSet() const override;
|
||||
bool isDefaultDestinationSet() const override;
|
||||
|
||||
QueueHandle_t getNativeQueueHandle();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Implementation to be called from any send Call within
|
||||
* MessageQueue and MessageQueueSenderIF.
|
||||
* @details
|
||||
* This method takes the message provided, adds the sentFrom information and
|
||||
* passes it on to the destination provided with an operating system call.
|
||||
* The OS's return value is returned.
|
||||
* @param sendTo
|
||||
* This parameter specifies the message queue id to send the message to.
|
||||
* @param message
|
||||
* This is a pointer to a previously created message, which is sent.
|
||||
* @param sentFrom
|
||||
* The sentFrom information can be set to inject the sender's queue id into
|
||||
* the message. This variable is set to zero by default.
|
||||
* @param ignoreFault
|
||||
* If set to true, the internal software fault counter is not incremented
|
||||
* if queue is full.
|
||||
* @param context Specify whether call is made from task or from an ISR.
|
||||
*/
|
||||
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault=false, CallContext callContext = CallContext::TASK);
|
||||
/**
|
||||
* @brief Implementation to be called from any send Call within
|
||||
* MessageQueue and MessageQueueSenderIF.
|
||||
* @details
|
||||
* This method takes the message provided, adds the sentFrom information and
|
||||
* passes it on to the destination provided with an operating system call.
|
||||
* The OS's return value is returned.
|
||||
* @param sendTo
|
||||
* This parameter specifies the message queue id to send the message to.
|
||||
* @param message
|
||||
* This is a pointer to a previously created message, which is sent.
|
||||
* @param sentFrom
|
||||
* The sentFrom information can be set to inject the sender's queue id into
|
||||
* the message. This variable is set to zero by default.
|
||||
* @param ignoreFault
|
||||
* If set to true, the internal software fault counter is not incremented
|
||||
* if queue is full.
|
||||
* @param context Specify whether call is made from task or from an ISR.
|
||||
*/
|
||||
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault=false, CallContext callContext = CallContext::TASK);
|
||||
|
||||
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
||||
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
||||
|
||||
private:
|
||||
bool defaultDestinationSet = false;
|
||||
QueueHandle_t handle;
|
||||
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
||||
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
|
||||
const size_t maxMessageSize;
|
||||
//! Stores the current system context
|
||||
CallContext callContext = CallContext::TASK;
|
||||
bool defaultDestinationSet = false;
|
||||
QueueHandle_t handle;
|
||||
MessageQueueId_t queueId = MessageQueueIF::NO_QUEUE;
|
||||
|
||||
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
||||
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
|
||||
const size_t maxMessageSize;
|
||||
//! Stores the current system context
|
||||
CallContext callContext = CallContext::TASK;
|
||||
};
|
||||
|
||||
#endif /* FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ */
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "PeriodicTask.h"
|
||||
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
#include "../../tasks/ExecutableObjectIF.h"
|
||||
|
||||
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
|
||||
@@ -100,7 +101,7 @@ void PeriodicTask::taskFunctionality() {
|
||||
}
|
||||
|
||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
|
||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(
|
||||
object);
|
||||
if (newObject == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
|
58
osal/FreeRTOS/QueueMapManager.cpp
Normal file
58
osal/FreeRTOS/QueueMapManager.cpp
Normal 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);
|
||||
}
|
50
osal/FreeRTOS/QueueMapManager.h
Normal file
50
osal/FreeRTOS/QueueMapManager.h
Normal 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_ */
|
@@ -1,3 +1,17 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
tcpipCommon.cpp
|
||||
)
|
||||
if(DEFINED WIN32 OR DEFINED UNIX)
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
tcpipCommon.cpp
|
||||
TcpIpBase.cpp
|
||||
UdpTcPollingTask.cpp
|
||||
UdpTmTcBridge.cpp
|
||||
TcpTmTcServer.cpp
|
||||
TcpTmTcBridge.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||
wsock32
|
||||
ws2_32
|
||||
)
|
||||
endif()
|
53
osal/common/TcpIpBase.cpp
Normal file
53
osal/common/TcpIpBase.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "TcpIpBase.h"
|
||||
#include "../../platform.h"
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
TcpIpBase::TcpIpBase() {
|
||||
|
||||
}
|
||||
|
||||
ReturnValue_t TcpIpBase::initialize() {
|
||||
#ifdef _WIN32
|
||||
/* Initiates Winsock DLL. */
|
||||
WSAData wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
int err = WSAStartup(wVersionRequested, &wsaData);
|
||||
if (err != 0) {
|
||||
/* Tell the user that we could not find a usable Winsock DLL. */
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: WSAStartup failed with error: " <<
|
||||
err << std::endl;
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
TcpIpBase::~TcpIpBase() {
|
||||
closeSocket(serverSocket);
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
int TcpIpBase::closeSocket(socket_t socket) {
|
||||
#ifdef PLATFORM_WIN
|
||||
return closesocket(socket);
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
return close(socket);
|
||||
#endif
|
||||
}
|
||||
|
||||
int TcpIpBase::getLastSocketError() {
|
||||
#ifdef PLATFORM_WIN
|
||||
return WSAGetLastError();
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
47
osal/common/TcpIpBase.h
Normal file
47
osal/common/TcpIpBase.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef FSFW_OSAL_COMMON_TCPIPIF_H_
|
||||
#define FSFW_OSAL_COMMON_TCPIPIF_H_
|
||||
|
||||
#include "../../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "../../platform.h"
|
||||
|
||||
#ifdef PLATFORM_WIN
|
||||
#include <winsock2.h>
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
class TcpIpBase {
|
||||
protected:
|
||||
|
||||
#ifdef PLATFORM_WIN
|
||||
static constexpr int SHUT_RECV = SD_RECEIVE;
|
||||
static constexpr int SHUT_SEND = SD_SEND;
|
||||
static constexpr int SHUT_BOTH = SD_BOTH;
|
||||
|
||||
using socket_t = SOCKET;
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
using socket_t = int;
|
||||
|
||||
static constexpr int INVALID_SOCKET = -1;
|
||||
static constexpr int SOCKET_ERROR = -1;
|
||||
|
||||
static constexpr int SHUT_RECV = SHUT_RD;
|
||||
static constexpr int SHUT_SEND = SHUT_WR;
|
||||
static constexpr int SHUT_BOTH = SHUT_RDWR;
|
||||
#endif
|
||||
|
||||
TcpIpBase();
|
||||
virtual ~TcpIpBase();
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
int closeSocket(socket_t socket);
|
||||
|
||||
int getLastSocketError();
|
||||
|
||||
socket_t serverSocket = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* FSFW_OSAL_COMMON_TCPIPIF_H_ */
|
77
osal/common/TcpTmTcBridge.cpp
Normal file
77
osal/common/TcpTmTcBridge.cpp
Normal 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;
|
||||
}
|
71
osal/common/TcpTmTcBridge.h
Normal file
71
osal/common/TcpTmTcBridge.h
Normal 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_ */
|
||||
|
226
osal/common/TcpTmTcServer.cpp
Normal file
226
osal/common/TcpTmTcServer.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
#include "TcpTmTcServer.h"
|
||||
#include "TcpTmTcBridge.h"
|
||||
#include "tcpipHelpers.h"
|
||||
|
||||
#include "../../platform.h"
|
||||
#include "../../container/SharedRingBuffer.h"
|
||||
#include "../../ipc/MessageQueueSenderIF.h"
|
||||
#include "../../ipc/MutexGuard.h"
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
#include "../../tmtcservices/TmTcMessage.h"
|
||||
|
||||
#ifdef PLATFORM_WIN
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED
|
||||
#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0
|
||||
#endif
|
||||
|
||||
const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7303";
|
||||
|
||||
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 == "") {
|
||||
tcpPort = DEFAULT_TCP_SERVER_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t TcpTmTcServer::initialize() {
|
||||
using namespace tcpip;
|
||||
|
||||
ReturnValue_t result = TcpIpBase::initialize();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
tcStore = ObjectManager::instance()->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::instance()->get<TcpTmTcBridge>(tmtcBridgeId);
|
||||
|
||||
int retval = 0;
|
||||
struct addrinfo *addrResult = nullptr;
|
||||
struct addrinfo hints = {};
|
||||
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
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);
|
||||
if (retval != 0) {
|
||||
handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL);
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
// Open TCP (stream) socket
|
||||
listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype,
|
||||
addrResult->ai_protocol);
|
||||
if(listenerTcpSocket == INVALID_SOCKET) {
|
||||
freeaddrinfo(addrResult);
|
||||
handleError(Protocol::TCP, ErrorSources::SOCKET_CALL);
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
// Bind to the address found by getaddrinfo
|
||||
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||
if(retval == SOCKET_ERROR) {
|
||||
freeaddrinfo(addrResult);
|
||||
handleError(Protocol::TCP, ErrorSources::BIND_CALL);
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
freeaddrinfo(addrResult);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
TcpTmTcServer::~TcpTmTcServer() {
|
||||
closeSocket(listenerTcpSocket);
|
||||
}
|
||||
|
||||
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
||||
using namespace tcpip;
|
||||
// If a connection is accepted, the corresponding socket will be assigned to the new socket
|
||||
socket_t connSocket = 0;
|
||||
// sockaddr clientSockAddr = {};
|
||||
// socklen_t connectorSockAddrLen = 0;
|
||||
int retval = 0;
|
||||
|
||||
// Listen for connection requests permanently for lifetime of program
|
||||
while(true) {
|
||||
retval = listen(listenerTcpSocket, tcpBacklog);
|
||||
if(retval == SOCKET_ERROR) {
|
||||
handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500);
|
||||
continue;
|
||||
}
|
||||
|
||||
//connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
|
||||
connSocket = accept(listenerTcpSocket, nullptr, nullptr);
|
||||
|
||||
if(connSocket == INVALID_SOCKET) {
|
||||
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
|
||||
closeSocket(connSocket);
|
||||
continue;
|
||||
};
|
||||
|
||||
handleServerOperation(connSocket);
|
||||
|
||||
// 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);
|
||||
}
|
||||
closeSocket(connSocket);
|
||||
}
|
||||
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;
|
||||
}
|
93
osal/common/TcpTmTcServer.h
Normal file
93
osal/common/TcpTmTcServer.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#ifndef FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_
|
||||
#define FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_
|
||||
|
||||
#include "TcpIpBase.h"
|
||||
|
||||
#include "../../platform.h"
|
||||
#include "../../ipc/messageQueueDefinitions.h"
|
||||
#include "../../ipc/MessageQueueIF.h"
|
||||
#include "../../objectmanager/frameworkObjects.h"
|
||||
#include "../../objectmanager/SystemObject.h"
|
||||
#include "../../storagemanager/StorageManagerIF.h"
|
||||
#include "../../tasks/ExecutableObjectIF.h"
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class TcpTmTcBridge;
|
||||
|
||||
/**
|
||||
* @brief TCP server implementation
|
||||
* @details
|
||||
* 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:
|
||||
public SystemObject,
|
||||
public TcpIpBase,
|
||||
public ExecutableObjectIF {
|
||||
public:
|
||||
/* The ports chosen here should not be used by any other process. */
|
||||
static const std::string DEFAULT_TCP_SERVER_PORT;
|
||||
|
||||
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 = "");
|
||||
virtual~ TcpTmTcServer();
|
||||
|
||||
void setTcpBacklog(uint8_t tcpBacklog);
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
protected:
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
private:
|
||||
//! TMTC bridge is cached.
|
||||
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
||||
TcpTmTcBridge* tmtcBridge = nullptr;
|
||||
|
||||
std::string tcpPort;
|
||||
int tcpFlags = 0;
|
||||
socket_t listenerTcpSocket = 0;
|
||||
struct sockaddr tcpAddress;
|
||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||
int tcpAddrLen = sizeof(tcpAddress);
|
||||
int tcpBacklog = 3;
|
||||
|
||||
std::vector<uint8_t> receptionBuffer;
|
||||
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_COMMON_TCP_TMTC_SERVER_H_ */
|
178
osal/common/UdpTcPollingTask.cpp
Normal file
178
osal/common/UdpTcPollingTask.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#include "UdpTcPollingTask.h"
|
||||
#include "tcpipHelpers.h"
|
||||
#include "../../platform.h"
|
||||
#include "../../globalfunctions/arrayprinter.h"
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
|
||||
#ifdef PLATFORM_WIN
|
||||
#include <winsock2.h>
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
//! Debugging preprocessor define.
|
||||
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
|
||||
|
||||
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId,
|
||||
object_id_t tmtcUdpBridge, size_t maxRecvSize,
|
||||
double timeoutSeconds): SystemObject(objectId),
|
||||
tmtcBridgeId(tmtcUdpBridge) {
|
||||
if(frameSize > 0) {
|
||||
this->frameSize = frameSize;
|
||||
}
|
||||
else {
|
||||
this->frameSize = DEFAULT_MAX_RECV_SIZE;
|
||||
}
|
||||
|
||||
/* Set up reception buffer with specified frame size.
|
||||
For now, it is assumed that only one frame is held in the buffer! */
|
||||
receptionBuffer.reserve(this->frameSize);
|
||||
receptionBuffer.resize(this->frameSize);
|
||||
|
||||
if(timeoutSeconds == -1) {
|
||||
receptionTimeout = DEFAULT_TIMEOUT;
|
||||
}
|
||||
else {
|
||||
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
UdpTcPollingTask::~UdpTcPollingTask() {}
|
||||
|
||||
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
|
||||
/* Sender Address is cached here. */
|
||||
struct sockaddr senderAddress;
|
||||
socklen_t senderAddressSize = sizeof(senderAddress);
|
||||
|
||||
/* Poll for new UDP datagrams in permanent loop. */
|
||||
while(true) {
|
||||
int bytesReceived = recvfrom(
|
||||
this->serverSocket,
|
||||
reinterpret_cast<char*>(receptionBuffer.data()),
|
||||
frameSize,
|
||||
receptionFlags,
|
||||
&senderAddress,
|
||||
&senderAddressSize
|
||||
);
|
||||
if(bytesReceived == SOCKET_ERROR) {
|
||||
/* Handle error */
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "UdpTcPollingTask::performOperation: Reception error." << std::endl;
|
||||
#endif
|
||||
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::RECVFROM_CALL, 1000);
|
||||
continue;
|
||||
}
|
||||
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "UdpTcPollingTask::performOperation: " << bytesReceived <<
|
||||
" bytes received" << std::endl;
|
||||
#else
|
||||
#endif
|
||||
#endif /* FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1 */
|
||||
|
||||
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
|
||||
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
||||
|
||||
}
|
||||
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
||||
store_address_t storeId;
|
||||
|
||||
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
|
||||
arrayprinter::print(receptionBuffer.data(), bytesRead);
|
||||
#endif
|
||||
|
||||
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRead);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning<< "UdpTcPollingTask::transferPusToSoftwareBus: Data storage failed." <<
|
||||
std::endl;
|
||||
sif::warning << "Packet size: " << bytesRead << std::endl;
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ReturnValue_t UdpTcPollingTask::initialize() {
|
||||
tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (tcStore == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "UdpTcPollingTask::initialize: TC store uninitialized!" << std::endl;
|
||||
#endif
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
tmtcBridge = ObjectManager::instance()->get<UdpTmTcBridge>(tmtcBridgeId);
|
||||
if(tmtcBridge == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "UdpTcPollingTask::initialize: Invalid TMTC bridge object!" <<
|
||||
std::endl;
|
||||
#endif
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t result = TcpIpBase::initialize();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t UdpTcPollingTask::initializeAfterTaskCreation() {
|
||||
/* Initialize the destination after task creation. This ensures
|
||||
that the destination has already been set in the TMTC bridge. */
|
||||
targetTcDestination = tmtcBridge->getRequestQueue();
|
||||
/* The server socket is set up in the bridge intialization. Calling this function here
|
||||
ensures that it is set up regardless of which class was initialized first */
|
||||
this->serverSocket = tmtcBridge->serverSocket;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
|
||||
#ifdef PLATFORM_WIN
|
||||
DWORD timeoutMs = timeoutSeconds * 1000.0;
|
||||
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
|
||||
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
|
||||
if(result == -1) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting "
|
||||
"receive timeout failed with " << strerror(errno) << std::endl;
|
||||
#endif
|
||||
}
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
timeval tval;
|
||||
tval = timevalOperations::toTimeval(timeoutSeconds);
|
||||
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
|
||||
&tval, sizeof(receptionTimeout));
|
||||
if(result == -1) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
|
||||
"receive timeout failed with " << strerror(errno) << std::endl;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
||||
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
||||
#ifndef FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_
|
||||
#define FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_
|
||||
|
||||
#include "TmTcWinUdpBridge.h"
|
||||
#include "UdpTmTcBridge.h"
|
||||
#include "../../objectmanager/SystemObject.h"
|
||||
#include "../../tasks/ExecutableObjectIF.h"
|
||||
#include "../../storagemanager/StorageManagerIF.h"
|
||||
@@ -9,25 +9,25 @@
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief This class can be used to implement the polling of a Unix socket,
|
||||
* using UDP for now.
|
||||
* @brief This class can be used with the UdpTmTcBridge to implement a UDP server
|
||||
* for receiving and sending PUS TMTC.
|
||||
* @details
|
||||
* The task will be blocked while the specified number of bytes has not been
|
||||
* received, so TC reception is handled inside a separate task.
|
||||
* This class caches the IP address of the sender. It is assumed there
|
||||
* is only one sender for now.
|
||||
* 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 TcWinUdpPollingTask: public SystemObject,
|
||||
class UdpTcPollingTask:
|
||||
public TcpIpBase,
|
||||
public SystemObject,
|
||||
public ExecutableObjectIF {
|
||||
friend class TmTcWinUdpBridge;
|
||||
public:
|
||||
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
|
||||
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
|
||||
//! 0.5 default milliseconds timeout for now.
|
||||
static constexpr timeval DEFAULT_TIMEOUT = {0, 500};
|
||||
|
||||
TcWinUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
||||
size_t frameSize = 0, double timeoutSeconds = -1);
|
||||
virtual~ TcWinUdpPollingTask();
|
||||
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
|
||||
size_t maxRecvSize = 0, double timeoutSeconds = -1);
|
||||
virtual~ UdpTcPollingTask();
|
||||
|
||||
/**
|
||||
* Turn on optional timeout for UDP polling. In the default mode,
|
||||
@@ -46,16 +46,10 @@ protected:
|
||||
private:
|
||||
//! TMTC bridge is cached.
|
||||
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
||||
TmTcWinUdpBridge* tmtcBridge = nullptr;
|
||||
UdpTmTcBridge* tmtcBridge = nullptr;
|
||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||
|
||||
//! See: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom
|
||||
int receptionFlags = 0;
|
||||
|
||||
//! Server socket, which is member of TMTC bridge.
|
||||
//! Will be cached shortly after SW intialization.
|
||||
SOCKET serverUdpSocket = 0;
|
||||
|
||||
std::vector<uint8_t> receptionBuffer;
|
||||
|
||||
size_t frameSize = 0;
|
||||
@@ -64,4 +58,4 @@ private:
|
||||
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
||||
#endif /* FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_ */
|
@@ -1,17 +1,26 @@
|
||||
#include "TmTcWinUdpBridge.h"
|
||||
#include "UdpTmTcBridge.h"
|
||||
#include "tcpipHelpers.h"
|
||||
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
#include <fsfw/ipc/MutexGuard.h>
|
||||
#include "../../platform.h"
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
#include "../../ipc/MutexGuard.h"
|
||||
|
||||
#ifdef PLATFORM_WIN
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
//! Debugging preprocessor define.
|
||||
#ifndef FSFW_UDP_SEND_WIRETAPPING_ENABLED
|
||||
#define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0
|
||||
#endif
|
||||
|
||||
const std::string TmTcWinUdpBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_UDP_SERVER_PORT;
|
||||
const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||
|
||||
TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort):
|
||||
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
std::string udpServerPort, object_id_t tmStoreId, object_id_t tcStoreId):
|
||||
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||
if(udpServerPort == "") {
|
||||
this->udpServerPort = DEFAULT_UDP_SERVER_PORT;
|
||||
@@ -24,16 +33,18 @@ TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestinati
|
||||
communicationLinkUp = false;
|
||||
}
|
||||
|
||||
ReturnValue_t TmTcWinUdpBridge::initialize() {
|
||||
ReturnValue_t UdpTmTcBridge::initialize() {
|
||||
ReturnValue_t result = TmTcBridge::initialize();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TmTcWinUdpBridge::initialize: TmTcBridge initialization failed!"
|
||||
sif::error << "UdpTmTcBridge::initialize: TmTcBridge initialization failed!"
|
||||
<< std::endl;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Initiates Winsock DLL. */
|
||||
WSAData wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
@@ -42,25 +53,22 @@ ReturnValue_t TmTcWinUdpBridge::initialize() {
|
||||
/* Tell the user that we could not find a usable */
|
||||
/* Winsock DLL. */
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: WSAStartup failed with error: " <<
|
||||
sif::error << "UdpTmTcBridge::UdpTmTcBridge: WSAStartup failed with error: " <<
|
||||
err << std::endl;
|
||||
#else
|
||||
sif::printError("TmTcWinUdpBridge::TmTcWinUdpBridge: WSAStartup failed with error: %d\n",
|
||||
sif::printError("UdpTmTcBridge::UdpTmTcBridge: WSAStartup failed with error: %d\n",
|
||||
err);
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct addrinfo *addrResult = nullptr;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo hints = {};
|
||||
|
||||
ZeroMemory(&hints, sizeof (hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_protocol = IPPROTO_UDP;
|
||||
/* See:
|
||||
https://docs.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo
|
||||
for information about AI_PASSIVE. */
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
/* Set up UDP socket:
|
||||
@@ -69,55 +77,45 @@ ReturnValue_t TmTcWinUdpBridge::initialize() {
|
||||
getaddrinfo to assign the address 0.0.0.0 (any address) */
|
||||
int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult);
|
||||
if (retval != 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TmTcWinUdpBridge::TmTcWinUdpBridge: Retrieving address info failed!" <<
|
||||
std::endl;
|
||||
#endif
|
||||
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::GETADDRINFO_CALL);
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol);
|
||||
if(serverSocket == INVALID_SOCKET) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not open UDP socket!" <<
|
||||
std::endl;
|
||||
#endif
|
||||
freeaddrinfo(addrResult);
|
||||
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL);
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
#if FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||
tcpip::printAddress(addrResult->ai_addr);
|
||||
#endif
|
||||
|
||||
retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||
if(retval != 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind "
|
||||
"local port (" << udpServerPort << ") to server socket!" << std::endl;
|
||||
#endif
|
||||
freeaddrinfo(addrResult);
|
||||
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL);
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
freeaddrinfo(addrResult);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
TmTcWinUdpBridge::~TmTcWinUdpBridge() {
|
||||
UdpTmTcBridge::~UdpTmTcBridge() {
|
||||
if(mutex != nullptr) {
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
}
|
||||
closesocket(serverSocket);
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||
ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||
int flags = 0;
|
||||
|
||||
/* The target address can be set by different threads so this lock ensures thread-safety */
|
||||
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||
char ipAddress [15];
|
||||
sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
||||
&clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||
#if FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||
tcpip::printAddress(&clientAddress);
|
||||
#endif
|
||||
|
||||
int bytesSent = sendto(
|
||||
@@ -125,33 +123,31 @@ ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||
reinterpret_cast<const char*>(data),
|
||||
dataLen,
|
||||
flags,
|
||||
reinterpret_cast<sockaddr*>(&clientAddress),
|
||||
&clientAddress,
|
||||
clientAddressLen
|
||||
);
|
||||
if(bytesSent == SOCKET_ERROR) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TmTcWinUdpBridge::sendTm: Send operation failed." << std::endl;
|
||||
sif::warning << "TmTcUdpBridge::sendTm: Send operation failed." << std::endl;
|
||||
#endif
|
||||
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL);
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||
sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
|
||||
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent << " bytes were"
|
||||
" sent." << std::endl;
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
|
||||
void UdpTmTcBridge::checkAndSetClientAddress(sockaddr& newAddress) {
|
||||
/* The target address can be set by different threads so this lock ensures thread-safety */
|
||||
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||
char ipAddress [15];
|
||||
sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
||||
&newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||
sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
|
||||
&clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||
#if FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||
tcpip::printAddress(&newAddress);
|
||||
tcpip::printAddress(&clientAddress);
|
||||
#endif
|
||||
|
||||
registerCommConnect();
|
||||
|
||||
/* Set new IP address to reply to */
|
||||
@@ -159,7 +155,7 @@ void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
|
||||
clientAddressLen = sizeof(clientAddress);
|
||||
}
|
||||
|
||||
void TmTcWinUdpBridge::setMutexProperties(MutexIF::TimeoutType timeoutType,
|
||||
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType,
|
||||
dur_millis_t timeoutMs) {
|
||||
this->timeoutType = timeoutType;
|
||||
this->mutexTimeoutMs = timeoutMs;
|
63
osal/common/UdpTmTcBridge.h
Normal file
63
osal/common/UdpTmTcBridge.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_
|
||||
#define FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_
|
||||
|
||||
#include "TcpIpBase.h"
|
||||
#include "../../platform.h"
|
||||
#include "../../tmtcservices/TmTcBridge.h"
|
||||
|
||||
#ifdef PLATFORM_WIN
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief This class can be used with the UdpTcPollingTask to implement a UDP server
|
||||
* 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:
|
||||
public TmTcBridge,
|
||||
public TcpIpBase {
|
||||
friend class UdpTcPollingTask;
|
||||
public:
|
||||
/* The ports chosen here should not be used by any other process. */
|
||||
static const std::string DEFAULT_UDP_SERVER_PORT;
|
||||
|
||||
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
std::string udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
|
||||
object_id_t tcStoreId = objects::TC_STORE);
|
||||
virtual~ UdpTmTcBridge();
|
||||
|
||||
/**
|
||||
* Set properties of internal mutex.
|
||||
*/
|
||||
void setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs);
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
void checkAndSetClientAddress(sockaddr& clientAddress);
|
||||
|
||||
protected:
|
||||
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
||||
|
||||
private:
|
||||
std::string udpServerPort;
|
||||
|
||||
struct sockaddr clientAddress;
|
||||
socklen_t clientAddressLen = 0;
|
||||
|
||||
//! Access to the client address is mutex protected as it is set by another task.
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
dur_millis_t mutexTimeoutMs = 20;
|
||||
MutexIF* mutex;
|
||||
};
|
||||
|
||||
#endif /* FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_ */
|
||||
|
@@ -1,4 +1,9 @@
|
||||
#include "tcpipCommon.h"
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string &protStr,
|
||||
std::string &srcString) {
|
||||
@@ -27,10 +32,53 @@ void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std:
|
||||
else if(errorSrc == ErrorSources::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) {
|
||||
srcString = "getaddrinfo call";
|
||||
}
|
||||
else if(errorSrc == ErrorSources::SHUTDOWN_CALL) {
|
||||
srcString = "shutdown call";
|
||||
}
|
||||
else {
|
||||
srcString = "unknown call";
|
||||
}
|
||||
}
|
||||
|
||||
void tcpip::printAddress(struct sockaddr* addr) {
|
||||
char ipAddress[INET6_ADDRSTRLEN] = {};
|
||||
const char* stringPtr = NULL;
|
||||
switch(addr->sa_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addrIn = reinterpret_cast<struct sockaddr_in*>(addr);
|
||||
stringPtr = inet_ntop(AF_INET, &(addrIn->sin_addr), ipAddress, INET_ADDRSTRLEN);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addrIn = reinterpret_cast<struct sockaddr_in6*>(addr);
|
||||
stringPtr = inet_ntop(AF_INET6, &(addrIn->sin6_addr), ipAddress, INET6_ADDRSTRLEN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
if(stringPtr == NULL) {
|
||||
sif::debug << "Could not convert IP address to text representation, error code "
|
||||
<< errno << std::endl;
|
||||
}
|
||||
else {
|
||||
sif::debug << "IP Address Sender: " << ipAddress << std::endl;
|
||||
}
|
||||
#else
|
||||
if(stringPtr == NULL) {
|
||||
sif::printDebug("Could not convert IP address to text representation, error code %d\n",
|
||||
errno);
|
||||
}
|
||||
else {
|
||||
sif::printDebug("IP Address Sender: %s\n", ipAddress);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@@ -4,10 +4,16 @@
|
||||
#include "../../timemanager/clockDefinitions.h"
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
namespace tcpip {
|
||||
|
||||
const char* const DEFAULT_UDP_SERVER_PORT = "7301";
|
||||
const char* const DEFAULT_TCP_SERVER_PORT = "7303";
|
||||
const char* const DEFAULT_SERVER_PORT = "7301";
|
||||
|
||||
enum class Protocol {
|
||||
UDP,
|
||||
@@ -23,14 +29,16 @@ enum class ErrorSources {
|
||||
RECVFROM_CALL,
|
||||
LISTEN_CALL,
|
||||
ACCEPT_CALL,
|
||||
SENDTO_CALL
|
||||
SEND_CALL,
|
||||
SENDTO_CALL,
|
||||
SHUTDOWN_CALL
|
||||
};
|
||||
|
||||
void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr,
|
||||
std::string& srcString);
|
||||
|
||||
void printAddress(struct sockaddr* addr);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* FSFW_OSAL_COMMON_TCPIPCOMMON_H_ */
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#define FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_
|
||||
|
||||
#include "../../timemanager/clockDefinitions.h"
|
||||
#include "../common/tcpipCommon.h"
|
||||
#include "tcpipCommon.h"
|
||||
|
||||
namespace tcpip {
|
||||
|
@@ -10,6 +10,7 @@ target_sources(${LIB_FSFW_NAME}
|
||||
QueueMapManager.cpp
|
||||
SemaphoreFactory.cpp
|
||||
TaskFactory.cpp
|
||||
taskHelpers.cpp
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
|
@@ -1,10 +1,12 @@
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
#include "../../timemanager/Clock.h"
|
||||
#include "../../platform.h"
|
||||
|
||||
#include <chrono>
|
||||
#if defined(WIN32)
|
||||
|
||||
#if defined(PLATFORM_WIN)
|
||||
#include <sysinfoapi.h>
|
||||
#elif defined(LINUX)
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
@@ -46,7 +48,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
||||
#if defined(WIN32)
|
||||
#if defined(PLATFORM_WIN)
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
||||
auto epoch = now.time_since_epoch();
|
||||
@@ -54,7 +56,7 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
||||
auto fraction = now - secondsChrono;
|
||||
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(fraction).count();
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
#elif defined(LINUX)
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
timespec timeUnix;
|
||||
int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
|
||||
if(status!=0){
|
||||
@@ -85,14 +87,14 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
||||
|
||||
timeval Clock::getUptime() {
|
||||
timeval timeval;
|
||||
#if defined(WIN32)
|
||||
#if defined(PLATFORM_WIN)
|
||||
auto uptime = std::chrono::milliseconds(GetTickCount64());
|
||||
auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime);
|
||||
timeval.tv_sec = secondsChrono.count();
|
||||
auto fraction = uptime - secondsChrono;
|
||||
timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
fraction).count();
|
||||
#elif defined(LINUX)
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
double 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;
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
||||
/* Do some magic with chrono (C++20!) */
|
||||
/* Right now, the library doesn't have the new features to get the required values yet.
|
||||
@@ -170,71 +171,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
||||
/ 3600.;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
|
||||
//SHOULDDO: works not for dates in the past (might have less leap seconds)
|
||||
if (timeMutex == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
uint16_t leapSeconds;
|
||||
ReturnValue_t result = getLeapSeconds(&leapSeconds);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
timeval leapSeconds_timeval = { 0, 0 };
|
||||
leapSeconds_timeval.tv_sec = leapSeconds;
|
||||
|
||||
//initial offset between UTC and TAI
|
||||
timeval UTCtoTAI1972 = { 10, 0 };
|
||||
|
||||
timeval TAItoTT = { 32, 184000 };
|
||||
|
||||
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
|
||||
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
ReturnValue_t result = timeMutex->lockMutex();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
leapSeconds = leapSeconds_;
|
||||
|
||||
result = timeMutex->unlockMutex();
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
||||
if(timeMutex == nullptr){
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
ReturnValue_t result = timeMutex->lockMutex();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
*leapSeconds_ = leapSeconds;
|
||||
|
||||
result = timeMutex->unlockMutex();
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::checkOrCreateClockMutex(){
|
||||
if(timeMutex == nullptr){
|
||||
MutexFactory* mutexFactory = MutexFactory::instance();
|
||||
if (mutexFactory == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
timeMutex = mutexFactory->createMutex();
|
||||
if (timeMutex == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
@@ -1,18 +1,21 @@
|
||||
#include "../../osal/host/FixedTimeslotTask.h"
|
||||
#include "taskHelpers.h"
|
||||
|
||||
#include "../../platform.h"
|
||||
#include "../../osal/host/FixedTimeslotTask.h"
|
||||
#include "../../ipc/MutexFactory.h"
|
||||
#include "../../osal/host/Mutex.h"
|
||||
#include "../../osal/host/FixedTimeslotTask.h"
|
||||
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
#include "../../tasks/ExecutableObjectIF.h"
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#if defined(WIN32)
|
||||
#if defined(PLATFORM_WIN)
|
||||
#include <windows.h>
|
||||
#elif defined(LINUX)
|
||||
#include "../windows/winTaskHelpers.h"
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
@@ -24,34 +27,12 @@ FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
|
||||
// It is propably possible to set task priorities by using the native
|
||||
// task handles for Windows / Linux
|
||||
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
|
||||
#if defined(WIN32)
|
||||
/* List of possible priority classes:
|
||||
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
|
||||
* nf-processthreadsapi-setpriorityclass
|
||||
* And respective thread priority numbers:
|
||||
* https://docs.microsoft.com/en-us/windows/
|
||||
* win32/procthread/scheduling-priorities */
|
||||
int result = SetPriorityClass(
|
||||
reinterpret_cast<HANDLE>(mainThread.native_handle()),
|
||||
ABOVE_NORMAL_PRIORITY_CLASS);
|
||||
if(result != 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
|
||||
<< GetLastError() << std::endl;
|
||||
#endif
|
||||
}
|
||||
result = SetThreadPriority(
|
||||
reinterpret_cast<HANDLE>(mainThread.native_handle()),
|
||||
THREAD_PRIORITY_NORMAL);
|
||||
if(result != 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
|
||||
<< GetLastError() << std::endl;
|
||||
#endif
|
||||
}
|
||||
#elif defined(LINUX)
|
||||
// TODO: we can just copy and paste the code from the linux OSAL here.
|
||||
#if defined(_WIN32)
|
||||
tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
|
||||
#elif defined(__unix__)
|
||||
// TODO: We could reuse existing code here.
|
||||
#endif
|
||||
tasks::insertTaskName(mainThread.get_id(), taskName);
|
||||
}
|
||||
|
||||
FixedTimeslotTask::~FixedTimeslotTask(void) {
|
||||
@@ -60,7 +41,6 @@ FixedTimeslotTask::~FixedTimeslotTask(void) {
|
||||
if(mainThread.joinable()) {
|
||||
mainThread.join();
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
||||
void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
||||
@@ -132,7 +112,7 @@ void FixedTimeslotTask::taskFunctionality() {
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
|
||||
uint32_t slotTimeMs, int8_t executionStep) {
|
||||
ExecutableObjectIF* executableObject = objectManager->
|
||||
ExecutableObjectIF* executableObject = ObjectManager::instance()->
|
||||
get<ExecutableObjectIF>(componentId);
|
||||
if (executableObject != nullptr) {
|
||||
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep,
|
||||
@@ -141,8 +121,11 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
|
||||
}
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Component " << std::hex << componentId <<
|
||||
" not found, not adding it to pst" << std::endl;
|
||||
sif::error << "Component " << std::hex << "0x" << componentId << "not found, "
|
||||
"not adding it to PST.." << std::dec << std::endl;
|
||||
#else
|
||||
sif::printError("Component 0x%08x not found, not adding it to PST..\n",
|
||||
static_cast<unsigned int>(componentId));
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
@@ -1,18 +1,22 @@
|
||||
#include "MessageQueue.h"
|
||||
#include "QueueMapManager.h"
|
||||
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
#include "../../ipc/MutexFactory.h"
|
||||
#include "../../ipc/MutexGuard.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
|
||||
messageSize(maxMessageSize), messageDepth(messageDepth) {
|
||||
queueLock = MutexFactory::instance()->createMutex();
|
||||
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MessageQueue::MessageQueue:"
|
||||
<< " Could not be created" << std::endl;
|
||||
sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl;
|
||||
#else
|
||||
sif::printError("MessageQueue::MessageQueue: Could not be created\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -63,12 +67,9 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||
if(messageQueue.empty()) {
|
||||
return MessageQueueIF::EMPTY;
|
||||
}
|
||||
// not sure this will work..
|
||||
//*message = std::move(messageQueue.front());
|
||||
MutexGuard mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20);
|
||||
MessageQueueMessage* currentMessage = &messageQueue.front();
|
||||
std::copy(currentMessage->getBuffer(),
|
||||
currentMessage->getBuffer() + messageSize, message->getBuffer());
|
||||
std::copy(messageQueue.front().data(), messageQueue.front().data() + messageSize,
|
||||
message->getBuffer());
|
||||
messageQueue.pop();
|
||||
// The last partner is the first uint32_t field in the message
|
||||
this->lastPartner = message->getSender();
|
||||
@@ -82,7 +83,7 @@ MessageQueueId_t MessageQueue::getLastPartner() const {
|
||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||
*count = messageQueue.size();
|
||||
// Clears the queue.
|
||||
messageQueue = std::queue<MessageQueueMessage>();
|
||||
messageQueue = std::queue<std::vector<uint8_t>>();
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
@@ -108,6 +109,9 @@ bool MessageQueue::isDefaultDestinationSet() const {
|
||||
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
||||
bool ignoreFault) {
|
||||
if(message == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
message->setSender(sentFrom);
|
||||
if(message->getMessageSize() > message->getMaximumMessageSize()) {
|
||||
// Actually, this should never happen or an error will be emitted
|
||||
@@ -119,32 +123,19 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||
QueueMapManager::instance()->getMessageQueue(sendTo));
|
||||
if(targetQueue == nullptr) {
|
||||
if(not ignoreFault) {
|
||||
InternalErrorReporterIF* internalErrorReporter =
|
||||
objectManager->get<InternalErrorReporterIF>(
|
||||
objects::INTERNAL_ERROR_REPORTER);
|
||||
InternalErrorReporterIF* internalErrorReporter = ObjectManager::instance()->
|
||||
get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||
if (internalErrorReporter != nullptr) {
|
||||
internalErrorReporter->queueMessageNotSent();
|
||||
}
|
||||
}
|
||||
// TODO: Better returnvalue
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return MessageQueueIF::DESTINATION_INVALID;
|
||||
}
|
||||
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
|
||||
MutexGuard mutexLock(targetQueue->queueLock,
|
||||
MutexIF::TimeoutType::WAITING, 20);
|
||||
// not ideal, works for now though.
|
||||
MessageQueueMessage* mqmMessage =
|
||||
dynamic_cast<MessageQueueMessage*>(message);
|
||||
if(message != nullptr) {
|
||||
targetQueue->messageQueue.push(*mqmMessage);
|
||||
}
|
||||
else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message"
|
||||
"is not MessageQueueMessage!" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
MutexGuard mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20);
|
||||
targetQueue->messageQueue.push(std::vector<uint8_t>(message->getMaximumMessageSize()));
|
||||
memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(),
|
||||
message->getMaximumMessageSize());
|
||||
}
|
||||
else {
|
||||
return MessageQueueIF::FULL;
|
||||
|
@@ -212,20 +212,20 @@ protected:
|
||||
//static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
||||
|
||||
private:
|
||||
std::queue<MessageQueueMessage> messageQueue;
|
||||
std::queue<std::vector<uint8_t>> messageQueue;
|
||||
/**
|
||||
* @brief The class stores the queue id it got assigned.
|
||||
* 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 messageDepth = 0;
|
||||
|
||||
MutexIF* queueLock;
|
||||
|
||||
bool defaultDestinationSet = false;
|
||||
MessageQueueId_t defaultDestination = 0;
|
||||
MessageQueueId_t lastPartner = 0;
|
||||
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
||||
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */
|
||||
|
@@ -1,16 +1,20 @@
|
||||
#include "Mutex.h"
|
||||
#include "PeriodicTask.h"
|
||||
#include "taskHelpers.h"
|
||||
|
||||
#include "../../platform.h"
|
||||
#include "../../ipc/MutexFactory.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
#include "../../tasks/ExecutableObjectIF.h"
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#if defined(WIN32)
|
||||
#if defined(PLATFORM_WIN)
|
||||
#include <processthreadsapi.h>
|
||||
#elif defined(LINUX)
|
||||
#include <fsfw/osal/windows/winTaskHelpers.h>
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
@@ -19,37 +23,15 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
|
||||
void (*setDeadlineMissedFunc)()) :
|
||||
started(false), taskName(name), period(setPeriod),
|
||||
deadlineMissedFunc(setDeadlineMissedFunc) {
|
||||
// It is propably 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
|
||||
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
|
||||
#if defined(WIN32)
|
||||
/* List of possible priority classes:
|
||||
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
|
||||
* nf-processthreadsapi-setpriorityclass
|
||||
* And respective thread priority numbers:
|
||||
* https://docs.microsoft.com/en-us/windows/
|
||||
* win32/procthread/scheduling-priorities */
|
||||
int result = SetPriorityClass(
|
||||
reinterpret_cast<HANDLE>(mainThread.native_handle()),
|
||||
ABOVE_NORMAL_PRIORITY_CLASS);
|
||||
if(result != 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
|
||||
<< GetLastError() << std::endl;
|
||||
#endif
|
||||
}
|
||||
result = SetThreadPriority(
|
||||
reinterpret_cast<HANDLE>(mainThread.native_handle()),
|
||||
THREAD_PRIORITY_NORMAL);
|
||||
if(result != 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
|
||||
<< GetLastError() << std::endl;
|
||||
#endif
|
||||
}
|
||||
#elif defined(LINUX)
|
||||
// we can just copy and paste the code from linux here.
|
||||
#if defined(PLATFORM_WIN)
|
||||
tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
// TODO: We could reuse existing code here.
|
||||
#endif
|
||||
tasks::insertTaskName(mainThread.get_id(), taskName);
|
||||
}
|
||||
|
||||
PeriodicTask::~PeriodicTask(void) {
|
||||
@@ -58,7 +40,6 @@ PeriodicTask::~PeriodicTask(void) {
|
||||
if(mainThread.joinable()) {
|
||||
mainThread.join();
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
||||
void PeriodicTask::taskEntryPoint(void* argument) {
|
||||
@@ -123,7 +104,7 @@ void PeriodicTask::taskFunctionality() {
|
||||
}
|
||||
|
||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
|
||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(
|
||||
object);
|
||||
if (newObject == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
|
@@ -10,53 +10,54 @@ QueueMapManager::QueueMapManager() {
|
||||
mapLock = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
|
||||
QueueMapManager::~QueueMapManager() {
|
||||
MutexFactory::instance()->deleteMutex(mapLock);
|
||||
}
|
||||
|
||||
QueueMapManager* QueueMapManager::instance() {
|
||||
if (mqManagerInstance == nullptr){
|
||||
mqManagerInstance = new QueueMapManager();
|
||||
}
|
||||
return QueueMapManager::mqManagerInstance;
|
||||
if (mqManagerInstance == nullptr){
|
||||
mqManagerInstance = new QueueMapManager();
|
||||
}
|
||||
return QueueMapManager::mqManagerInstance;
|
||||
}
|
||||
|
||||
ReturnValue_t QueueMapManager::addMessageQueue(
|
||||
MessageQueueIF* queueToInsert, MessageQueueId_t* id) {
|
||||
/* Not thread-safe, but it is assumed all message queues are created at software initialization
|
||||
now. If this is to be made thread-safe in the future, it propably would be sufficient to lock
|
||||
the increment operation here. */
|
||||
uint32_t currentId = queueCounter++;
|
||||
auto returnPair = queueMap.emplace(currentId, queueToInsert);
|
||||
if(not returnPair.second) {
|
||||
/* This should never happen for the atomic variable. */
|
||||
MessageQueueIF* queueToInsert, MessageQueueId_t* id) {
|
||||
MutexGuard lock(mapLock);
|
||||
uint32_t currentId = queueCounter++;
|
||||
auto returnPair = queueMap.emplace(currentId, queueToInsert);
|
||||
if(not returnPair.second) {
|
||||
/* This should never happen for the atomic variable. */
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "QueueMapManager::addMessageQueue This ID is already "
|
||||
"inside the map!" << std::endl;
|
||||
sif::error << "QueueMapManager::addMessageQueue This ID is already "
|
||||
"inside the map!" << std::endl;
|
||||
#else
|
||||
sif::printError("QueueMapManager::addMessageQueue This ID is already "
|
||||
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;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
if (id != nullptr) {
|
||||
*id = currentId;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
MessageQueueIF* QueueMapManager::getMessageQueue(
|
||||
MessageQueueId_t messageQueueId) const {
|
||||
MutexGuard(mapLock, MutexIF::TimeoutType::WAITING, 50);
|
||||
auto queueIter = queueMap.find(messageQueueId);
|
||||
if(queueIter != queueMap.end()) {
|
||||
return queueIter->second;
|
||||
}
|
||||
else {
|
||||
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;
|
||||
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);
|
||||
sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n",
|
||||
messageQueueId);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@@ -15,31 +15,36 @@ using QueueMap = std::unordered_map<MessageQueueId_t, MessageQueueIF*>;
|
||||
*/
|
||||
class QueueMapManager {
|
||||
public:
|
||||
//! Returns the single instance of SemaphoreFactory.
|
||||
static QueueMapManager* instance();
|
||||
|
||||
/**
|
||||
* Insert a message queue into the map and returns a message queue ID
|
||||
* @param queue The message queue to insert.
|
||||
* @param id The passed value will be set unless a nullptr is passed
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t*
|
||||
id = nullptr);
|
||||
/**
|
||||
* Get the message queue handle by providing a message queue ID.
|
||||
* @param messageQueueId
|
||||
* @return
|
||||
*/
|
||||
MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const;
|
||||
|
||||
//! Returns the single instance of QueueMapManager.
|
||||
static QueueMapManager* instance();
|
||||
|
||||
/**
|
||||
* Insert a message queue into the map and returns a message queue ID
|
||||
* @param queue The message queue to insert.
|
||||
* @param id The passed value will be set unless a nullptr is passed
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t*
|
||||
id = nullptr);
|
||||
/**
|
||||
* 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:
|
||||
//! External instantiation is forbidden.
|
||||
QueueMapManager();
|
||||
uint32_t queueCounter = 0;
|
||||
MutexIF* mapLock;
|
||||
QueueMap queueMap;
|
||||
static QueueMapManager* mqManagerInstance;
|
||||
//! External instantiation is forbidden. Constructor still required for singleton instantiation.
|
||||
QueueMapManager();
|
||||
~QueueMapManager();
|
||||
|
||||
uint32_t queueCounter = 0;
|
||||
MutexIF* mapLock;
|
||||
QueueMap queueMap;
|
||||
static QueueMapManager* mqManagerInstance;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -1,14 +1,16 @@
|
||||
#include "taskHelpers.h"
|
||||
#include "../../tasks/TaskFactory.h"
|
||||
#include "../../osal/host/FixedTimeslotTask.h"
|
||||
#include "../../osal/host/PeriodicTask.h"
|
||||
#include "../../tasks/TaskFactory.h"
|
||||
#include "../../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "../../tasks/PeriodicTaskIF.h"
|
||||
#include "../../serviceinterface/ServiceInterface.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
||||
|
||||
// Will propably not be used for hosted implementation
|
||||
// Not used for the host implementation for now because C++ thread abstraction is used
|
||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
|
||||
|
||||
TaskFactory::TaskFactory() {
|
||||
@@ -49,8 +51,12 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
|
||||
}
|
||||
|
||||
void TaskFactory::printMissedDeadline() {
|
||||
/* TODO: Implement */
|
||||
return;
|
||||
std::string name = tasks::getTaskName(std::this_thread::get_id());
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TaskFactory::printMissedDeadline: " << name << std::endl;
|
||||
#else
|
||||
sif::printWarning("TaskFactory::printMissedDeadline: %s\n", name);
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
}
|
||||
|
||||
|
||||
|
27
osal/host/taskHelpers.cpp
Normal file
27
osal/host/taskHelpers.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "taskHelpers.h"
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
std::mutex nameMapLock;
|
||||
std::map<std::thread::id, std::string> taskNameMap;
|
||||
|
||||
ReturnValue_t tasks::insertTaskName(std::thread::id threadId, std::string taskName) {
|
||||
std::lock_guard<std::mutex> lg(nameMapLock);
|
||||
auto returnPair = taskNameMap.emplace(threadId, taskName);
|
||||
if(not returnPair.second) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
std::string tasks::getTaskName(std::thread::id threadId) {
|
||||
std::lock_guard<std::mutex> lg(nameMapLock);
|
||||
auto resultIter = taskNameMap.find(threadId);
|
||||
if(resultIter != taskNameMap.end()) {
|
||||
return resultIter->second;
|
||||
}
|
||||
else {
|
||||
return "Unknown task";
|
||||
}
|
||||
}
|
||||
|
16
osal/host/taskHelpers.h
Normal file
16
osal/host/taskHelpers.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef FSFW_OSAL_HOST_TASKHELPERS_H_
|
||||
#define FSFW_OSAL_HOST_TASKHELPERS_H_
|
||||
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
#include <thread>
|
||||
|
||||
namespace tasks {
|
||||
|
||||
ReturnValue_t insertTaskName(std::thread::id threadId, std::string taskName);
|
||||
std::string getTaskName(std::thread::id threadId);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* FSFW_OSAL_HOST_TASKHELPERS_H_ */
|
@@ -1,4 +1,5 @@
|
||||
#include "BinarySemaphore.h"
|
||||
#include "unixUtility.h"
|
||||
#include "../../serviceinterface/ServiceInterfacePrinter.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
|
||||
@@ -8,154 +9,154 @@
|
||||
|
||||
|
||||
BinarySemaphore::BinarySemaphore() {
|
||||
// Using unnamed semaphores for now
|
||||
initSemaphore();
|
||||
// Using unnamed semaphores for now
|
||||
initSemaphore();
|
||||
}
|
||||
|
||||
BinarySemaphore::~BinarySemaphore() {
|
||||
sem_destroy(&handle);
|
||||
sem_destroy(&handle);
|
||||
}
|
||||
|
||||
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
|
||||
initSemaphore();
|
||||
initSemaphore();
|
||||
}
|
||||
|
||||
BinarySemaphore& BinarySemaphore::operator =(
|
||||
BinarySemaphore&& s) {
|
||||
initSemaphore();
|
||||
return * this;
|
||||
initSemaphore();
|
||||
return * this;
|
||||
}
|
||||
|
||||
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
|
||||
uint32_t timeoutMs) {
|
||||
int result = 0;
|
||||
if(timeoutType == TimeoutType::POLLING) {
|
||||
result = sem_trywait(&handle);
|
||||
}
|
||||
else if(timeoutType == TimeoutType::BLOCKING) {
|
||||
result = sem_wait(&handle);
|
||||
}
|
||||
else if(timeoutType == TimeoutType::WAITING){
|
||||
timespec timeOut;
|
||||
clock_gettime(CLOCK_REALTIME, &timeOut);
|
||||
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
|
||||
nseconds += timeoutMs * 1000000;
|
||||
timeOut.tv_sec = nseconds / 1000000000;
|
||||
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
|
||||
result = sem_timedwait(&handle, &timeOut);
|
||||
if(result != 0 and errno == EINVAL) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "BinarySemaphore::acquire: Invalid time value possible"
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if(result == 0) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
uint32_t timeoutMs) {
|
||||
int result = 0;
|
||||
if(timeoutType == TimeoutType::POLLING) {
|
||||
result = sem_trywait(&handle);
|
||||
}
|
||||
else if(timeoutType == TimeoutType::BLOCKING) {
|
||||
result = sem_wait(&handle);
|
||||
}
|
||||
else if(timeoutType == TimeoutType::WAITING){
|
||||
timespec timeOut;
|
||||
clock_gettime(CLOCK_REALTIME, &timeOut);
|
||||
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
|
||||
nseconds += timeoutMs * 1000000;
|
||||
timeOut.tv_sec = nseconds / 1000000000;
|
||||
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
|
||||
result = sem_timedwait(&handle, &timeOut);
|
||||
if(result != 0 and errno == EINVAL) {
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "sem_timedwait");
|
||||
}
|
||||
}
|
||||
if(result == 0) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
switch(errno) {
|
||||
case(EAGAIN):
|
||||
// Operation could not be performed without blocking (for sem_trywait)
|
||||
case(ETIMEDOUT):
|
||||
// Semaphore is 0
|
||||
return SemaphoreIF::SEMAPHORE_TIMEOUT;
|
||||
case(EINVAL):
|
||||
// Semaphore invalid
|
||||
return SemaphoreIF::SEMAPHORE_INVALID;
|
||||
case(EINTR):
|
||||
// Call was interrupted by signal handler
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "BinarySemaphore::acquire: Signal handler interrupted."
|
||||
"Code " << strerror(errno) << std::endl;
|
||||
#endif
|
||||
/* No break */
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
switch(errno) {
|
||||
case(EAGAIN):
|
||||
// Operation could not be performed without blocking (for sem_trywait)
|
||||
case(ETIMEDOUT): {
|
||||
// Semaphore is 0
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "ETIMEDOUT");
|
||||
return SemaphoreIF::SEMAPHORE_TIMEOUT;
|
||||
}
|
||||
case(EINVAL): {
|
||||
// Semaphore invalid
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "EINVAL");
|
||||
return SemaphoreIF::SEMAPHORE_INVALID;
|
||||
}
|
||||
case(EINTR): {
|
||||
// Call was interrupted by signal handler
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "EINTR");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t BinarySemaphore::release() {
|
||||
return BinarySemaphore::release(&this->handle);
|
||||
return BinarySemaphore::release(&this->handle);
|
||||
}
|
||||
|
||||
ReturnValue_t BinarySemaphore::release(sem_t *handle) {
|
||||
ReturnValue_t countResult = checkCount(handle, 1);
|
||||
if(countResult != HasReturnvaluesIF::RETURN_OK) {
|
||||
return countResult;
|
||||
}
|
||||
ReturnValue_t countResult = checkCount(handle, 1);
|
||||
if(countResult != HasReturnvaluesIF::RETURN_OK) {
|
||||
return countResult;
|
||||
}
|
||||
|
||||
int result = sem_post(handle);
|
||||
if(result == 0) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
int result = sem_post(handle);
|
||||
if(result == 0) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
switch(errno) {
|
||||
case(EINVAL):
|
||||
// Semaphore invalid
|
||||
return SemaphoreIF::SEMAPHORE_INVALID;
|
||||
case(EOVERFLOW):
|
||||
// SEM_MAX_VALUE overflow. This should never happen
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
switch(errno) {
|
||||
case(EINVAL): {
|
||||
// Semaphore invalid
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "release", "EINVAL");
|
||||
return SemaphoreIF::SEMAPHORE_INVALID;
|
||||
}
|
||||
case(EOVERFLOW): {
|
||||
// SEM_MAX_VALUE overflow. This should never happen
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "release", "EOVERFLOW");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t BinarySemaphore::getSemaphoreCounter() const {
|
||||
// And another ugly cast :-D
|
||||
return getSemaphoreCounter(const_cast<sem_t*>(&this->handle));
|
||||
// And another ugly cast :-D
|
||||
return getSemaphoreCounter(const_cast<sem_t*>(&this->handle));
|
||||
}
|
||||
|
||||
uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) {
|
||||
int value = 0;
|
||||
int result = sem_getvalue(handle, &value);
|
||||
if (result == 0) {
|
||||
return value;
|
||||
}
|
||||
else if(result != 0 and errno == EINVAL) {
|
||||
// Could be called from interrupt, use lightweight printf
|
||||
sif::printError("BinarySemaphore::getSemaphoreCounter: "
|
||||
"Invalid semaphore\n");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
// This should never happen.
|
||||
return 0;
|
||||
}
|
||||
int value = 0;
|
||||
int result = sem_getvalue(handle, &value);
|
||||
if (result == 0) {
|
||||
return value;
|
||||
}
|
||||
else if(result != 0 and errno == EINVAL) {
|
||||
// Could be called from interrupt, use lightweight printf
|
||||
sif::printError("BinarySemaphore::getSemaphoreCounter: "
|
||||
"Invalid semaphore\n");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
// This should never happen.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void BinarySemaphore::initSemaphore(uint8_t initCount) {
|
||||
auto result = sem_init(&handle, true, initCount);
|
||||
if(result == -1) {
|
||||
switch(errno) {
|
||||
case(EINVAL):
|
||||
// Value exceeds SEM_VALUE_MAX
|
||||
case(ENOSYS): {
|
||||
// System does not support process-shared semaphores
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "BinarySemaphore: Init failed with "
|
||||
<< strerror(errno) << std::endl;
|
||||
#else
|
||||
sif::printError("BinarySemaphore: Init failed with %s\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
auto result = sem_init(&handle, true, initCount);
|
||||
if(result == -1) {
|
||||
switch(errno) {
|
||||
case(EINVAL): {
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "initSemaphore", "EINVAL");
|
||||
break;
|
||||
}
|
||||
case(ENOSYS): {
|
||||
// System does not support process-shared semaphores
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "initSemaphore", "ENOSYS");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) {
|
||||
int value = getSemaphoreCounter(handle);
|
||||
if(value >= maxCount) {
|
||||
if(maxCount == 1 and value > 1) {
|
||||
// Binary Semaphore special case.
|
||||
// This is a config error use lightweight printf is this is called
|
||||
// from an interrupt
|
||||
printf("BinarySemaphore::release: Value of binary semaphore greater"
|
||||
" than 1!\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
int value = getSemaphoreCounter(handle);
|
||||
if(value >= maxCount) {
|
||||
if(maxCount == 1 and value > 1) {
|
||||
// Binary Semaphore special case.
|
||||
// This is a config error use lightweight printf is this is called
|
||||
// from an interrupt
|
||||
printf("BinarySemaphore::release: Value of binary semaphore greater than 1!\n");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
@@ -76,6 +76,7 @@ public:
|
||||
static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount);
|
||||
protected:
|
||||
sem_t handle;
|
||||
static constexpr const char* CLASS_NAME = "BinarySemaphore";
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user