moved examples modules to fsfw
This commit is contained in:
parent
c0d560afe4
commit
6978869a42
|
@ -9,7 +9,7 @@ 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_ADD_INTEGRATION_TEST_MODULES "Add modules which can be used for integration tests" OFF)
|
||||
option(FSFW_ADD_EXAMPLES "Add example modules which can also be used as test code" OFF)
|
||||
option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON)
|
||||
option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF)
|
||||
option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON)
|
||||
|
@ -30,6 +30,10 @@ set(LIB_FSFW_NAME fsfw)
|
|||
add_library(${LIB_FSFW_NAME})
|
||||
set(FSFW_CORE_INC_PATH "inc")
|
||||
|
||||
if(FSFW_ADD_EXAMPLES)
|
||||
configure_file(examples/fsfw_examples/config/ExampleConfig.h.in ExampleConfig.h)
|
||||
endif()
|
||||
|
||||
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
|
||||
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
|
@ -93,6 +97,9 @@ add_subdirectory(tests)
|
|||
if(FSFW_ADD_HAL)
|
||||
add_subdirectory(hal)
|
||||
endif()
|
||||
if(FSFW_ADD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
add_subdirectory(contrib)
|
||||
|
||||
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
|
||||
|
|
9
examples/CMakeLists.txt
Normal file
9
examples/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
add_subdirectory(fsfw_examples)
|
||||
|
||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
7
examples/fsfw_examples/CMakeLists.txt
Normal file
7
examples/fsfw_examples/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
add_subdirectory(devices)
|
||||
add_subdirectory(controller)
|
||||
add_subdirectory(config)
|
||||
add_subdirectory(assemblies)
|
||||
add_subdirectory(utility)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(core)
|
3
examples/fsfw_examples/assemblies/CMakeLists.txt
Normal file
3
examples/fsfw_examples/assemblies/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
target_sources(${TARGET_NAME} PRIVATE
|
||||
TestAssembly.cpp
|
||||
)
|
200
examples/fsfw_examples/assemblies/TestAssembly.cpp
Normal file
200
examples/fsfw_examples/assemblies/TestAssembly.cpp
Normal file
|
@ -0,0 +1,200 @@
|
|||
#include "exampleObjectIds.h"
|
||||
|
||||
#include <fsfw_examples/assemblies/TestAssembly.h>
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
|
||||
|
||||
TestAssembly::TestAssembly(object_id_t objectId, object_id_t parentId):
|
||||
AssemblyBase(objectId, parentId) {
|
||||
ModeListEntry newModeListEntry;
|
||||
newModeListEntry.setObject(objects::TEST_DEVICE_HANDLER_0);
|
||||
newModeListEntry.setMode(MODE_OFF);
|
||||
newModeListEntry.setSubmode(SUBMODE_NONE);
|
||||
|
||||
commandTable.insert(newModeListEntry);
|
||||
|
||||
newModeListEntry.setObject(objects::TEST_DEVICE_HANDLER_1);
|
||||
newModeListEntry.setMode(MODE_OFF);
|
||||
newModeListEntry.setSubmode(SUBMODE_NONE);
|
||||
|
||||
commandTable.insert(newModeListEntry);
|
||||
|
||||
}
|
||||
|
||||
TestAssembly::~TestAssembly() {
|
||||
}
|
||||
|
||||
ReturnValue_t TestAssembly::commandChildren(Mode_t mode,
|
||||
Submode_t submode) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestAssembly: Received command to go to mode " << mode <<
|
||||
" submode " << (int) submode << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestAssembly: Received command to go to mode %d submode %d\n", mode, submode);
|
||||
#endif
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
if(mode == MODE_OFF){
|
||||
commandTable[0].setMode(MODE_OFF);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
commandTable[1].setMode(MODE_OFF);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
}
|
||||
else if(mode == DeviceHandlerIF::MODE_NORMAL) {
|
||||
if(submode == submodes::SINGLE){
|
||||
commandTable[0].setMode(MODE_OFF);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
commandTable[1].setMode(MODE_OFF);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
// We try to prefer 0 here but we try to switch to 1 even if it might fail
|
||||
if(isDeviceAvailable(objects::TEST_DEVICE_HANDLER_0)) {
|
||||
if (childrenMap[objects::TEST_DEVICE_HANDLER_0].mode == MODE_ON) {
|
||||
commandTable[0].setMode(mode);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
}
|
||||
else {
|
||||
commandTable[0].setMode(MODE_ON);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
result = NEED_SECOND_STEP;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (childrenMap[objects::TEST_DEVICE_HANDLER_1].mode == MODE_ON) {
|
||||
commandTable[1].setMode(mode);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
}
|
||||
else{
|
||||
commandTable[1].setMode(MODE_ON);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
result = NEED_SECOND_STEP;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
// Dual Mode Normal
|
||||
if (childrenMap[objects::TEST_DEVICE_HANDLER_0].mode == MODE_ON) {
|
||||
commandTable[0].setMode(mode);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
}
|
||||
else{
|
||||
commandTable[0].setMode(MODE_ON);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
result = NEED_SECOND_STEP;
|
||||
}
|
||||
if (childrenMap[objects::TEST_DEVICE_HANDLER_1].mode == MODE_ON) {
|
||||
commandTable[1].setMode(mode);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
}
|
||||
else{
|
||||
commandTable[1].setMode(MODE_ON);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
result = NEED_SECOND_STEP;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
//Mode ON
|
||||
if(submode == submodes::SINGLE){
|
||||
commandTable[0].setMode(MODE_OFF);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
commandTable[1].setMode(MODE_OFF);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
// We try to prefer 0 here but we try to switch to 1 even if it might fail
|
||||
if(isDeviceAvailable(objects::TEST_DEVICE_HANDLER_0)){
|
||||
commandTable[0].setMode(MODE_ON);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
}
|
||||
else{
|
||||
commandTable[1].setMode(MODE_ON);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
}
|
||||
}
|
||||
else{
|
||||
commandTable[0].setMode(MODE_ON);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
commandTable[1].setMode(MODE_ON);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
HybridIterator<ModeListEntry> iter(commandTable.begin(),
|
||||
commandTable.end());
|
||||
executeTable(iter);
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t TestAssembly::isModeCombinationValid(Mode_t mode,
|
||||
Submode_t submode) {
|
||||
switch (mode) {
|
||||
case MODE_OFF:
|
||||
if (submode == SUBMODE_NONE) {
|
||||
return RETURN_OK;
|
||||
} else {
|
||||
return INVALID_SUBMODE;
|
||||
}
|
||||
case DeviceHandlerIF::MODE_NORMAL:
|
||||
case MODE_ON:
|
||||
if (submode < 3) {
|
||||
return RETURN_OK;
|
||||
} else {
|
||||
return INVALID_SUBMODE;
|
||||
}
|
||||
}
|
||||
return INVALID_MODE;
|
||||
}
|
||||
|
||||
ReturnValue_t TestAssembly::initialize() {
|
||||
ReturnValue_t result = AssemblyBase::initialize();
|
||||
if(result != RETURN_OK){
|
||||
return result;
|
||||
}
|
||||
handler0 = ObjectManager::instance()->get<TestDevice>(objects::TEST_DEVICE_HANDLER_0);
|
||||
handler1 = ObjectManager::instance()->get<TestDevice>(objects::TEST_DEVICE_HANDLER_1);
|
||||
if((handler0 == nullptr) or (handler1 == nullptr)){
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
handler0->setParentQueue(this->getCommandQueue());
|
||||
handler1->setParentQueue(this->getCommandQueue());
|
||||
|
||||
|
||||
result = registerChild(objects::TEST_DEVICE_HANDLER_0);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = registerChild(objects::TEST_DEVICE_HANDLER_1);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t TestAssembly::checkChildrenStateOn(
|
||||
Mode_t wantedMode, Submode_t wantedSubmode) {
|
||||
if(submode == submodes::DUAL){
|
||||
for(const auto& info:childrenMap) {
|
||||
if(info.second.mode != wantedMode or info.second.mode != wantedSubmode){
|
||||
return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
else if(submode == submodes::SINGLE) {
|
||||
for(const auto& info:childrenMap) {
|
||||
if(info.second.mode == wantedMode and info.second.mode != wantedSubmode){
|
||||
return RETURN_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return INVALID_SUBMODE;
|
||||
}
|
||||
|
||||
bool TestAssembly::isDeviceAvailable(object_id_t object) {
|
||||
if(healthHelper.healthTable->getHealth(object) == HasHealthIF::HEALTHY){
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
return false;
|
||||
}
|
||||
}
|
53
examples/fsfw_examples/assemblies/TestAssembly.h
Normal file
53
examples/fsfw_examples/assemblies/TestAssembly.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef MISSION_ASSEMBLIES_TESTASSEMBLY_H_
|
||||
#define MISSION_ASSEMBLIES_TESTASSEMBLY_H_
|
||||
|
||||
#include <fsfw/devicehandlers/AssemblyBase.h>
|
||||
#include "fsfw_examples/devices/TestDeviceHandler.h"
|
||||
|
||||
class TestAssembly: public AssemblyBase {
|
||||
public:
|
||||
TestAssembly(object_id_t objectId, object_id_t parentId);
|
||||
virtual ~TestAssembly();
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
enum submodes: Submode_t{
|
||||
SINGLE = 0,
|
||||
DUAL = 1
|
||||
};
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Command children to reach [mode,submode] combination
|
||||
* Can be done by setting #commandsOutstanding correctly,
|
||||
* or using executeTable()
|
||||
* @param mode
|
||||
* @param submode
|
||||
* @return
|
||||
* - @c RETURN_OK if ok
|
||||
* - @c NEED_SECOND_STEP if children need to be commanded again
|
||||
*/
|
||||
ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override;
|
||||
/**
|
||||
* Check whether desired assembly mode was achieved by checking the modes
|
||||
* or/and health states of child device handlers.
|
||||
* The assembly template class will also call this function if a health
|
||||
* or mode change of a child device handler was detected.
|
||||
* @param wantedMode
|
||||
* @param wantedSubmode
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode)
|
||||
override;
|
||||
|
||||
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode,
|
||||
Submode_t wantedSubmode) override;
|
||||
private:
|
||||
FixedArrayList<ModeListEntry, 2> commandTable;
|
||||
TestDevice* handler0 = nullptr;
|
||||
TestDevice* handler1 = nullptr;
|
||||
|
||||
|
||||
bool isDeviceAvailable(object_id_t object);
|
||||
};
|
||||
|
||||
#endif /* MISSION_ASSEMBLIES_TESTASSEMBLY_H_ */
|
11
examples/fsfw_examples/config/CMakeLists.txt
Normal file
11
examples/fsfw_examples/config/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
examplePollingSequenceFactory.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
67
examples/fsfw_examples/config/ExampleConfig.h.in
Normal file
67
examples/fsfw_examples/config/ExampleConfig.h.in
Normal file
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* @brief This file will contain configuration constants which are used across all BSPs
|
||||
*/
|
||||
#ifndef COMMON_COMMONCONFIG_H_
|
||||
#define COMMON_COMMONCONFIG_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//! Specify the debug output verbose level
|
||||
#define OBSW_VERBOSE_LEVEL 1
|
||||
|
||||
#define OBSW_PRINT_MISSED_DEADLINES 0
|
||||
|
||||
//! Perform internal unit testd at application startup
|
||||
#define OBSW_PERFORM_INTERNAL_UNITTEST 1
|
||||
|
||||
//! Add core components for the FSFW and for TMTC communication
|
||||
#define OBSW_ADD_CORE_COMPONENTS 1
|
||||
|
||||
//! Add the PUS service stack
|
||||
#define OBSW_ADD_PUS_STACK 1
|
||||
#define OBSW_PUS_PRINTOUT 0
|
||||
|
||||
//! Add the task examples
|
||||
#define OBSW_ADD_TASK_EXAMPLE 1
|
||||
#define OBSW_TASK_EXAMPLE_PRINTOUT 0
|
||||
|
||||
//! Add the demo device handler object
|
||||
#define OBSW_ADD_DEVICE_HANDLER_DEMO 1
|
||||
#define OBSW_DEVICE_HANDLER_PRINTOUT 1
|
||||
|
||||
//! Add the demo controller object
|
||||
#define OBSW_ADD_CONTROLLER_DEMO 1
|
||||
#define OBSW_CONTROLLER_PRINTOUT 1
|
||||
|
||||
/**
|
||||
* The APID is a 14 bit identifier which can be used to distinguish processes and applications
|
||||
* on a spacecraft. For more details, see the related ECSS/CCSDS standards.
|
||||
* For this example, we are going to use a constant APID
|
||||
*/
|
||||
static const uint16_t COMMON_APID = 0xEF;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <fsfw/events/fwSubsystemIdRanges.h>
|
||||
#include <fsfw/returnvalues/FwClassIds.h>
|
||||
|
||||
/**
|
||||
* Enumerations for used PUS service IDs.
|
||||
*/
|
||||
namespace pus {
|
||||
enum ServiceIds: uint8_t {
|
||||
PUS_SERVICE_1 = 1,
|
||||
PUS_SERVICE_2 = 2,
|
||||
PUS_SERVICE_3 = 3,
|
||||
PUS_SERVICE_5 = 5,
|
||||
PUS_SERVICE_8 = 8,
|
||||
PUS_SERVICE_9 = 9,
|
||||
PUS_SERVICE_17 = 17,
|
||||
PUS_SERVICE_20 = 20,
|
||||
PUS_SERVICE_200 = 200
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* COMMON_COMMONCONFIG_H_ */
|
14
examples/fsfw_examples/config/exampleClassIds.h
Normal file
14
examples/fsfw_examples/config/exampleClassIds.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef COMMON_CONFIG_COMMONCLASSIDS_H_
|
||||
#define COMMON_CONFIG_COMMONCLASSIDS_H_
|
||||
|
||||
#include "fsfw/returnvalues/FwClassIds.h"
|
||||
|
||||
namespace CLASS_ID {
|
||||
enum commonClassIds: uint8_t {
|
||||
COMMON_CLASS_ID_START = FW_CLASS_ID_COUNT,
|
||||
DUMMY_HANDLER, //DDH
|
||||
COMMON_CLASS_ID_END // [EXPORT] : [END]
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* COMMON_CONFIG_COMMONCLASSIDS_H_ */
|
32
examples/fsfw_examples/config/exampleObjectIds.h
Normal file
32
examples/fsfw_examples/config/exampleObjectIds.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef COMMON_COMMONSYSTEMOBJECTS_H_
|
||||
#define COMMON_COMMONSYSTEMOBJECTS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||
|
||||
namespace objects {
|
||||
enum commonObjects: object_id_t {
|
||||
|
||||
EXAMPLE_OBJECTS_START = FSFW_OBJECTS_END,
|
||||
// 0x54 reserved for example objects
|
||||
|
||||
TEST_ASSEMBLY = 0x5400CAFE,
|
||||
TEST_CONTROLLER = 0x5401CAFE,
|
||||
TEST_DEVICE_HANDLER_0 = 0x5401AFFE,
|
||||
TEST_DEVICE_HANDLER_1 = 0x5402AFFE,
|
||||
TEST_ECHO_COM_IF = 0x5400AFFE,
|
||||
CCSDS_DISTRIBUTOR = 0x54000000,
|
||||
PUS_DISTRIBUTOR = 0x54000001,
|
||||
TM_FUNNEL = 0x54030002,
|
||||
TEST_TASK = 0x5402CAFE,
|
||||
TEST_DUMMY_1 = 0x54000101,
|
||||
TEST_DUMMY_2 = 0x54000102,
|
||||
TEST_DUMMY_3= 0x54000103,
|
||||
TEST_DUMMY_4 = 0x54000104,
|
||||
TEST_DUMMY_5 = 0x54000105,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* COMMON_COMMONSYSTEMOBJECTS_H_ */
|
|
@ -0,0 +1,82 @@
|
|||
#include "exampleObjectIds.h"
|
||||
#include "pollingsequence/pollingSequenceFactory.h"
|
||||
#include "fsfw_examples/test/FsfwExampleTask.h"
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
|
||||
|
||||
|
||||
ReturnValue_t pst::pollingSequenceExamples(FixedTimeslotTaskIF* thisSequence) {
|
||||
uint32_t length = thisSequence->getPeriodMs();
|
||||
|
||||
thisSequence->addSlot(objects::TEST_DUMMY_1, length * 0,
|
||||
FsfwExampleTask::OpCodes::SEND_RAND_NUM);
|
||||
thisSequence->addSlot(objects::TEST_DUMMY_2, length * 0,
|
||||
FsfwExampleTask::OpCodes::SEND_RAND_NUM);
|
||||
thisSequence->addSlot(objects::TEST_DUMMY_3, length * 0,
|
||||
FsfwExampleTask::OpCodes::SEND_RAND_NUM);
|
||||
|
||||
thisSequence->addSlot(objects::TEST_DUMMY_1, length * 0.2,
|
||||
FsfwExampleTask::OpCodes::RECEIVE_RAND_NUM);
|
||||
thisSequence->addSlot(objects::TEST_DUMMY_2, length * 0.2,
|
||||
FsfwExampleTask::OpCodes::RECEIVE_RAND_NUM);
|
||||
thisSequence->addSlot(objects::TEST_DUMMY_3, length * 0.2,
|
||||
FsfwExampleTask::OpCodes::RECEIVE_RAND_NUM);
|
||||
|
||||
thisSequence->addSlot(objects::TEST_DUMMY_1, length * 0.5,
|
||||
FsfwExampleTask::OpCodes::DELAY_SHORT);
|
||||
thisSequence->addSlot(objects::TEST_DUMMY_2, length * 0.5,
|
||||
FsfwExampleTask::OpCodes::DELAY_SHORT);
|
||||
thisSequence->addSlot(objects::TEST_DUMMY_3, length * 0.5,
|
||||
FsfwExampleTask::OpCodes::DELAY_SHORT);
|
||||
|
||||
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "pst::pollingSequenceInitFunction: Initialization errors!" << std::endl;
|
||||
#else
|
||||
sif::printError("pst::pollingSequenceInitFunction: Initialization errors!\n");
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t pst::pollingSequenceDevices(FixedTimeslotTaskIF *thisSequence) {
|
||||
uint32_t length = thisSequence->getPeriodMs();
|
||||
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_0, 0, DeviceHandlerIF::PERFORM_OPERATION);
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_1, 0, DeviceHandlerIF::PERFORM_OPERATION);
|
||||
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_0, 0.3, DeviceHandlerIF::SEND_WRITE);
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_1, 0.3, DeviceHandlerIF::SEND_WRITE);
|
||||
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_0, 0.45 * length,
|
||||
DeviceHandlerIF::GET_WRITE);
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_1, 0.45 * length,
|
||||
DeviceHandlerIF::GET_WRITE);
|
||||
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_0, 0.6 * length, DeviceHandlerIF::SEND_READ);
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_1, 0.6 * length, DeviceHandlerIF::SEND_READ);
|
||||
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_0, 0.8 * length, DeviceHandlerIF::GET_READ);
|
||||
thisSequence->addSlot(objects::TEST_DEVICE_HANDLER_1, 0.8 * length, DeviceHandlerIF::GET_READ);
|
||||
|
||||
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "pst::pollingSequenceTestFunction: Initialization errors!" << std::endl;
|
||||
#else
|
||||
sif::printError("pst::pollingSequenceTestFunction: Initialization errors!\n");
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
15
examples/fsfw_examples/config/exampleSubsystemIds.h
Normal file
15
examples/fsfw_examples/config/exampleSubsystemIds.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COMMON_CONFIG_COMMONSUBSYSTEMIDS_H_
|
||||
#define COMMON_CONFIG_COMMONSUBSYSTEMIDS_H_
|
||||
|
||||
#include "fsfw/events/fwSubsystemIdRanges.h"
|
||||
|
||||
namespace SUBSYSTEM_ID {
|
||||
enum commonSubsystemId: uint8_t {
|
||||
EXAMPLE_SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE,
|
||||
TEST_TASK_ID,
|
||||
EXAMPLE_SUBSYSTEM_ID_END
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /* COMMON_CONFIG_COMMONSUBSYSTEMIDS_H_ */
|
3
examples/fsfw_examples/core/CMakeLists.txt
Normal file
3
examples/fsfw_examples/core/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
GenericFactory.cpp
|
||||
)
|
125
examples/fsfw_examples/core/GenericFactory.cpp
Normal file
125
examples/fsfw_examples/core/GenericFactory.cpp
Normal file
|
@ -0,0 +1,125 @@
|
|||
#include "GenericFactory.h"
|
||||
|
||||
#include "fsfw/ExampleConfig.h"
|
||||
#include "tmtc/pusIds.h"
|
||||
#include "exampleObjectIds.h"
|
||||
|
||||
#include "fsfw_tests/internal/InternalUnitTester.h"
|
||||
#include "fsfw_examples/test/FsfwExampleTask.h"
|
||||
#include "fsfw_examples/test/FsfwReaderTask.h"
|
||||
#include "fsfw_examples/assemblies/TestAssembly.h"
|
||||
#include "fsfw_examples/devices/TestCookie.h"
|
||||
#include "fsfw_examples/devices/TestDeviceHandler.h"
|
||||
#include "fsfw_examples/devices/TestEchoComIF.h"
|
||||
#include "fsfw_examples/utility/TmFunnel.h"
|
||||
#include "fsfw_examples/controller/TestController.h"
|
||||
|
||||
#include "fsfw/devicehandlers/CookieIF.h"
|
||||
#include "fsfw/events/EventManager.h"
|
||||
#include "fsfw/health/HealthTable.h"
|
||||
#include "fsfw/internalerror/InternalErrorReporter.h"
|
||||
#include "fsfw/pus/CService200ModeCommanding.h"
|
||||
#include "fsfw/pus/Service17Test.h"
|
||||
#include "fsfw/pus/Service1TelecommandVerification.h"
|
||||
#include "fsfw/pus/Service20ParameterManagement.h"
|
||||
#include "fsfw/pus/Service2DeviceAccess.h"
|
||||
#include "fsfw/pus/Service3Housekeeping.h"
|
||||
#include "fsfw/pus/Service5EventReporting.h"
|
||||
#include "fsfw/pus/Service8FunctionManagement.h"
|
||||
#include "fsfw/pus/Service9TimeManagement.h"
|
||||
#include "fsfw/tcdistribution/CCSDSDistributor.h"
|
||||
#include "fsfw/tcdistribution/PUSDistributor.h"
|
||||
#include "fsfw/timemanager/TimeStamper.h"
|
||||
#include "fsfw/tmtcpacket/pus/tm.h"
|
||||
|
||||
|
||||
|
||||
void ObjectFactory::produceGenericObjects(uint16_t apid) {
|
||||
#if OBSW_ADD_CORE_COMPONENTS == 1
|
||||
/* Framework objects */
|
||||
new EventManager(objects::EVENT_MANAGER);
|
||||
new HealthTable(objects::HEALTH_TABLE);
|
||||
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER);
|
||||
new TimeStamper(objects::TIME_STAMPER);
|
||||
new CCSDSDistributor(apid, objects::CCSDS_DISTRIBUTOR);
|
||||
new PUSDistributor(apid, objects::PUS_DISTRIBUTOR,
|
||||
objects::CCSDS_DISTRIBUTOR);
|
||||
new TmFunnel(objects::TM_FUNNEL);
|
||||
#endif /* OBSW_ADD_CORE_COMPONENTS == 1 */
|
||||
|
||||
/* PUS stack */
|
||||
#if OBSW_ADD_PUS_STACK == 1
|
||||
new Service1TelecommandVerification(objects::PUS_SERVICE_1_VERIFICATION,
|
||||
apid, pus::PUS_SERVICE_1, objects::TM_FUNNEL, 5);
|
||||
new Service2DeviceAccess(objects::PUS_SERVICE_2_DEVICE_ACCESS,
|
||||
apid, pus::PUS_SERVICE_2, 3, 10);
|
||||
new Service3Housekeeping(objects::PUS_SERVICE_3_HOUSEKEEPING, apid, pus::PUS_SERVICE_3);
|
||||
new Service5EventReporting(objects::PUS_SERVICE_5_EVENT_REPORTING,
|
||||
apid, pus::PUS_SERVICE_5, 50);
|
||||
new Service8FunctionManagement(objects::PUS_SERVICE_8_FUNCTION_MGMT,
|
||||
apid, pus::PUS_SERVICE_8, 3, 10);
|
||||
new Service9TimeManagement(objects::PUS_SERVICE_9_TIME_MGMT, apid,
|
||||
pus::PUS_SERVICE_9);
|
||||
new Service17Test(objects::PUS_SERVICE_17_TEST, apid,
|
||||
pus::PUS_SERVICE_17);
|
||||
new Service20ParameterManagement(objects::PUS_SERVICE_20_PARAMETERS, apid,
|
||||
pus::PUS_SERVICE_20);
|
||||
new CService200ModeCommanding(objects::PUS_SERVICE_200_MODE_MGMT,
|
||||
apid, pus::PUS_SERVICE_200);
|
||||
#endif /* OBSW_ADD_PUS_STACK == 1 */
|
||||
|
||||
#if OBSW_ADD_TASK_EXAMPLE == 1
|
||||
/* Demo objects */
|
||||
new FsfwExampleTask(objects::TEST_DUMMY_1);
|
||||
new FsfwExampleTask(objects::TEST_DUMMY_2);
|
||||
new FsfwExampleTask(objects::TEST_DUMMY_3);
|
||||
|
||||
|
||||
bool enablePrintout = false;
|
||||
#if OBSW_TASK_EXAMPLE_PRINTOUT == 1
|
||||
enablePrintout = true;
|
||||
#endif
|
||||
new FsfwReaderTask(objects::TEST_DUMMY_4, enablePrintout);
|
||||
#endif /* OBSW_ADD_TASK_EXAMPLE == 1 */
|
||||
|
||||
#if OBSW_ADD_DEVICE_HANDLER_DEMO == 1
|
||||
|
||||
#if OBSW_DEVICE_HANDLER_PRINTOUT == 1
|
||||
bool enableInfoPrintout = true;
|
||||
#else
|
||||
bool enableInfoPrintout = false;
|
||||
#endif /* OBSW_DEVICE_HANDLER_PRINTOUT == 1 */
|
||||
|
||||
/* Demo device handler object */
|
||||
size_t expectedMaxReplyLen = 64;
|
||||
CookieIF* testCookie = new DummyCookie(
|
||||
static_cast<address_t>(testdevice::DeviceIndex::DEVICE_0), expectedMaxReplyLen);
|
||||
new TestEchoComIF(objects::TEST_ECHO_COM_IF);
|
||||
new TestDevice(objects::TEST_DEVICE_HANDLER_0, objects::TEST_ECHO_COM_IF, testCookie,
|
||||
testdevice::DeviceIndex::DEVICE_0, enableInfoPrintout);
|
||||
testCookie = new DummyCookie(static_cast<address_t>(testdevice::DeviceIndex::DEVICE_1),
|
||||
expectedMaxReplyLen);
|
||||
new TestDevice(objects::TEST_DEVICE_HANDLER_1, objects::TEST_ECHO_COM_IF, testCookie,
|
||||
testdevice::DeviceIndex::DEVICE_1, enableInfoPrintout);
|
||||
|
||||
new TestAssembly(objects::TEST_ASSEMBLY, objects::NO_OBJECT);
|
||||
|
||||
#endif /* OBSW_ADD_DEVICE_HANDLER_DEMO == 1 */
|
||||
|
||||
|
||||
/* Demo controller object */
|
||||
#if OBSW_ADD_CONTROLLER_DEMO == 1
|
||||
|
||||
#if OBSW_CONTROLLER_PRINTOUT == 1
|
||||
#endif
|
||||
new TestController(objects::TEST_CONTROLLER);
|
||||
|
||||
#endif /* OBSW_ADD_CONTROLLER_DEMO == 1 */
|
||||
|
||||
#if OBSW_PERFORM_INTERNAL_UNITTEST == 1
|
||||
InternalUnitTester::TestConfig testCfg;
|
||||
testCfg.testArrayPrinter = false;
|
||||
InternalUnitTester unittester;
|
||||
unittester.performTests(testCfg);
|
||||
#endif /* OBSW_PERFORM_INTERNAL_UNITTEST == 1 */
|
||||
}
|
17
examples/fsfw_examples/core/GenericFactory.h
Normal file
17
examples/fsfw_examples/core/GenericFactory.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef MISSION_CORE_GENERICFACTORY_H_
|
||||
#define MISSION_CORE_GENERICFACTORY_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
|
||||
namespace ObjectFactory {
|
||||
|
||||
/**
|
||||
* @brief Produce hardware independant objects. Called by bsp specific
|
||||
* object factory.
|
||||
*/
|
||||
void produceGenericObjects(uint16_t apid);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* MISSION_CORE_GENERICFACTORY_H_ */
|
|
@ -1,5 +1,5 @@
|
|||
#include "TestDeviceHandler.h"
|
||||
#include <OBSWConfig.h>
|
||||
#include "fsfw/ExampleConfig.h"
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
|
||||
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||
#include <commonSystemObjects.h>
|
||||
#include <exampleObjectIds.h>
|
||||
|
||||
namespace testdevice {
|
||||
|
7
examples/fsfw_examples/test/CMakeLists.txt
Normal file
7
examples/fsfw_examples/test/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
target_sources(${TARGET_NAME}
|
||||
PRIVATE
|
||||
TestTask.cpp
|
||||
FsfwReaderTask.cpp
|
||||
FsfwExampleTask.cpp
|
||||
MutexExample.cpp
|
||||
)
|
264
examples/fsfw_examples/test/FsfwExampleTask.cpp
Normal file
264
examples/fsfw_examples/test/FsfwExampleTask.cpp
Normal file
|
@ -0,0 +1,264 @@
|
|||
#include "FsfwExampleTask.h"
|
||||
#include "fsfw/ExampleConfig.h"
|
||||
#include "exampleObjectIds.h"
|
||||
#include "objects/systemObjectList.h"
|
||||
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
#include <fsfw/tasks/TaskFactory.h>
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/ipc/CommandMessage.h>
|
||||
|
||||
|
||||
FsfwExampleTask::FsfwExampleTask(object_id_t objectId): SystemObject(objectId),
|
||||
poolManager(this, nullptr), demoSet(this),
|
||||
monitor(objectId, MONITOR_ID, gp_id_t(objectId, FsfwDemoSet::VARIABLE_LIMIT), 30, 10)
|
||||
{
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(10,
|
||||
CommandMessage::MAX_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
FsfwExampleTask::~FsfwExampleTask() {
|
||||
}
|
||||
|
||||
ReturnValue_t FsfwExampleTask::performOperation(uint8_t operationCode) {
|
||||
if(operationCode == OpCodes::DELAY_SHORT){
|
||||
TaskFactory::delayTask(5);
|
||||
}
|
||||
|
||||
// TODO: Move this to new test controller?
|
||||
ReturnValue_t result = performMonitoringDemo();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (operationCode == OpCodes::SEND_RAND_NUM) {
|
||||
result = performSendOperation();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (operationCode == OpCodes::RECEIVE_RAND_NUM) {
|
||||
result = performReceiveOperation();
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
object_id_t FsfwExampleTask::getNextRecipient() {
|
||||
switch(this->getObjectId()) {
|
||||
case(objects::TEST_DUMMY_1): {
|
||||
return objects::TEST_DUMMY_2;
|
||||
}
|
||||
case(objects::TEST_DUMMY_2): {
|
||||
return objects::TEST_DUMMY_3;
|
||||
}
|
||||
case(objects::TEST_DUMMY_3): {
|
||||
return objects::TEST_DUMMY_1;
|
||||
}
|
||||
default:
|
||||
return objects::TEST_DUMMY_1;
|
||||
}
|
||||
}
|
||||
|
||||
object_id_t FsfwExampleTask::getSender() {
|
||||
switch(this->getObjectId()) {
|
||||
case(objects::TEST_DUMMY_1): {
|
||||
return objects::TEST_DUMMY_3;
|
||||
}
|
||||
case(objects::TEST_DUMMY_2): {
|
||||
return objects::TEST_DUMMY_1;
|
||||
}
|
||||
case(objects::TEST_DUMMY_3): {
|
||||
return objects::TEST_DUMMY_2;
|
||||
}
|
||||
default:
|
||||
return objects::TEST_DUMMY_1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t FsfwExampleTask::initialize() {
|
||||
// Get the dataset of the sender. Will be cached for later checks.
|
||||
object_id_t sender = getSender();
|
||||
HasLocalDataPoolIF* senderIF = ObjectManager::instance()->get<HasLocalDataPoolIF>(sender);
|
||||
if(senderIF == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FsfwDemoTask::initialize: Sender object invalid!" << std::endl;
|
||||
#else
|
||||
sif::printError("FsfwDemoTask::initialize: Sender object invalid!\n");
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
// we need a private copy of the previous dataset.. or we use the shared dataset.
|
||||
senderSet = new FsfwDemoSet(senderIF);
|
||||
if(senderSet == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FsfwDemoTask::initialize: Sender dataset invalid!" << std::endl;
|
||||
#else
|
||||
sif::printError("FsfwDemoTask::initialize: Sender dataset invalid!\n");
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return poolManager.initialize(commandQueue);
|
||||
}
|
||||
|
||||
ReturnValue_t FsfwExampleTask::initializeAfterTaskCreation() {
|
||||
return poolManager.initializeAfterTaskCreation();
|
||||
}
|
||||
|
||||
object_id_t FsfwExampleTask::getObjectId() const {
|
||||
return SystemObject::getObjectId();
|
||||
}
|
||||
|
||||
MessageQueueId_t FsfwExampleTask::getMessageQueueId(){
|
||||
return commandQueue->getId();
|
||||
}
|
||||
|
||||
void FsfwExampleTask::setTaskIF(PeriodicTaskIF* task){
|
||||
this->task = task;
|
||||
}
|
||||
|
||||
LocalPoolDataSetBase* FsfwExampleTask::getDataSetHandle(sid_t sid) {
|
||||
return &demoSet;
|
||||
}
|
||||
|
||||
uint32_t FsfwExampleTask::getPeriodicOperationFrequency() const {
|
||||
return task->getPeriodMs();
|
||||
}
|
||||
|
||||
ReturnValue_t FsfwExampleTask::initializeLocalDataPool(
|
||||
localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
|
||||
localDataPoolMap.emplace(FsfwDemoSet::PoolIds::VARIABLE, new PoolEntry<uint32_t>({0}));
|
||||
localDataPoolMap.emplace(FsfwDemoSet::PoolIds::VARIABLE_LIMIT, new PoolEntry<uint16_t>({0}));
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t FsfwExampleTask::performMonitoringDemo() {
|
||||
ReturnValue_t result = demoSet.variableLimit.read(
|
||||
MutexIF::TimeoutType::WAITING, 20);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
/* Configuration error */
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "DummyObject::performOperation: Could not read variableLimit!" << std::endl;
|
||||
#else
|
||||
sif::printError("DummyObject::performOperation: Could not read variableLimit!\n");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
if(this->getObjectId() == objects::TEST_DUMMY_5){
|
||||
if(demoSet.variableLimit.value > 20){
|
||||
demoSet.variableLimit.value = 0;
|
||||
}
|
||||
demoSet.variableLimit.value++;
|
||||
demoSet.variableLimit.commit(20);
|
||||
monitor.check();
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t FsfwExampleTask::performSendOperation() {
|
||||
object_id_t nextRecipient = getNextRecipient();
|
||||
FsfwExampleTask* target = ObjectManager::instance()->get<FsfwExampleTask>(nextRecipient);
|
||||
if (target == nullptr) {
|
||||
/* Configuration error */
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "DummyObject::performOperation: Next recipient does not exist!" << std::endl;
|
||||
#else
|
||||
sif::printError("DummyObject::performOperation: Next recipient does not exist!\n");
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
|
||||
uint32_t randomNumber = rand() % 100;
|
||||
CommandMessage message;
|
||||
message.setParameter(randomNumber);
|
||||
message.setParameter2(this->getMessageQueueId());
|
||||
|
||||
/* Send message using own message queue */
|
||||
ReturnValue_t result = commandQueue->sendMessage(target->getMessageQueueId(), &message);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK
|
||||
&& result != MessageQueueIF::FULL) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FsfwDemoTask::performSendOperation: Send failed with " << result <<
|
||||
std::endl;
|
||||
#else
|
||||
sif::printError("FsfwDemoTask::performSendOperation: Send failed with %hu\n", result);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Send message without via MessageQueueSenderIF */
|
||||
result = MessageQueueSenderIF::sendMessage(target->getMessageQueueId(), &message,
|
||||
commandQueue->getId());
|
||||
if (result != HasReturnvaluesIF::RETURN_OK
|
||||
&& result != MessageQueueIF::FULL) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FsfwDemoTask::performSendOperation: Send failed with " << result << std::endl;
|
||||
#else
|
||||
sif::printError("FsfwDemoTask::performSendOperation: Send failed with %hu\n", result);
|
||||
#endif
|
||||
}
|
||||
|
||||
demoSet.variableWrite.value = randomNumber;
|
||||
result = demoSet.variableWrite.commit(20);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t FsfwExampleTask::performReceiveOperation() {
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
while (result != MessageQueueIF::EMPTY) {
|
||||
CommandMessage receivedMessage;
|
||||
result = commandQueue->receiveMessage(&receivedMessage);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK
|
||||
&& result != MessageQueueIF::EMPTY) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "Receive failed with " << result << std::endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (result != MessageQueueIF::EMPTY) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
#if OBSW_VERBOSE_LEVEL >= 2
|
||||
sif::debug << "Message Received by " << getObjectId() << " from Queue " <<
|
||||
receivedMessage.getSender() << " ObjectId " << receivedMessage.getParameter() <<
|
||||
" Queue " << receivedMessage.getParameter2() << std::endl;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(senderSet == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
result = senderSet->variableRead.read(MutexIF::TimeoutType::WAITING,
|
||||
20);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if(senderSet->variableRead.value != receivedMessage.getParameter()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FsfwDemoTask::performReceiveOperation: Variable " << std::hex <<
|
||||
"0x" << senderSet->variableRead.getDataPoolId() << std::dec <<
|
||||
" has wrong value." << std::endl;
|
||||
sif::error << "Value: " << demoSet.variableRead.value << ", expected: " <<
|
||||
receivedMessage.getParameter() << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageQueueId_t FsfwExampleTask::getCommandQueue() const {
|
||||
return commandQueue->getId();
|
||||
}
|
||||
|
||||
LocalDataPoolManager* FsfwExampleTask::getHkManagerHandle() {
|
||||
return &poolManager;
|
||||
}
|
116
examples/fsfw_examples/test/FsfwExampleTask.h
Normal file
116
examples/fsfw_examples/test/FsfwExampleTask.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
#ifndef MISSION_DEMO_FSFWDEMOTASK_H_
|
||||
#define MISSION_DEMO_FSFWDEMOTASK_H_
|
||||
|
||||
#include "testdefinitions/demoDefinitions.h"
|
||||
|
||||
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
|
||||
#include <fsfw/datapoollocal/LocalPoolVariable.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/ipc/MessageQueueIF.h>
|
||||
#include <fsfw/monitoring/AbsLimitMonitor.h>
|
||||
|
||||
class PeriodicTaskIF;
|
||||
|
||||
|
||||
/**
|
||||
* @brief This demo set shows the local data pool functionality and fixed
|
||||
* timeslot capabilities of the FSFW.
|
||||
*
|
||||
* @details
|
||||
* There will be multiple demo objects. Each demo object will generate a random
|
||||
* number and send that number via message queues to the next demo object
|
||||
* (e.g. DUMMY_1 sends the number to DUMMY_2 etc.). The receiving object
|
||||
* will check the received value against the sent value by extracting the sent
|
||||
* value directly from the sender via the local data pool interface.
|
||||
* If the timing is set up correctly, the values will always be the same.
|
||||
*/
|
||||
class FsfwExampleTask:
|
||||
public ExecutableObjectIF,
|
||||
public SystemObject,
|
||||
public HasLocalDataPoolIF {
|
||||
public:
|
||||
enum OpCodes {
|
||||
SEND_RAND_NUM,
|
||||
RECEIVE_RAND_NUM,
|
||||
DELAY_SHORT
|
||||
};
|
||||
|
||||
static constexpr uint8_t MONITOR_ID = 2;
|
||||
|
||||
/**
|
||||
* @brief Simple constructor, only expects object ID.
|
||||
* @param objectId
|
||||
*/
|
||||
FsfwExampleTask(object_id_t objectId);
|
||||
|
||||
virtual ~FsfwExampleTask();
|
||||
|
||||
/**
|
||||
* @brief The performOperation method is executed in a task.
|
||||
* @details There are no restrictions for calls within this method, so any
|
||||
* other member of the class can be used.
|
||||
* @return Currently, the return value is ignored.
|
||||
*/
|
||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0);
|
||||
|
||||
/**
|
||||
* @brief This function will be called by the global object manager
|
||||
* @details
|
||||
* This function will always be called before any tasks are started.
|
||||
* It can also be used to return error codes in the software initialization
|
||||
* process cleanly.
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initialize() override;
|
||||
|
||||
/**
|
||||
* @brief This function will be called by the OSAL task handlers
|
||||
* @details
|
||||
* This function will be called before the first #performOperation
|
||||
* call after the tasks have been started. It can be used if some
|
||||
* initialization process requires task specific properties like
|
||||
* periodic intervals (by using the PeriodicTaskIF* handle).
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
/**
|
||||
* This function will be called by the OSAL task handler. The
|
||||
* task interface handle can be cached to access task specific properties.
|
||||
* @param task
|
||||
*/
|
||||
void setTaskIF(PeriodicTaskIF* task) override;
|
||||
|
||||
object_id_t getObjectId() const override;
|
||||
|
||||
MessageQueueId_t getMessageQueueId();
|
||||
|
||||
|
||||
private:
|
||||
LocalDataPoolManager poolManager;
|
||||
FsfwDemoSet* senderSet = nullptr;
|
||||
FsfwDemoSet demoSet;
|
||||
AbsLimitMonitor<int32_t> monitor;
|
||||
PeriodicTaskIF* task = nullptr;
|
||||
MessageQueueIF* commandQueue = nullptr;
|
||||
|
||||
/* HasLocalDatapoolIF overrides */
|
||||
MessageQueueId_t getCommandQueue() const override;
|
||||
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
|
||||
uint32_t getPeriodicOperationFrequency() const override;
|
||||
virtual ReturnValue_t initializeLocalDataPool(
|
||||
localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) override;
|
||||
virtual LocalDataPoolManager* getHkManagerHandle() override;
|
||||
|
||||
object_id_t getNextRecipient();
|
||||
object_id_t getSender();
|
||||
|
||||
ReturnValue_t performMonitoringDemo();
|
||||
ReturnValue_t performSendOperation();
|
||||
ReturnValue_t performReceiveOperation();
|
||||
uint8_t execCounter = 0;
|
||||
};
|
||||
|
||||
#endif /* MISSION_DEMO_FSFWDEMOTASK_H_ */
|
55
examples/fsfw_examples/test/FsfwReaderTask.cpp
Normal file
55
examples/fsfw_examples/test/FsfwReaderTask.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include "FsfwReaderTask.h"
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
#include <fsfw/tasks/TaskFactory.h>
|
||||
#include <fsfw/timemanager/Stopwatch.h>
|
||||
|
||||
#include <OBSWConfig.h>
|
||||
|
||||
|
||||
FsfwReaderTask::FsfwReaderTask(object_id_t objectId, bool enablePrintout):
|
||||
SystemObject(objectId), printoutEnabled(enablePrintout), opDivider(10),
|
||||
readSet(this->getObjectId(),
|
||||
gp_id_t(objects::TEST_DUMMY_1, FsfwDemoSet::PoolIds::VARIABLE),
|
||||
gp_id_t(objects::TEST_DUMMY_2, FsfwDemoSet::PoolIds::VARIABLE),
|
||||
gp_id_t(objects::TEST_DUMMY_3, FsfwDemoSet::PoolIds::VARIABLE)) {
|
||||
/* Special protection for set reading because each variable is read from a different pool */
|
||||
readSet.setReadCommitProtectionBehaviour(true);
|
||||
}
|
||||
|
||||
FsfwReaderTask::~FsfwReaderTask() {
|
||||
}
|
||||
|
||||
ReturnValue_t FsfwReaderTask::initializeAfterTaskCreation() {
|
||||
/* Give other task some time to set up local data pools. */
|
||||
TaskFactory::delayTask(20);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t FsfwReaderTask::performOperation(uint8_t operationCode) {
|
||||
PoolReadGuard readHelper(&readSet);
|
||||
|
||||
uint32_t variable1 = readSet.variable1.value;
|
||||
uint32_t variable2 = readSet.variable2.value;
|
||||
uint32_t variable3 = readSet.variable3.value;
|
||||
|
||||
#if OBSW_VERBOSE_LEVEL >= 1
|
||||
if(opDivider.checkAndIncrement() and printoutEnabled) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "FsfwPeriodicTask::performOperation: Reading variables." << std::endl;
|
||||
sif::info << "Variable read from demo object 1: " << variable1 << std::endl;
|
||||
sif::info << "Variable read from demo object 2: " << variable2 << std::endl;
|
||||
sif::info << "Variable read from demo object 3: " << variable3 << std::endl;
|
||||
#else
|
||||
sif::printInfo("FsfwPeriodicTask::performOperation: Reading variables.\n\r");
|
||||
sif::printInfo("Variable read from demo object 1: %d\n\r", variable1);
|
||||
sif::printInfo("Variable read from demo object 2: %d\n\r", variable2);
|
||||
sif::printInfo("Variable read from demo object 3: %d\n\r", variable3);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if(variable1 and variable2 and variable3) {};
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
24
examples/fsfw_examples/test/FsfwReaderTask.h
Normal file
24
examples/fsfw_examples/test/FsfwReaderTask.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef MISSION_DEMO_FSFWPERIODICTASK_H_
|
||||
#define MISSION_DEMO_FSFWPERIODICTASK_H_
|
||||
|
||||
#include "testdefinitions/demoDefinitions.h"
|
||||
|
||||
#include <fsfw/globalfunctions/PeriodicOperationDivider.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
|
||||
class FsfwReaderTask: public ExecutableObjectIF, public SystemObject {
|
||||
public:
|
||||
FsfwReaderTask(object_id_t objectId, bool enablePrintout);
|
||||
virtual ~FsfwReaderTask();
|
||||
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0);
|
||||
|
||||
private:
|
||||
bool printoutEnabled = false;
|
||||
PeriodicOperationDivider opDivider;
|
||||
CompleteDemoReadSet readSet;
|
||||
};
|
||||
|
||||
#endif /* MISSION_DEMO_FSFWPERIODICTASK_H_ */
|
47
examples/fsfw_examples/test/MutexExample.cpp
Normal file
47
examples/fsfw_examples/test/MutexExample.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "MutexExample.h"
|
||||
|
||||
#include <fsfw/ipc/MutexFactory.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
|
||||
void MutexExample::example(){
|
||||
MutexIF* mutex = MutexFactory::instance()->createMutex();
|
||||
MutexIF* mutex2 = MutexFactory::instance()->createMutex();
|
||||
|
||||
ReturnValue_t result = mutex->lockMutex(MutexIF::TimeoutType::WAITING,
|
||||
2 * 60 * 1000);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MutexExample::example: Lock Failed with " << result << std::endl;
|
||||
#else
|
||||
sif::printError("MutexExample::example: Lock Failed with %hu\n", result);
|
||||
#endif
|
||||
}
|
||||
|
||||
result = mutex2->lockMutex(MutexIF::TimeoutType::BLOCKING);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MutexExample::example: Lock Failed with " << result << std::endl;
|
||||
#else
|
||||
sif::printError("MutexExample::example: Lock Failed with %hu\n", result);
|
||||
#endif
|
||||
}
|
||||
|
||||
result = mutex->unlockMutex();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MutexExample::example: Unlock Failed with " << result << std::endl;
|
||||
#else
|
||||
sif::printError("MutexExample::example: Unlock Failed with %hu\n", result);
|
||||
#endif
|
||||
}
|
||||
|
||||
result = mutex2->unlockMutex();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MutexExample::example: Unlock Failed with " << result << std::endl;
|
||||
#else
|
||||
sif::printError("MutexExample::example: Unlock Failed with %hu\n", result);
|
||||
#endif
|
||||
}
|
||||
}
|
8
examples/fsfw_examples/test/MutexExample.h
Normal file
8
examples/fsfw_examples/test/MutexExample.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef MISSION_DEMO_MUTEXEXAMPLE_H_
|
||||
#define MISSION_DEMO_MUTEXEXAMPLE_H_
|
||||
|
||||
namespace MutexExample {
|
||||
void example();
|
||||
};
|
||||
|
||||
#endif /* MISSION_DEMO_MUTEXEXAMPLE_H_ */
|
80
examples/fsfw_examples/test/TestTask.cpp
Normal file
80
examples/fsfw_examples/test/TestTask.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#include "TestTask.h"
|
||||
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
bool TestTask::oneShotAction = true;
|
||||
MutexIF* TestTask::testLock = nullptr;
|
||||
|
||||
TestTask::TestTask(object_id_t objectId, bool periodicPrintout, bool periodicEvent):
|
||||
SystemObject(objectId), testMode(testModes::A),
|
||||
periodicPrinout(periodicPrintout), periodicEvent(periodicEvent) {
|
||||
if(testLock == nullptr) {
|
||||
testLock = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
IPCStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
}
|
||||
|
||||
TestTask::~TestTask() {
|
||||
}
|
||||
|
||||
ReturnValue_t TestTask::performOperation(uint8_t operationCode) {
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
testLock->lockMutex(MutexIF::TimeoutType::WAITING, 20);
|
||||
if(oneShotAction) {
|
||||
// Add code here which should only be run once
|
||||
performOneShotAction();
|
||||
oneShotAction = false;
|
||||
}
|
||||
testLock->unlockMutex();
|
||||
|
||||
// Add code here which should only be run once per performOperation
|
||||
performPeriodicAction();
|
||||
|
||||
// Add code here which should only be run on alternating cycles.
|
||||
if(testMode == testModes::A) {
|
||||
performActionA();
|
||||
testMode = testModes::B;
|
||||
}
|
||||
else if(testMode == testModes::B) {
|
||||
performActionB();
|
||||
testMode = testModes::A;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t TestTask::performOneShotAction() {
|
||||
/* Everything here will only be performed once. */
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t TestTask::performPeriodicAction() {
|
||||
/* This is performed each task cycle */
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
|
||||
if(periodicPrinout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestTask::performPeriodicAction: Hello World!" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestTask::performPeriodicAction: Hello World!\n");
|
||||
#endif
|
||||
}
|
||||
if(periodicEvent) {
|
||||
triggerEvent(TEST_EVENT, 0x1234, 0x4321);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t TestTask::performActionA() {
|
||||
/* This is performed each alternating task cycle */
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t TestTask::performActionB() {
|
||||
/* This is performed each alternating task cycle */
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
return result;
|
||||
}
|
||||
|
56
examples/fsfw_examples/test/TestTask.h
Normal file
56
examples/fsfw_examples/test/TestTask.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef MISSION_DEMO_TESTTASK_H_
|
||||
#define MISSION_DEMO_TESTTASK_H_
|
||||
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/storagemanager/StorageManagerIF.h>
|
||||
|
||||
#include "fsfw/events/Event.h"
|
||||
#include "events/subsystemIdRanges.h"
|
||||
|
||||
/**
|
||||
* @brief Test class for general C++ testing and any other code which will not be part of the
|
||||
* primary mission software.
|
||||
* @details
|
||||
* Should not be used for board specific tests. Instead, a derived board test class should be used.
|
||||
*/
|
||||
class TestTask :
|
||||
public SystemObject,
|
||||
public ExecutableObjectIF,
|
||||
public HasReturnvaluesIF {
|
||||
public:
|
||||
TestTask(object_id_t objectId, bool periodicPrintout = false, bool periodicEvent = false);
|
||||
virtual ~TestTask();
|
||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0);
|
||||
|
||||
static constexpr uint8_t subsystemId = SUBSYSTEM_ID::TEST_TASK_ID;
|
||||
static constexpr Event TEST_EVENT = event::makeEvent(subsystemId, 0, severity::INFO);
|
||||
|
||||
protected:
|
||||
virtual ReturnValue_t performOneShotAction();
|
||||
virtual ReturnValue_t performPeriodicAction();
|
||||
virtual ReturnValue_t performActionA();
|
||||
virtual ReturnValue_t performActionB();
|
||||
|
||||
enum testModes: uint8_t {
|
||||
A,
|
||||
B
|
||||
};
|
||||
|
||||
testModes testMode;
|
||||
bool periodicPrinout = false;
|
||||
bool periodicEvent = false;
|
||||
|
||||
bool testFlag = false;
|
||||
uint8_t counter { 1 };
|
||||
uint8_t counterTrigger { 3 };
|
||||
|
||||
void performPusInjectorTest();
|
||||
void examplePacketTest();
|
||||
private:
|
||||
static bool oneShotAction;
|
||||
static MutexIF* testLock;
|
||||
StorageManagerIF* IPCStore;
|
||||
};
|
||||
|
||||
#endif /* TESTTASK_H_ */
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef MISSION_DEMO_DEMODEFINITIONS_H_
|
||||
#define MISSION_DEMO_DEMODEFINITIONS_H_
|
||||
|
||||
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
|
||||
#include <fsfw/datapoollocal/LocalPoolVariable.h>
|
||||
|
||||
/**
|
||||
* @brief This demo set showcases the local data pool functionality of the
|
||||
* FSFW
|
||||
* @details
|
||||
* Each demo object will have an own instance of this set class, which contains
|
||||
* pool variables (for read and write access respectively).
|
||||
*/
|
||||
class FsfwDemoSet: public StaticLocalDataSet<3> {
|
||||
public:
|
||||
|
||||
static constexpr uint32_t DEMO_SET_ID = 0;
|
||||
|
||||
enum PoolIds {
|
||||
VARIABLE,
|
||||
VARIABLE_LIMIT
|
||||
};
|
||||
|
||||
FsfwDemoSet(HasLocalDataPoolIF* hkOwner):
|
||||
StaticLocalDataSet(hkOwner, DEMO_SET_ID) {}
|
||||
|
||||
lp_var_t<uint32_t> variableRead = lp_var_t<uint32_t>(sid.objectId,
|
||||
PoolIds::VARIABLE, this, pool_rwm_t::VAR_READ);
|
||||
lp_var_t<uint32_t> variableWrite = lp_var_t<uint32_t>(sid.objectId,
|
||||
PoolIds::VARIABLE, this, pool_rwm_t::VAR_WRITE);
|
||||
lp_var_t<uint16_t> variableLimit = lp_var_t<uint16_t>(sid.objectId,
|
||||
PoolIds::VARIABLE_LIMIT, this);
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* This set will enable object to read the dummy variables from the dataset
|
||||
* above. An example application would be a consumer object like a controller
|
||||
* which reads multiple sensor values at once.
|
||||
*/
|
||||
class CompleteDemoReadSet: public StaticLocalDataSet<3> {
|
||||
public:
|
||||
static constexpr uint32_t DEMO_SET_ID = 0;
|
||||
|
||||
CompleteDemoReadSet(object_id_t owner, gp_id_t variable1,
|
||||
gp_id_t variable2, gp_id_t variable3):
|
||||
StaticLocalDataSet(sid_t(owner, DEMO_SET_ID)),
|
||||
variable1(variable1, this, pool_rwm_t::VAR_READ),
|
||||
variable2(variable2, this, pool_rwm_t::VAR_READ),
|
||||
variable3(variable3, this, pool_rwm_t::VAR_READ) {}
|
||||
|
||||
|
||||
lp_var_t<uint32_t> variable1;
|
||||
lp_var_t<uint32_t> variable2;
|
||||
lp_var_t<uint32_t> variable3;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* MISSION_DEMO_DEMODEFINITIONS_H_ */
|
4
examples/fsfw_examples/utility/CMakeLists.txt
Normal file
4
examples/fsfw_examples/utility/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
target_sources(${TARGET_NAME} PRIVATE
|
||||
utility.cpp
|
||||
TmFunnel.cpp
|
||||
)
|
22
examples/fsfw_examples/utility/TaskCreation.h
Normal file
22
examples/fsfw_examples/utility/TaskCreation.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef MISSION_UTILITY_TASKCREATION_H_
|
||||
#define MISSION_UTILITY_TASKCREATION_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
namespace task {
|
||||
|
||||
void printInitError(const char* objName, object_id_t objectId) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "InitMission: Adding object " << objName << "("
|
||||
<< std::setw(8) << std::setfill('0') << std::hex << objectId
|
||||
<< std::dec << ") failed." << std::endl;
|
||||
#else
|
||||
sif::printError("InitMission: Adding object %s (0x%08x) failed.\n",
|
||||
objName, static_cast<unsigned int>(objectId));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* MISSION_UTILITY_TASKCREATION_H_ */
|
121
examples/fsfw_examples/utility/TmFunnel.cpp
Normal file
121
examples/fsfw_examples/utility/TmFunnel.cpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
#include "TmFunnel.h"
|
||||
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
#include <fsfw/tmtcpacket/pus/tm.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
|
||||
object_id_t TmFunnel::downlinkDestination = objects::NO_OBJECT;
|
||||
object_id_t TmFunnel::storageDestination = objects::NO_OBJECT;
|
||||
|
||||
TmFunnel::TmFunnel(object_id_t objectId, uint32_t messageDepth):
|
||||
SystemObject(objectId), messageDepth(messageDepth) {
|
||||
tmQueue = QueueFactory::instance()->createMessageQueue(messageDepth,
|
||||
MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
storageQueue = QueueFactory::instance()->createMessageQueue(messageDepth,
|
||||
MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
TmFunnel::~TmFunnel() {
|
||||
}
|
||||
|
||||
MessageQueueId_t TmFunnel::getReportReceptionQueue(uint8_t virtualChannel) {
|
||||
return tmQueue->getId();
|
||||
}
|
||||
|
||||
ReturnValue_t TmFunnel::performOperation(uint8_t operationCode) {
|
||||
TmTcMessage currentMessage;
|
||||
ReturnValue_t status = tmQueue->receiveMessage(¤tMessage);
|
||||
while(status == HasReturnvaluesIF::RETURN_OK)
|
||||
{
|
||||
status = handlePacket(¤tMessage);
|
||||
if(status != HasReturnvaluesIF::RETURN_OK){
|
||||
break;
|
||||
}
|
||||
status = tmQueue->receiveMessage(¤tMessage);
|
||||
}
|
||||
|
||||
if (status == MessageQueueIF::EMPTY) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
else {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t TmFunnel::handlePacket(TmTcMessage* message) {
|
||||
uint8_t* packetData = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = tmPool->modifyData(message->getStorageId(),
|
||||
&packetData, &size);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
||||
return result;
|
||||
}
|
||||
TmPacketPusC packet(packetData);
|
||||
packet.setPacketSequenceCount(this->sourceSequenceCount);
|
||||
sourceSequenceCount++;
|
||||
sourceSequenceCount = sourceSequenceCount %
|
||||
SpacePacketBase::LIMIT_SEQUENCE_COUNT;
|
||||
packet.setErrorControl();
|
||||
|
||||
result = tmQueue->sendToDefault(message);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
||||
tmPool->deleteData(message->getStorageId());
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TmFunnel::handlePacket: Error sending to downlink handler" << std::endl;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
if(storageDestination != objects::NO_OBJECT) {
|
||||
result = storageQueue->sendToDefault(message);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
||||
tmPool->deleteData(message->getStorageId());
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TmFunnel::handlePacket: Error sending to storage handler" << std::endl;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t TmFunnel::initialize() {
|
||||
|
||||
tmPool = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if(tmPool == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TmFunnel::initialize: TM store not set." << std::endl;
|
||||
sif::error << "Make sure the tm store is set up properly and implements StorageManagerIF" <<
|
||||
std::endl;
|
||||
#endif
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
|
||||
AcceptsTelemetryIF* tmTarget = ObjectManager::instance()->
|
||||
get<AcceptsTelemetryIF>(downlinkDestination);
|
||||
if(tmTarget == nullptr){
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TmFunnel::initialize: Downlink Destination not set." << std::endl;
|
||||
sif::error << "Make sure the downlink destination object is set up properly and implements "
|
||||
"AcceptsTelemetryIF" << std::endl;
|
||||
#endif
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
tmQueue->setDefaultDestination(tmTarget->getReportReceptionQueue());
|
||||
|
||||
// Storage destination is optional.
|
||||
if(storageDestination == objects::NO_OBJECT) {
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
AcceptsTelemetryIF* storageTarget = ObjectManager::instance()->
|
||||
get<AcceptsTelemetryIF>(storageDestination);
|
||||
if(storageTarget != nullptr) {
|
||||
storageQueue->setDefaultDestination(
|
||||
storageTarget->getReportReceptionQueue());
|
||||
}
|
||||
|
||||
return SystemObject::initialize();
|
||||
}
|
51
examples/fsfw_examples/utility/TmFunnel.h
Normal file
51
examples/fsfw_examples/utility/TmFunnel.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
#ifndef MISSION_UTILITY_TMFUNNEL_H_
|
||||
#define MISSION_UTILITY_TMFUNNEL_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
|
||||
#include <fsfw/ipc/MessageQueueIF.h>
|
||||
#include <fsfw/tmtcservices/TmTcMessage.h>
|
||||
|
||||
namespace Factory{
|
||||
void setStaticFrameworkObjectIds();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TM Recipient.
|
||||
* @details
|
||||
* Main telemetry receiver. All generated telemetry is funneled into
|
||||
* this object.
|
||||
* @ingroup utility
|
||||
* @author J. Meier
|
||||
*/
|
||||
class TmFunnel:
|
||||
public AcceptsTelemetryIF,
|
||||
public ExecutableObjectIF,
|
||||
public SystemObject {
|
||||
friend void (Factory::setStaticFrameworkObjectIds)();
|
||||
public:
|
||||
TmFunnel(object_id_t objectId, uint32_t messageDepth = 20);
|
||||
virtual ~TmFunnel();
|
||||
|
||||
virtual MessageQueueId_t getReportReceptionQueue(
|
||||
uint8_t virtualChannel = 0) override;
|
||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override;
|
||||
virtual ReturnValue_t initialize() override;
|
||||
|
||||
protected:
|
||||
static object_id_t downlinkDestination;
|
||||
static object_id_t storageDestination;
|
||||
|
||||
private:
|
||||
uint16_t sourceSequenceCount = 0;
|
||||
MessageQueueIF* tmQueue = nullptr;
|
||||
MessageQueueIF* storageQueue = nullptr;
|
||||
|
||||
StorageManagerIF* tmPool = nullptr;
|
||||
uint32_t messageDepth = 0;
|
||||
|
||||
ReturnValue_t handlePacket(TmTcMessage* message);
|
||||
};
|
||||
|
||||
#endif /* MISSION_UTILITY_TMFUNNEL_H_ */
|
97
examples/fsfw_examples/utility/compile_time.h
Normal file
97
examples/fsfw_examples/utility/compile_time.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
*
|
||||
* Created: 29.03.2018
|
||||
*
|
||||
* Authors:
|
||||
*
|
||||
* Assembled from the code released on Stackoverflow by:
|
||||
* Dennis (instructable.com/member/nqtronix) | https://stackoverflow.com/questions/23032002/c-c-how-to-get-integer-unix-timestamp-of-build-time-not-string
|
||||
* and
|
||||
* Alexis Wilke | https://stackoverflow.com/questions/10538444/do-you-know-of-a-c-macro-to-compute-unix-time-and-date
|
||||
*
|
||||
* Assembled by Jean Rabault
|
||||
*
|
||||
* UNIX_TIMESTAMP gives the UNIX timestamp (unsigned long integer of seconds since 1st Jan 1970) of compilation from macros using the compiler defined __TIME__ macro.
|
||||
* This should include Gregorian calendar leap days, in particular the 29ths of February, 100 and 400 years modulo leaps.
|
||||
*
|
||||
* Careful: __TIME__ is the local time of the computer, NOT the UTC time in general!
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef COMPILE_TIME_H_
|
||||
#define COMPILE_TIME_H_
|
||||
|
||||
// Some definitions for calculation
|
||||
#define SEC_PER_MIN 60UL
|
||||
#define SEC_PER_HOUR 3600UL
|
||||
#define SEC_PER_DAY 86400UL
|
||||
#define SEC_PER_YEAR (SEC_PER_DAY*365)
|
||||
|
||||
// extracts 1..4 characters from a string and interprets it as a decimal value
|
||||
#define CONV_STR2DEC_1(str, i) (str[i]>'0'?str[i]-'0':0)
|
||||
#define CONV_STR2DEC_2(str, i) (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
|
||||
#define CONV_STR2DEC_3(str, i) (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
|
||||
#define CONV_STR2DEC_4(str, i) (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
|
||||
|
||||
// Custom "glue logic" to convert the month name to a usable number
|
||||
#define GET_MONTH(str, i) (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 : \
|
||||
str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 : \
|
||||
str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 : \
|
||||
str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 : \
|
||||
str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 : \
|
||||
str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 : \
|
||||
str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 : \
|
||||
str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 : \
|
||||
str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 : \
|
||||
str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 : \
|
||||
str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 : \
|
||||
str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0)
|
||||
|
||||
// extract the information from the time string given by __TIME__ and __DATE__
|
||||
#define __TIME_SECONDS__ CONV_STR2DEC_2(__TIME__, 6)
|
||||
#define __TIME_MINUTES__ CONV_STR2DEC_2(__TIME__, 3)
|
||||
#define __TIME_HOURS__ CONV_STR2DEC_2(__TIME__, 0)
|
||||
#define __TIME_DAYS__ CONV_STR2DEC_2(__DATE__, 4)
|
||||
#define __TIME_MONTH__ GET_MONTH(__DATE__, 0)
|
||||
#define __TIME_YEARS__ CONV_STR2DEC_4(__DATE__, 7)
|
||||
|
||||
// Days in February
|
||||
#define _UNIX_TIMESTAMP_FDAY(year) \
|
||||
(((year) % 400) == 0UL ? 29UL : \
|
||||
(((year) % 100) == 0UL ? 28UL : \
|
||||
(((year) % 4) == 0UL ? 29UL : \
|
||||
28UL)))
|
||||
|
||||
// Days in the year
|
||||
#define _UNIX_TIMESTAMP_YDAY(year, month, day) \
|
||||
( \
|
||||
/* January */ day \
|
||||
/* February */ + (month >= 2 ? 31UL : 0UL) \
|
||||
/* March */ + (month >= 3 ? _UNIX_TIMESTAMP_FDAY(year) : 0UL) \
|
||||
/* April */ + (month >= 4 ? 31UL : 0UL) \
|
||||
/* May */ + (month >= 5 ? 30UL : 0UL) \
|
||||
/* June */ + (month >= 6 ? 31UL : 0UL) \
|
||||
/* July */ + (month >= 7 ? 30UL : 0UL) \
|
||||
/* August */ + (month >= 8 ? 31UL : 0UL) \
|
||||
/* September */+ (month >= 9 ? 31UL : 0UL) \
|
||||
/* October */ + (month >= 10 ? 30UL : 0UL) \
|
||||
/* November */ + (month >= 11 ? 31UL : 0UL) \
|
||||
/* December */ + (month >= 12 ? 30UL : 0UL) \
|
||||
)
|
||||
|
||||
// get the UNIX timestamp from a digits representation
|
||||
#define _UNIX_TIMESTAMP(year, month, day, hour, minute, second) \
|
||||
( /* time */ second \
|
||||
+ minute * SEC_PER_MIN \
|
||||
+ hour * SEC_PER_HOUR \
|
||||
+ /* year day (month + day) */ (_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * SEC_PER_DAY \
|
||||
+ /* year */ (year - 1970UL) * SEC_PER_YEAR \
|
||||
+ ((year - 1969UL) / 4UL) * SEC_PER_DAY \
|
||||
- ((year - 1901UL) / 100UL) * SEC_PER_DAY \
|
||||
+ ((year - 1601UL) / 400UL) * SEC_PER_DAY \
|
||||
)
|
||||
|
||||
// the UNIX timestamp
|
||||
#define UNIX_TIMESTAMP (_UNIX_TIMESTAMP(__TIME_YEARS__, __TIME_MONTH__, __TIME_DAYS__, __TIME_HOURS__, __TIME_MINUTES__, __TIME_SECONDS__))
|
||||
|
||||
#endif
|
22
examples/fsfw_examples/utility/utility.cpp
Normal file
22
examples/fsfw_examples/utility/utility.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "utility.h"
|
||||
#include <FSFWConfig.h>
|
||||
#include <OBSWVersion.h>
|
||||
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
void utility::commonInitPrint(const char *const os, const char* const board) {
|
||||
if(os == nullptr or board == nullptr) {
|
||||
return;
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
std::cout << "-- FSFW Example (" << os<< ") v" << FSFW_EXAMPLE_VERSION << "." <<
|
||||
FSFW_EXAMPLE_SUBVERSION << "." << FSFW_EXAMPLE_REVISION << " --" << std::endl;
|
||||
std::cout << "-- Compiled for " << board << " --" << std::endl;
|
||||
std::cout << "-- Compiled on " << __DATE__ << " " << __TIME__ << " --" << std::endl;
|
||||
#else
|
||||
printf("\n\r-- FSFW Example (%s) v%d.%d.%d --\n", os, FSFW_EXAMPLE_VERSION,
|
||||
FSFW_EXAMPLE_SUBVERSION, FSFW_EXAMPLE_REVISION);
|
||||
printf("-- Compiled for %s --\n", board);
|
||||
printf("-- Compiled on %s %s --\n", __DATE__, __TIME__);
|
||||
#endif
|
||||
}
|
11
examples/fsfw_examples/utility/utility.h
Normal file
11
examples/fsfw_examples/utility/utility.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COMMON_UTILITY_UTILITY_H_
|
||||
#define COMMON_UTILITY_UTILITY_H_
|
||||
|
||||
namespace utility {
|
||||
|
||||
void commonInitPrint(const char *const os, const char* const board);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* COMMON_UTILITY_UTILITY_H_ */
|
|
@ -1,7 +1,3 @@
|
|||
if(FSFW_ADD_INTEGRATION_TEST_MODULES)
|
||||
add_subdirectory(integration)
|
||||
endif()
|
||||
|
||||
if(FSFW_ADD_INTERNAL_TESTS)
|
||||
add_subdirectory(internal)
|
||||
endif()
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
add_subdirectory(devices)
|
||||
add_subdirectory(controller)
|
Loading…
Reference in New Issue
Block a user