Compare commits
31 Commits
7ab3e36d9c
...
mueller/ex
Author | SHA1 | Date | |
---|---|---|---|
349ada87f1 | |||
db0af8b29a | |||
127a0f6e16 | |||
693676304a | |||
cf8552e950 | |||
da0886cf56 | |||
b94e83612e | |||
44c09ef877 | |||
5526abb8fb | |||
19a8ba7640 | |||
172df0b570 | |||
253780d5d4 | |||
d5a342a509 | |||
c548d3b507 | |||
afe0a13566 | |||
27215b67aa | |||
0ad5c91fc7 | |||
abee0930f9 | |||
49566cd130 | |||
e4879130b0 | |||
1176959a93 | |||
20842a26af | |||
ff6025d04d | |||
0901604854 | |||
112adcbb64 | |||
edaccc0dbd | |||
39e0a0ca0f | |||
d79ab3df35 | |||
c60e8c8523 | |||
64935286e1 | |||
77bee78a2b |
@ -1,8 +1,10 @@
|
||||
add_subdirectory(mission)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(config)
|
||||
add_subdirectory(utility)
|
||||
add_subdirectory(example)
|
||||
|
||||
target_include_directories(${TARGET_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if(TGT_BSP MATCHES "arm/stm32h743zi-nucleo")
|
||||
add_subdirectory(stm32h7)
|
||||
endif()
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define COMMON_OBSWVERSION_H_
|
||||
|
||||
#define FSFW_EXAMPLE_VERSION 1
|
||||
#define FSFW_EXAMPLE_SUBVERSION 2
|
||||
#define FSFW_EXAMPLE_SUBVERSION 4
|
||||
#define FSFW_EXAMPLE_REVISION 0
|
||||
|
||||
#endif /* COMMON_OBSWVERSION_H_ */
|
||||
|
@ -11,6 +11,9 @@
|
||||
|
||||
#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
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include <pollingsequence/pollingSequenceFactory.h>
|
||||
#include <objects/systemObjectList.h>
|
||||
#include "pollingsequence/pollingSequenceFactory.h"
|
||||
#include "objects/systemObjectList.h"
|
||||
|
||||
#include "example/test/FsfwExampleTask.h"
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
|
||||
#include <test/FsfwExampleTask.h>
|
||||
|
||||
|
||||
ReturnValue_t pst::pollingSequenceExamples(FixedTimeslotTaskIF* thisSequence) {
|
||||
uint32_t length = thisSequence->getPeriodMs();
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace SUBSYSTEM_ID {
|
||||
enum commonSubsystemId: uint8_t {
|
||||
COMMON_SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE,
|
||||
TEST_TASK_ID = 105,
|
||||
COMMON_SUBSYSTEM_ID_END
|
||||
};
|
||||
}
|
||||
|
BIN
doc/images/FSFW_Logo_V3_bw.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
doc/images/build_cfg_mingw.PNG
Normal file
After Width: | Height: | Size: 96 KiB |
BIN
doc/images/cmake.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
doc/images/eclipse/eclipse-cross-compile-linux.png
Normal file
After Width: | Height: | Size: 109 KiB |
BIN
doc/images/eclipse/eclipse-cross-compile-win.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
doc/images/eclipse/eclipse-indexer.png
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
doc/images/eclipse/eclipse-rpi.png
Normal file
After Width: | Height: | Size: 151 KiB |
BIN
doc/images/eclipse/rpi-win-environment.PNG
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
doc/images/eclipse_cfg.PNG
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
doc/images/eclipse_logo_colour.png
Normal file
After Width: | Height: | Size: 34 KiB |
@ -1,5 +1,5 @@
|
||||
add_subdirectory(controller)
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(devices)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(utility)
|
||||
add_subdirectory(controller)
|
||||
add_subdirectory(assemblies)
|
0
example/controller/CMakeLists.txt
Normal file
@ -1,24 +1,26 @@
|
||||
#include "GenericFactory.h"
|
||||
|
||||
#include "OBSWConfig.h"
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "tmtc/apid.h"
|
||||
#include "tmtc/pusIds.h"
|
||||
#include "objects/systemObjectList.h"
|
||||
|
||||
#include "test/FsfwExampleTask.h"
|
||||
#include "test/FsfwReaderTask.h"
|
||||
#include "example/utility/TmFunnel.h"
|
||||
#include "example/test/FsfwExampleTask.h"
|
||||
#include "example/test/FsfwReaderTask.h"
|
||||
|
||||
#include "mission/assemblies/TestAssembly.h"
|
||||
#include "mission/devices/TestCookie.h"
|
||||
#include "mission/devices/TestDeviceHandler.h"
|
||||
#include "mission/devices/TestEchoComIF.h"
|
||||
#include "mission/utility/TmFunnel.h"
|
||||
#include "mission/controller/TestController.h"
|
||||
#include "fsfw_tests/internal/InternalUnitTester.h"
|
||||
#include "fsfw_tests/integration/assemblies/TestAssembly.h"
|
||||
#include "fsfw_tests/integration/devices/TestCookie.h"
|
||||
#include "fsfw_tests/integration/devices/TestDeviceHandler.h"
|
||||
#include "fsfw_tests/integration/devices/TestEchoComIF.h"
|
||||
#include "fsfw_tests/integration/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/internalerror/InternalErrorReporter.h"
|
||||
#include "fsfw/pus/CService200ModeCommanding.h"
|
||||
#include "fsfw/pus/Service17Test.h"
|
||||
#include "fsfw/pus/Service1TelecommandVerification.h"
|
||||
@ -31,7 +33,7 @@
|
||||
#include "fsfw/tcdistribution/CCSDSDistributor.h"
|
||||
#include "fsfw/tcdistribution/PUSDistributor.h"
|
||||
#include "fsfw/timemanager/TimeStamper.h"
|
||||
#include "fsfw/tmtcpacket/pus/TmPacketStored.h"
|
||||
#include "fsfw/tmtcpacket/pus/tm.h"
|
||||
|
||||
|
||||
|
||||
@ -76,10 +78,9 @@ void ObjectFactory::produceGenericObjects() {
|
||||
new FsfwExampleTask(objects::TEST_DUMMY_3);
|
||||
|
||||
|
||||
#if OBSW_TASK_EXAMPLE_PRINTOUT == 1
|
||||
bool enablePrintout = true;
|
||||
#else
|
||||
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 */
|
||||
@ -94,17 +95,18 @@ void ObjectFactory::produceGenericObjects() {
|
||||
|
||||
/* Demo device handler object */
|
||||
size_t expectedMaxReplyLen = 64;
|
||||
CookieIF* testCookie = new DummyCookie(
|
||||
CookieIF* testCookie = new TestCookie(
|
||||
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),
|
||||
testCookie = new TestCookie(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);
|
||||
new TestAssembly(objects::TEST_ASSEMBLY, objects::NO_OBJECT, objects::TEST_DEVICE_HANDLER_0,
|
||||
objects::TEST_DEVICE_HANDLER_1);
|
||||
|
||||
#endif /* OBSW_ADD_DEVICE_HANDLER_DEMO == 1 */
|
||||
|
||||
@ -117,6 +119,17 @@ void ObjectFactory::produceGenericObjects() {
|
||||
new TestController(objects::TEST_CONTROLLER);
|
||||
|
||||
#endif /* OBSW_ADD_CONTROLLER_DEMO == 1 */
|
||||
|
||||
#if OBSW_PERFORM_INTERNAL_UNITTEST == 1
|
||||
InternalUnitTester::TestConfig testCfg;
|
||||
testCfg.testArrayPrinter = false;
|
||||
#if defined FSFW_OSAL_HOST
|
||||
// Not implemented yet for hosted OSAL (requires C++20)
|
||||
testCfg.testSemaphores = false;
|
||||
#endif
|
||||
InternalUnitTester unittester;
|
||||
unittester.performTests(testCfg);
|
||||
#endif /* OBSW_PERFORM_INTERNAL_UNITTEST == 1 */
|
||||
}
|
||||
|
||||
void Factory::setStaticFrameworkObjectIds() {
|
0
example/devices/CMakeLists.txt
Normal file
12
example/devices/TestDeviceHandler.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef EXAMPLE_COMMON_DEVICES_TESTDEVICEHANDLER_H_
|
||||
#define EXAMPLE_COMMON_DEVICES_TESTDEVICEHANDLER_H_
|
||||
|
||||
//#include "fsfw_tests/integration/TestDeviceHandler.h"
|
||||
//
|
||||
//class FsfwTestDeviceHandler: public TestDeviceHandler {
|
||||
//
|
||||
//};
|
||||
|
||||
|
||||
|
||||
#endif /* EXAMPLE_COMMON_DEVICES_TESTDEVICEHANDLER_H_ */
|
5
example/test/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
FsfwReaderTask.cpp
|
||||
FsfwExampleTask.cpp
|
||||
MutexExample.cpp
|
||||
)
|
@ -1,3 +1,4 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
utility.cpp
|
||||
TmFunnel.cpp
|
||||
)
|
10
example/utility/PusPacketCreator.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include <fsfw/tmtcpacket/pus/tc.h>
|
||||
#include <fsfw/tmtcpacket/pus/tm.h>
|
||||
#include <fsfw/globalfunctions/arrayprinter.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
#include <mission/utility/PusPacketCreator.h>
|
||||
|
||||
void PusPacketCreator::createPusPacketAndPrint() {
|
||||
// TODO: use TC packet stored here instead..
|
||||
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
#include "TmFunnel.h"
|
||||
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
|
||||
#include <fsfw/tmtcpacket/pus/tm.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
#include <fsfw/tmtcpacket/pus/TmPacketPusC.h>
|
||||
#include <mission/utility/TmFunnel.h>
|
||||
|
||||
object_id_t TmFunnel::downlinkDestination = objects::NO_OBJECT;
|
||||
object_id_t TmFunnel::storageDestination = objects::NO_OBJECT;
|
@ -1,3 +0,0 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
TestAssembly.cpp
|
||||
)
|
@ -1,200 +0,0 @@
|
||||
#include "commonSystemObjects.h"
|
||||
|
||||
#include <mission/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;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
#ifndef MISSION_ASSEMBLIES_TESTASSEMBLY_H_
|
||||
#define MISSION_ASSEMBLIES_TESTASSEMBLY_H_
|
||||
|
||||
#include <fsfw/devicehandlers/AssemblyBase.h>
|
||||
#include "../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_ */
|
@ -1,3 +0,0 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
TestController.cpp
|
||||
)
|
@ -1,214 +0,0 @@
|
||||
#include "TestController.h"
|
||||
#include "OBSWConfig.h"
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
TestController::TestController(object_id_t objectId, size_t commandQueueDepth):
|
||||
ExtendedControllerBase(objectId, objects::NO_OBJECT, commandQueueDepth),
|
||||
deviceDataset0(objects::TEST_DEVICE_HANDLER_0),
|
||||
deviceDataset1(objects::TEST_DEVICE_HANDLER_1) {
|
||||
}
|
||||
|
||||
TestController::~TestController() {
|
||||
}
|
||||
|
||||
ReturnValue_t TestController::handleCommandMessage(CommandMessage *message) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void TestController::performControlOperation() {
|
||||
/* We will trace vaiables if we received an update notification or snapshots */
|
||||
#if OBSW_CONTROLLER_PRINTOUT == 1
|
||||
if(not traceVariable) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(currentTraceType) {
|
||||
case(NONE): {
|
||||
break;
|
||||
}
|
||||
case(TRACE_DEV_0_UINT8): {
|
||||
if(traceCounter == 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "Tracing finished" << std::endl;
|
||||
#else
|
||||
sif::printInfo("Tracing finished\n");
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
traceVariable = false;
|
||||
traceCounter = traceCycles;
|
||||
currentTraceType = TraceTypes::NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
PoolReadGuard readHelper(&deviceDataset0.testUint8Var);
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "Tracing device 0 variable 0 (UINT8), current value: " <<
|
||||
static_cast<int>(deviceDataset0.testUint8Var.value) << std::endl;
|
||||
#else
|
||||
sif::printInfo("Tracing device 0 variable 0 (UINT8), current value: %d\n",
|
||||
deviceDataset0.testUint8Var.value);
|
||||
#endif
|
||||
traceCounter--;
|
||||
break;
|
||||
}
|
||||
case(TRACE_DEV_0_VECTOR): {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* OBSW_CONTROLLER_PRINTOUT == 1 */
|
||||
}
|
||||
|
||||
void TestController::handleChangedDataset(sid_t sid, store_address_t storeId, bool* clearMessage) {
|
||||
using namespace std;
|
||||
|
||||
#if OBSW_CONTROLLER_PRINTOUT == 1
|
||||
char const* printout = nullptr;
|
||||
if(storeId == storeId::INVALID_STORE_ADDRESS) {
|
||||
printout = "Notification";
|
||||
}
|
||||
else {
|
||||
printout = "Snapshot";
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestController::handleChangedDataset: " << printout << " update from object "
|
||||
"ID " << setw(8) << setfill('0') << hex << sid.objectId <<
|
||||
" and set ID " << sid.ownerSetId << dec << setfill(' ') << endl;
|
||||
#else
|
||||
sif::printInfo("TestController::handleChangedPoolVariable: %s update from object ID 0x%08x and "
|
||||
"set ID %lu\n", printout, sid.objectId, sid.ownerSetId);
|
||||
#endif
|
||||
|
||||
if (storeId == storeId::INVALID_STORE_ADDRESS) {
|
||||
if(sid.objectId == objects::TEST_DEVICE_HANDLER_0) {
|
||||
PoolReadGuard readHelper(&deviceDataset0.testFloat3Vec);
|
||||
float floatVec[3];
|
||||
floatVec[0] = deviceDataset0.testFloat3Vec.value[0];
|
||||
floatVec[1] = deviceDataset0.testFloat3Vec.value[1];
|
||||
floatVec[2] = deviceDataset0.testFloat3Vec.value[2];
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "Current float vector (3) values: [" << floatVec[0] << ", " <<
|
||||
floatVec[1] << ", " << floatVec[2] << "]" << std::endl;
|
||||
#else
|
||||
sif::printInfo("Current float vector (3) values: [%f, %f, %f]\n",
|
||||
floatVec[0], floatVec[1], floatVec[2]);
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
}
|
||||
}
|
||||
#endif /* OBSW_CONTROLLER_PRINTOUT == 1 */
|
||||
|
||||
/* We will trace the variables for snapshots and update notifications */
|
||||
if(not traceVariable) {
|
||||
traceVariable = true;
|
||||
traceCounter = traceCycles;
|
||||
currentTraceType = TraceTypes::TRACE_DEV_0_VECTOR;
|
||||
}
|
||||
}
|
||||
|
||||
void TestController::handleChangedPoolVariable(gp_id_t globPoolId, store_address_t storeId,
|
||||
bool* clearMessage) {
|
||||
using namespace std;
|
||||
|
||||
#if OBSW_CONTROLLER_PRINTOUT == 1
|
||||
char const* printout = nullptr;
|
||||
if (storeId == storeId::INVALID_STORE_ADDRESS) {
|
||||
printout = "Notification";
|
||||
}
|
||||
else {
|
||||
printout = "Snapshot";
|
||||
}
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestController::handleChangedPoolVariable: " << printout << " update from object "
|
||||
"ID 0x" << setw(8) << setfill('0') << hex << globPoolId.objectId <<
|
||||
" and local pool ID " << globPoolId.localPoolId << dec << setfill(' ') << endl;
|
||||
#else
|
||||
sif::printInfo("TestController::handleChangedPoolVariable: %s update from object ID 0x%08x and "
|
||||
"local pool ID %lu\n", printout, globPoolId.objectId, globPoolId.localPoolId);
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
|
||||
if (storeId == storeId::INVALID_STORE_ADDRESS) {
|
||||
if(globPoolId.objectId == objects::TEST_DEVICE_HANDLER_0) {
|
||||
PoolReadGuard readHelper(&deviceDataset0.testUint8Var);
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "Current test variable 0 (UINT8) value: " << static_cast<int>(
|
||||
deviceDataset0.testUint8Var.value) << std::endl;
|
||||
#else
|
||||
sif::printInfo("Current test variable 0 (UINT8) value %d\n",
|
||||
deviceDataset0.testUint8Var.value);
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
}
|
||||
}
|
||||
#endif /* OBSW_CONTROLLER_PRINTOUT == 1 */
|
||||
|
||||
/* We will trace the variables for snapshots and update notifications */
|
||||
if(not traceVariable) {
|
||||
traceVariable = true;
|
||||
traceCounter = traceCycles;
|
||||
currentTraceType = TraceTypes::TRACE_DEV_0_UINT8;
|
||||
}
|
||||
}
|
||||
|
||||
LocalPoolDataSetBase* TestController::getDataSetHandle(sid_t sid) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ReturnValue_t TestController::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
|
||||
LocalDataPoolManager &poolManager) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestController::initializeAfterTaskCreation() {
|
||||
namespace td = testdevice;
|
||||
HasLocalDataPoolIF* device0 = ObjectManager::instance()->get<HasLocalDataPoolIF>(
|
||||
objects::TEST_DEVICE_HANDLER_0);
|
||||
if(device0 == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TestController::initializeAfterTaskCreation: Test device handler 0 "
|
||||
"handle invalid!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("TestController::initializeAfterTaskCreation: Test device handler 0 "
|
||||
"handle invalid!");
|
||||
#endif
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
ProvidesDataPoolSubscriptionIF* subscriptionIF = device0->getSubscriptionInterface();
|
||||
if(subscriptionIF != nullptr) {
|
||||
/* For DEVICE_0, we only subscribe for notifications */
|
||||
subscriptionIF->subscribeForSetUpdateMessage(td::TEST_SET_ID, getObjectId(),
|
||||
getCommandQueue(), false);
|
||||
subscriptionIF->subscribeForVariableUpdateMessage(td::PoolIds::TEST_UINT8_ID,
|
||||
getObjectId(), getCommandQueue(), false);
|
||||
}
|
||||
|
||||
|
||||
HasLocalDataPoolIF* device1 = ObjectManager::instance()->get<HasLocalDataPoolIF>(
|
||||
objects::TEST_DEVICE_HANDLER_1);
|
||||
if(device1 == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TestController::initializeAfterTaskCreation: Test device handler 1 "
|
||||
"handle invalid!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("TestController::initializeAfterTaskCreation: Test device handler 1 "
|
||||
"handle invalid!");
|
||||
#endif
|
||||
}
|
||||
|
||||
subscriptionIF = device1->getSubscriptionInterface();
|
||||
if(subscriptionIF != nullptr) {
|
||||
/* For DEVICE_1, we will subscribe for snapshots */
|
||||
subscriptionIF->subscribeForSetUpdateMessage(td::TEST_SET_ID, getObjectId(),
|
||||
getCommandQueue(), true);
|
||||
subscriptionIF->subscribeForVariableUpdateMessage(td::PoolIds::TEST_UINT8_ID,
|
||||
getObjectId(), getCommandQueue(), true);
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestController::checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
@ -1,50 +0,0 @@
|
||||
#ifndef MISSION_CONTROLLER_TESTCONTROLLER_H_
|
||||
#define MISSION_CONTROLLER_TESTCONTROLLER_H_
|
||||
|
||||
#include "../devices/devicedefinitions/testDeviceDefinitions.h"
|
||||
#include <fsfw/controller/ExtendedControllerBase.h>
|
||||
|
||||
|
||||
class TestController:
|
||||
public ExtendedControllerBase {
|
||||
public:
|
||||
TestController(object_id_t objectId, size_t commandQueueDepth = 10);
|
||||
virtual~ TestController();
|
||||
protected:
|
||||
testdevice::TestDataSet deviceDataset0;
|
||||
testdevice::TestDataSet deviceDataset1;
|
||||
|
||||
/* Extended Controller Base overrides */
|
||||
ReturnValue_t handleCommandMessage(CommandMessage *message) override;
|
||||
void performControlOperation() override;
|
||||
|
||||
/* HasLocalDatapoolIF callbacks */
|
||||
void handleChangedDataset(sid_t sid, store_address_t storeId, bool* clearMessage) override;
|
||||
void handleChangedPoolVariable(gp_id_t globPoolId, store_address_t storeId,
|
||||
bool* clearMessage) override;
|
||||
|
||||
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
|
||||
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) override;
|
||||
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override;
|
||||
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
private:
|
||||
|
||||
bool traceVariable = false;
|
||||
uint8_t traceCycles = 5;
|
||||
uint8_t traceCounter = traceCycles;
|
||||
|
||||
enum TraceTypes {
|
||||
NONE,
|
||||
TRACE_DEV_0_UINT8,
|
||||
TRACE_DEV_0_VECTOR
|
||||
};
|
||||
TraceTypes currentTraceType = TraceTypes::NONE;
|
||||
};
|
||||
|
||||
|
||||
#endif /* MISSION_CONTROLLER_TESTCONTROLLER_H_ */
|
@ -1,18 +0,0 @@
|
||||
#ifndef MISSION_CONTROLLER_CTRLDEFINITIONS_TESTCTRLDEFINITIONS_H_
|
||||
#define MISSION_CONTROLLER_CTRLDEFINITIONS_TESTCTRLDEFINITIONS_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
#include <OBSWConfig.h>
|
||||
|
||||
namespace testcontroller {
|
||||
|
||||
enum sourceObjectIds: object_id_t {
|
||||
DEVICE_0_ID = objects::TEST_DEVICE_HANDLER_0,
|
||||
DEVICE_1_ID = objects::TEST_DEVICE_HANDLER_1,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* MISSION_CONTROLLER_CTRLDEFINITIONS_TESTCTRLDEFINITIONS_H_ */
|
@ -1,6 +0,0 @@
|
||||
target_sources(${TARGET_NAME}
|
||||
PRIVATE
|
||||
TestCookie.cpp
|
||||
TestDeviceHandler.cpp
|
||||
TestEchoComIF.cpp
|
||||
)
|
@ -1,14 +0,0 @@
|
||||
#include "TestCookie.h"
|
||||
|
||||
DummyCookie::DummyCookie(address_t address, size_t replyMaxLen):
|
||||
address(address), replyMaxLen(replyMaxLen) {}
|
||||
|
||||
DummyCookie::~DummyCookie() {}
|
||||
|
||||
address_t DummyCookie::getAddress() const {
|
||||
return address;
|
||||
}
|
||||
|
||||
size_t DummyCookie::getReplyMaxLen() const {
|
||||
return replyMaxLen;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
#ifndef MISSION_DEVICES_TESTCOOKIE_H_
|
||||
#define MISSION_DEVICES_TESTCOOKIE_H_
|
||||
|
||||
#include <fsfw/devicehandlers/CookieIF.h>
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* @brief Really simple cookie which does not do a lot.
|
||||
*/
|
||||
class DummyCookie: public CookieIF {
|
||||
public:
|
||||
DummyCookie(address_t address, size_t maxReplyLen);
|
||||
virtual ~DummyCookie();
|
||||
|
||||
address_t getAddress() const;
|
||||
size_t getReplyMaxLen() const;
|
||||
private:
|
||||
address_t address = 0;
|
||||
size_t replyMaxLen = 0;
|
||||
};
|
||||
|
||||
#endif /* MISSION_DEVICES_TESTCOOKIE_H_ */
|
@ -1,804 +0,0 @@
|
||||
#include "TestDeviceHandler.h"
|
||||
#include <OBSWConfig.h>
|
||||
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
TestDevice::TestDevice(object_id_t objectId, object_id_t comIF,
|
||||
CookieIF * cookie, testdevice::DeviceIndex deviceIdx, bool fullInfoPrintout,
|
||||
bool changingDataset):
|
||||
DeviceHandlerBase(objectId, comIF, cookie), deviceIdx(deviceIdx),
|
||||
dataset(this), fullInfoPrintout(fullInfoPrintout) {
|
||||
}
|
||||
|
||||
TestDevice::~TestDevice() {}
|
||||
|
||||
void TestDevice::performOperationHook() {
|
||||
if(periodicPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::performOperationHook: Alive!" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::performOperationHook: Alive!", deviceIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
if(oneShot) {
|
||||
oneShot = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestDevice::doStartUp() {
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::doStartUp: Switching On" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::doStartUp: Switching On\n", static_cast<int>(deviceIdx));
|
||||
#endif
|
||||
}
|
||||
|
||||
setMode(_MODE_TO_ON);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void TestDevice::doShutDown() {
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::doShutDown: Switching Off" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::doShutDown: Switching Off\n", static_cast<int>(deviceIdx));
|
||||
#endif
|
||||
}
|
||||
|
||||
setMode(_MODE_SHUT_DOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t TestDevice::buildNormalDeviceCommand(DeviceCommandId_t* id) {
|
||||
using namespace testdevice;
|
||||
*id = TEST_NORMAL_MODE_CMD;
|
||||
if(DeviceHandlerBase::isAwaitingReply()) {
|
||||
return NOTHING_TO_SEND;
|
||||
}
|
||||
return buildCommandFromCommand(*id, nullptr, 0);
|
||||
}
|
||||
|
||||
ReturnValue_t TestDevice::buildTransitionDeviceCommand(DeviceCommandId_t* id) {
|
||||
if(mode == _MODE_TO_ON) {
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::buildTransitionDeviceCommand: Was called"
|
||||
" from _MODE_TO_ON mode" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::buildTransitionDeviceCommand: "
|
||||
"Was called from _MODE_TO_ON mode\n", deviceIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
if(mode == _MODE_TO_NORMAL) {
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::buildTransitionDeviceCommand: Was called "
|
||||
"from _MODE_TO_NORMAL mode" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::buildTransitionDeviceCommand: Was called from "
|
||||
" _MODE_TO_NORMAL mode\n", deviceIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
setMode(MODE_NORMAL);
|
||||
}
|
||||
if(mode == _MODE_SHUT_DOWN) {
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::buildTransitionDeviceCommand: Was called "
|
||||
"from _MODE_SHUT_DOWN mode" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::buildTransitionDeviceCommand: Was called from "
|
||||
"_MODE_SHUT_DOWN mode\n", deviceIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
setMode(MODE_OFF);
|
||||
}
|
||||
return NOTHING_TO_SEND;
|
||||
}
|
||||
|
||||
void TestDevice::doTransition(Mode_t modeFrom, Submode_t submodeFrom) {
|
||||
if(mode == _MODE_TO_NORMAL) {
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::doTransition: Custom transition to "
|
||||
"normal mode" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::doTransition: Custom transition to normal mode\n",
|
||||
deviceIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
DeviceHandlerBase::doTransition(modeFrom, submodeFrom);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t TestDevice::buildCommandFromCommand(
|
||||
DeviceCommandId_t deviceCommand, const uint8_t* commandData,
|
||||
size_t commandDataLen) {
|
||||
using namespace testdevice;
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
switch(deviceCommand) {
|
||||
case(TEST_NORMAL_MODE_CMD): {
|
||||
commandSent = true;
|
||||
result = buildNormalModeCommand(deviceCommand, commandData, commandDataLen);
|
||||
break;
|
||||
}
|
||||
|
||||
case(TEST_COMMAND_0): {
|
||||
commandSent = true;
|
||||
result = buildTestCommand0(deviceCommand, commandData, commandDataLen);
|
||||
break;
|
||||
}
|
||||
|
||||
case(TEST_COMMAND_1): {
|
||||
commandSent = true;
|
||||
result = buildTestCommand1(deviceCommand, commandData, commandDataLen);
|
||||
break;
|
||||
}
|
||||
case(TEST_NOTIF_SNAPSHOT_VAR): {
|
||||
if(changingDatasets) {
|
||||
changingDatasets = false;
|
||||
}
|
||||
|
||||
PoolReadGuard readHelper(&dataset.testUint8Var);
|
||||
if(deviceIdx == testdevice::DeviceIndex::DEVICE_0) {
|
||||
/* This will trigger a variable notification to the demo controller */
|
||||
dataset.testUint8Var = 220;
|
||||
dataset.testUint8Var.setValid(true);
|
||||
}
|
||||
else if(deviceIdx == testdevice::DeviceIndex::DEVICE_1) {
|
||||
/* This will trigger a variable snapshot to the demo controller */
|
||||
dataset.testUint8Var = 30;
|
||||
dataset.testUint8Var.setValid(true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case(TEST_NOTIF_SNAPSHOT_SET): {
|
||||
if(changingDatasets) {
|
||||
changingDatasets = false;
|
||||
}
|
||||
|
||||
PoolReadGuard readHelper(&dataset.testFloat3Vec);
|
||||
|
||||
if(deviceIdx == testdevice::DeviceIndex::DEVICE_0) {
|
||||
/* This will trigger a variable notification to the demo controller */
|
||||
dataset.testFloat3Vec.value[0] = 60;
|
||||
dataset.testFloat3Vec.value[1] = 70;
|
||||
dataset.testFloat3Vec.value[2] = 55;
|
||||
dataset.testFloat3Vec.setValid(true);
|
||||
}
|
||||
else if(deviceIdx == testdevice::DeviceIndex::DEVICE_1) {
|
||||
/* This will trigger a variable notification to the demo controller */
|
||||
dataset.testFloat3Vec.value[0] = -60;
|
||||
dataset.testFloat3Vec.value[1] = -70;
|
||||
dataset.testFloat3Vec.value[2] = -55;
|
||||
dataset.testFloat3Vec.setValid(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
result = DeviceHandlerIF::COMMAND_NOT_SUPPORTED;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t TestDevice::buildNormalModeCommand(DeviceCommandId_t deviceCommand,
|
||||
const uint8_t* commandData, size_t commandDataLen) {
|
||||
if(fullInfoPrintout) {
|
||||
#if OBSW_VERBOSE_LEVEL >= 3
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice::buildTestCommand1: Building normal command" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice::buildTestCommand1: Building command from TEST_COMMAND_1\n");
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif /* OBSW_VERBOSE_LEVEL >= 3 */
|
||||
}
|
||||
|
||||
if(commandDataLen > MAX_BUFFER_SIZE - sizeof(DeviceCommandId_t)) {
|
||||
return DeviceHandlerIF::INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS;
|
||||
}
|
||||
/* The command is passed on in the command buffer as it is */
|
||||
passOnCommand(deviceCommand, commandData, commandDataLen);
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestDevice::buildTestCommand0(DeviceCommandId_t deviceCommand,
|
||||
const uint8_t* commandData, size_t commandDataLen) {
|
||||
using namespace testdevice;
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::buildTestCommand0: Executing simple command "
|
||||
" with completion reply" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::buildTestCommand0: Executing simple command with "
|
||||
"completion reply\n", deviceIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
if(commandDataLen > MAX_BUFFER_SIZE - sizeof(DeviceCommandId_t)) {
|
||||
return DeviceHandlerIF::INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS;
|
||||
}
|
||||
|
||||
/* The command is passed on in the command buffer as it is */
|
||||
passOnCommand(deviceCommand, commandData, commandDataLen);
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestDevice::buildTestCommand1(DeviceCommandId_t deviceCommand,
|
||||
const uint8_t* commandData,
|
||||
size_t commandDataLen) {
|
||||
using namespace testdevice;
|
||||
if(commandDataLen < 7) {
|
||||
return DeviceHandlerIF::INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS;
|
||||
}
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::buildTestCommand1: Executing command with "
|
||||
"data reply" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d:buildTestCommand1: Executing command with data reply\n",
|
||||
deviceIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
deviceCommand = EndianConverter::convertBigEndian(deviceCommand);
|
||||
memcpy(commandBuffer, &deviceCommand, sizeof(deviceCommand));
|
||||
|
||||
/* Assign and check parameters */
|
||||
uint16_t parameter1 = 0;
|
||||
size_t size = commandDataLen;
|
||||
ReturnValue_t result = SerializeAdapter::deSerialize(¶meter1,
|
||||
&commandData, &size, SerializeIF::Endianness::BIG);
|
||||
if(result == HasReturnvaluesIF::RETURN_FAILED) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Parameter 1 needs to be correct */
|
||||
if(parameter1 != testdevice::COMMAND_1_PARAM1) {
|
||||
return DeviceHandlerIF::INVALID_COMMAND_PARAMETER;
|
||||
}
|
||||
uint64_t parameter2 = 0;
|
||||
result = SerializeAdapter::deSerialize(¶meter2,
|
||||
&commandData, &size, SerializeIF::Endianness::BIG);
|
||||
if(parameter2!= testdevice::COMMAND_1_PARAM2){
|
||||
return DeviceHandlerIF::INVALID_COMMAND_PARAMETER;
|
||||
}
|
||||
|
||||
/* Pass on the parameters to the Echo IF */
|
||||
commandBuffer[4] = (parameter1 & 0xFF00) >> 8;
|
||||
commandBuffer[5] = (parameter1 & 0xFF);
|
||||
parameter2 = EndianConverter::convertBigEndian(parameter2);
|
||||
memcpy(commandBuffer + 6, ¶meter2, sizeof(parameter2));
|
||||
rawPacket = commandBuffer;
|
||||
rawPacketLen = sizeof(deviceCommand) + sizeof(parameter1) +
|
||||
sizeof(parameter2);
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void TestDevice::passOnCommand(DeviceCommandId_t command, const uint8_t *commandData,
|
||||
size_t commandDataLen) {
|
||||
DeviceCommandId_t deviceCommandBe = EndianConverter::convertBigEndian(command);
|
||||
memcpy(commandBuffer, &deviceCommandBe, sizeof(deviceCommandBe));
|
||||
memcpy(commandBuffer + 4, commandData, commandDataLen);
|
||||
rawPacket = commandBuffer;
|
||||
rawPacketLen = sizeof(deviceCommandBe) + commandDataLen;
|
||||
}
|
||||
|
||||
void TestDevice::fillCommandAndReplyMap() {
|
||||
namespace td = testdevice;
|
||||
insertInCommandAndReplyMap(testdevice::TEST_NORMAL_MODE_CMD, 5, &dataset);
|
||||
insertInCommandAndReplyMap(testdevice::TEST_COMMAND_0, 5);
|
||||
insertInCommandAndReplyMap(testdevice::TEST_COMMAND_1, 5);
|
||||
|
||||
/* No reply expected for these commands */
|
||||
insertInCommandMap(td::TEST_NOTIF_SNAPSHOT_SET);
|
||||
insertInCommandMap(td::TEST_NOTIF_SNAPSHOT_VAR);
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t TestDevice::scanForReply(const uint8_t *start, size_t len,
|
||||
DeviceCommandId_t *foundId, size_t *foundLen) {
|
||||
using namespace testdevice;
|
||||
|
||||
/* Unless a command was sent explicitely, we don't expect any replies and ignore this
|
||||
the packet. On a real device, there might be replies which are sent without a previous
|
||||
command. */
|
||||
if(not commandSent) {
|
||||
return DeviceHandlerBase::IGNORE_FULL_PACKET;
|
||||
}
|
||||
else {
|
||||
commandSent = false;
|
||||
}
|
||||
|
||||
if(len < sizeof(object_id_t)) {
|
||||
return DeviceHandlerIF::LENGTH_MISSMATCH;
|
||||
}
|
||||
|
||||
size_t size = len;
|
||||
ReturnValue_t result = SerializeAdapter::deSerialize(foundId, &start, &size,
|
||||
SerializeIF::Endianness::BIG);
|
||||
if (result != RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
DeviceCommandId_t pendingCmd = this->getPendingCommand();
|
||||
|
||||
switch(pendingCmd) {
|
||||
|
||||
case(TEST_NORMAL_MODE_CMD): {
|
||||
if(fullInfoPrintout) {
|
||||
#if OBSW_VERBOSE_LEVEL >= 3
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice::scanForReply: Reply for normal commnand (ID " <<
|
||||
TEST_NORMAL_MODE_CMD << ") received!" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::scanForReply: Reply for normal command (ID %d) "
|
||||
"received!\n", deviceIdx, TEST_NORMAL_MODE_CMD);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
*foundLen = len;
|
||||
*foundId = pendingCmd;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
case(TEST_COMMAND_0): {
|
||||
if(len < TEST_COMMAND_0_SIZE) {
|
||||
return DeviceHandlerIF::LENGTH_MISSMATCH;
|
||||
}
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::scanForReply: Reply for simple command "
|
||||
"(ID " << TEST_COMMAND_0 << ") received!" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::scanForReply: Reply for simple command (ID %d) "
|
||||
"received!\n", deviceIdx, TEST_COMMAND_0);
|
||||
#endif
|
||||
}
|
||||
|
||||
*foundLen = TEST_COMMAND_0_SIZE;
|
||||
*foundId = pendingCmd;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
case(TEST_COMMAND_1): {
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::scanForReply: Reply for data command "
|
||||
"(ID " << TEST_COMMAND_1 << ") received!" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::scanForReply: Reply for data command (ID %d) "
|
||||
"received\n", deviceIdx, TEST_COMMAND_1);
|
||||
#endif
|
||||
}
|
||||
|
||||
*foundLen = len;
|
||||
*foundId = pendingCmd;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
default:
|
||||
return DeviceHandlerIF::DEVICE_REPLY_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t TestDevice::interpretDeviceReply(DeviceCommandId_t id,
|
||||
const uint8_t* packet) {
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
switch(id) {
|
||||
/* Periodic replies */
|
||||
case testdevice::TEST_NORMAL_MODE_CMD: {
|
||||
result = interpretingNormalModeReply();
|
||||
break;
|
||||
}
|
||||
/* Simple reply */
|
||||
case testdevice::TEST_COMMAND_0: {
|
||||
result = interpretingTestReply0(id, packet);
|
||||
break;
|
||||
}
|
||||
/* Data reply */
|
||||
case testdevice::TEST_COMMAND_1: {
|
||||
result = interpretingTestReply1(id, packet);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return DeviceHandlerIF::DEVICE_REPLY_INVALID;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t TestDevice::interpretingNormalModeReply() {
|
||||
CommandMessage directReplyMessage;
|
||||
if(changingDatasets) {
|
||||
PoolReadGuard readHelper(&dataset);
|
||||
if(dataset.testUint8Var.value == 0) {
|
||||
dataset.testUint8Var.value = 10;
|
||||
dataset.testUint32Var.value = 777;
|
||||
dataset.testFloat3Vec.value[0] = 2.5;
|
||||
dataset.testFloat3Vec.value[1] = -2.5;
|
||||
dataset.testFloat3Vec.value[2] = 2.5;
|
||||
dataset.setValidity(true, true);
|
||||
}
|
||||
else {
|
||||
dataset.testUint8Var.value = 0;
|
||||
dataset.testUint32Var.value = 0;
|
||||
dataset.testFloat3Vec.value[0] = 0.0;
|
||||
dataset.testFloat3Vec.value[1] = 0.0;
|
||||
dataset.testFloat3Vec.value[2] = 0.0;
|
||||
dataset.setValidity(false, true);
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
PoolReadGuard readHelper(&dataset);
|
||||
if(dataset.testUint8Var.value == 0) {
|
||||
/* Reset state */
|
||||
dataset.testUint8Var.value = 128;
|
||||
}
|
||||
else if(dataset.testUint8Var.value > 200) {
|
||||
if(not resetAfterChange) {
|
||||
/* This will trigger an update notification to the controller */
|
||||
dataset.testUint8Var.setChanged(true);
|
||||
resetAfterChange = true;
|
||||
/* Decrement by 30 automatically. This will prevent any additional notifications. */
|
||||
dataset.testUint8Var.value -= 30;
|
||||
}
|
||||
}
|
||||
/* If the value is greater than 0, it will be decremented in a linear way */
|
||||
else if(dataset.testUint8Var.value > 128) {
|
||||
size_t sizeToDecrement = 0;
|
||||
if(dataset.testUint8Var.value > 128 + 30) {
|
||||
sizeToDecrement = 30;
|
||||
}
|
||||
else {
|
||||
sizeToDecrement = dataset.testUint8Var.value - 128;
|
||||
resetAfterChange = false;
|
||||
}
|
||||
dataset.testUint8Var.value -= sizeToDecrement;
|
||||
}
|
||||
else if(dataset.testUint8Var.value < 50) {
|
||||
if(not resetAfterChange) {
|
||||
/* This will trigger an update snapshot to the controller */
|
||||
dataset.testUint8Var.setChanged(true);
|
||||
resetAfterChange = true;
|
||||
}
|
||||
else {
|
||||
/* Increment by 30 automatically. */
|
||||
dataset.testUint8Var.value += 30;
|
||||
}
|
||||
}
|
||||
/* Increment in linear way */
|
||||
else if(dataset.testUint8Var.value < 128) {
|
||||
size_t sizeToIncrement = 0;
|
||||
if(dataset.testUint8Var.value < 128 - 20) {
|
||||
sizeToIncrement = 20;
|
||||
}
|
||||
else {
|
||||
sizeToIncrement = 128 - dataset.testUint8Var.value;
|
||||
resetAfterChange = false;
|
||||
}
|
||||
dataset.testUint8Var.value += sizeToIncrement;
|
||||
}
|
||||
|
||||
/* TODO: Same for vector */
|
||||
float vectorMean = (dataset.testFloat3Vec.value[0] + dataset.testFloat3Vec.value[1] +
|
||||
dataset.testFloat3Vec.value[2]) / 3.0;
|
||||
|
||||
/* Lambda (private local function) */
|
||||
auto sizeToAdd = [](bool tooHigh, float currentVal) {
|
||||
if(tooHigh) {
|
||||
if(currentVal - 20.0 > 10.0) {
|
||||
return -10.0;
|
||||
}
|
||||
else {
|
||||
return 20.0 - currentVal;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(std::abs(currentVal + 20.0) > 10.0) {
|
||||
return 10.0;
|
||||
}
|
||||
else {
|
||||
return -20.0 - currentVal;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(vectorMean > 20.0 and std::abs(vectorMean - 20.0) > 1.0) {
|
||||
if(not resetAfterChange) {
|
||||
dataset.testFloat3Vec.setChanged(true);
|
||||
resetAfterChange = true;
|
||||
}
|
||||
else {
|
||||
float sizeToDecrementVal0 = 0;
|
||||
float sizeToDecrementVal1 = 0;
|
||||
float sizeToDecrementVal2 = 0;
|
||||
|
||||
sizeToDecrementVal0 = sizeToAdd(true, dataset.testFloat3Vec.value[0]);
|
||||
sizeToDecrementVal1 = sizeToAdd(true, dataset.testFloat3Vec.value[1]);
|
||||
sizeToDecrementVal2 = sizeToAdd(true, dataset.testFloat3Vec.value[2]);
|
||||
|
||||
dataset.testFloat3Vec.value[0] += sizeToDecrementVal0;
|
||||
dataset.testFloat3Vec.value[1] += sizeToDecrementVal1;
|
||||
dataset.testFloat3Vec.value[2] += sizeToDecrementVal2;
|
||||
}
|
||||
}
|
||||
else if (vectorMean < -20.0 and std::abs(vectorMean + 20.0) < 1.0) {
|
||||
if(not resetAfterChange) {
|
||||
dataset.testFloat3Vec.setChanged(true);
|
||||
resetAfterChange = true;
|
||||
}
|
||||
else {
|
||||
float sizeToDecrementVal0 = 0;
|
||||
float sizeToDecrementVal1 = 0;
|
||||
float sizeToDecrementVal2 = 0;
|
||||
|
||||
sizeToDecrementVal0 = sizeToAdd(false, dataset.testFloat3Vec.value[0]);
|
||||
sizeToDecrementVal1 = sizeToAdd(false, dataset.testFloat3Vec.value[1]);
|
||||
sizeToDecrementVal2 = sizeToAdd(false, dataset.testFloat3Vec.value[2]);
|
||||
|
||||
dataset.testFloat3Vec.value[0] += sizeToDecrementVal0;
|
||||
dataset.testFloat3Vec.value[1] += sizeToDecrementVal1;
|
||||
dataset.testFloat3Vec.value[2] += sizeToDecrementVal2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(resetAfterChange) {
|
||||
resetAfterChange = false;
|
||||
}
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestDevice::interpretingTestReply0(DeviceCommandId_t id, const uint8_t* packet) {
|
||||
CommandMessage commandMessage;
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice::interpretingTestReply0: Generating step and finish reply" <<
|
||||
std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice::interpretingTestReply0: Generating step and finish reply\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
MessageQueueId_t commander = getCommanderId(id);
|
||||
/* Generate one step reply and the finish reply */
|
||||
actionHelper.step(1, commander, id);
|
||||
actionHelper.finish(true, commander, id);
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestDevice::interpretingTestReply1(DeviceCommandId_t id,
|
||||
const uint8_t* packet) {
|
||||
CommandMessage directReplyMessage;
|
||||
if(fullInfoPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::interpretingReply1: Setting data reply" <<
|
||||
std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::interpretingReply1: Setting data reply\n", deviceIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
MessageQueueId_t commander = getCommanderId(id);
|
||||
/* Send reply with data */
|
||||
ReturnValue_t result = actionHelper.reportData(commander, id, packet,
|
||||
testdevice::TEST_COMMAND_1_SIZE, false);
|
||||
|
||||
if (result != RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "TestDevice" << deviceIdx << "::interpretingReply1: Sending data "
|
||||
"reply failed!" << std::endl;
|
||||
#else
|
||||
sif::printError("TestDevice%d::interpretingReply1: Sending data reply failed!\n",
|
||||
deviceIdx);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
if(result == HasReturnvaluesIF::RETURN_OK) {
|
||||
/* Finish reply */
|
||||
actionHelper.finish(true, commander, id);
|
||||
}
|
||||
else {
|
||||
/* Finish reply */
|
||||
actionHelper.finish(false, commander, id, result);
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
uint32_t TestDevice::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) {
|
||||
return 5000;
|
||||
}
|
||||
|
||||
void TestDevice::enableFullDebugOutput(bool enable) {
|
||||
this->fullInfoPrintout = enable;
|
||||
}
|
||||
|
||||
ReturnValue_t TestDevice::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
|
||||
LocalDataPoolManager &poolManager) {
|
||||
namespace td = testdevice;
|
||||
localDataPoolMap.emplace(td::PoolIds::TEST_UINT8_ID, new PoolEntry<uint8_t>({0}));
|
||||
localDataPoolMap.emplace(td::PoolIds::TEST_UINT32_ID, new PoolEntry<uint32_t>({0}));
|
||||
localDataPoolMap.emplace(td::PoolIds::TEST_FLOAT_VEC_3_ID,
|
||||
new PoolEntry<float>({0.0, 0.0, 0.0}));
|
||||
|
||||
sid_t sid;
|
||||
if(deviceIdx == td::DeviceIndex::DEVICE_0) {
|
||||
sid = td::TEST_SET_DEV_0_SID;
|
||||
}
|
||||
else {
|
||||
sid = td::TEST_SET_DEV_1_SID;
|
||||
}
|
||||
/* Subscribe for periodic HK packets but do not enable reporting for now.
|
||||
Non-diangostic with a period of one second */
|
||||
poolManager.subscribeForPeriodicPacket(sid, false, 1.0, false);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues,
|
||||
uint16_t startAtIndex) {
|
||||
using namespace testdevice;
|
||||
switch (uniqueId) {
|
||||
case ParameterUniqueIds::TEST_UINT32_0: {
|
||||
if(fullInfoPrintout) {
|
||||
uint32_t newValue = 0;
|
||||
ReturnValue_t result = newValues->getElement<uint32_t>(&newValue, 0, 0);
|
||||
if(result == HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::getParameter: Setting parameter 0 to "
|
||||
"new value " << newValue << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::getParameter: Setting parameter 0 to new value %lu\n",
|
||||
deviceIdx, static_cast<unsigned long>(newValue));
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
}
|
||||
}
|
||||
parameterWrapper->set(testParameter0);
|
||||
break;
|
||||
}
|
||||
case ParameterUniqueIds::TEST_INT32_1: {
|
||||
if(fullInfoPrintout) {
|
||||
int32_t newValue = 0;
|
||||
ReturnValue_t result = newValues->getElement<int32_t>(&newValue, 0, 0);
|
||||
if(result == HasReturnvaluesIF::RETURN_OK) {
|
||||
#if OBSW_DEVICE_HANDLER_PRINTOUT == 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::getParameter: Setting parameter 1 to "
|
||||
"new value " << newValue << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::getParameter: Setting parameter 1 to new value %lu\n",
|
||||
deviceIdx, static_cast<unsigned long>(newValue));
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif /* OBSW_DEVICE_HANDLER_PRINTOUT == 1 */
|
||||
}
|
||||
}
|
||||
parameterWrapper->set(testParameter1);
|
||||
break;
|
||||
}
|
||||
case ParameterUniqueIds::TEST_FLOAT_VEC3_2: {
|
||||
if(fullInfoPrintout) {
|
||||
float newVector[3];
|
||||
if(newValues->getElement<float>(newVector, 0, 0) != RETURN_OK or
|
||||
newValues->getElement<float>(newVector + 1, 0, 1) != RETURN_OK or
|
||||
newValues->getElement<float>(newVector + 2, 0, 2) != RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
#if OBSW_DEVICE_HANDLER_PRINTOUT == 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::getParameter: Setting parameter 3 to "
|
||||
"(float vector with 3 entries) to new values [" << newVector[0] << ", " <<
|
||||
newVector[1] << ", " << newVector[2] << "]" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::getParameter: Setting parameter 3 to new values "
|
||||
"[%f, %f, %f]\n", deviceIdx, newVector[0], newVector[1], newVector[2]);
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif /* OBSW_DEVICE_HANDLER_PRINTOUT == 1 */
|
||||
}
|
||||
parameterWrapper->setVector(vectorFloatParams2);
|
||||
break;
|
||||
}
|
||||
case(ParameterUniqueIds::PERIODIC_PRINT_ENABLED): {
|
||||
if(fullInfoPrintout) {
|
||||
uint8_t enabled = 0;
|
||||
ReturnValue_t result = newValues->getElement<uint8_t>(&enabled, 0, 0);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
char const* printout = nullptr;
|
||||
if (enabled) {
|
||||
printout = "enabled";
|
||||
}
|
||||
else {
|
||||
printout = "disabled";
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::getParameter: Periodic printout " <<
|
||||
printout << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::getParameter: Periodic printout %s", printout);
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
}
|
||||
|
||||
parameterWrapper->set(periodicPrintout);
|
||||
break;
|
||||
}
|
||||
case(ParameterUniqueIds::CHANGING_DATASETS): {
|
||||
|
||||
uint8_t enabled = 0;
|
||||
ReturnValue_t result = newValues->getElement<uint8_t>(&enabled, 0, 0);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if(not enabled) {
|
||||
PoolReadGuard readHelper(&dataset);
|
||||
dataset.testUint8Var.value = 0;
|
||||
dataset.testUint32Var.value = 0;
|
||||
dataset.testFloat3Vec.value[0] = 0.0;
|
||||
dataset.testFloat3Vec.value[0] = 0.0;
|
||||
dataset.testFloat3Vec.value[1] = 0.0;
|
||||
}
|
||||
|
||||
if(fullInfoPrintout) {
|
||||
char const* printout = nullptr;
|
||||
if (enabled) {
|
||||
printout = "enabled";
|
||||
}
|
||||
else {
|
||||
printout = "disabled";
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::getParameter: Changing datasets " <<
|
||||
printout << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::getParameter: Changing datasets %s", printout);
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
}
|
||||
|
||||
parameterWrapper->set(changingDatasets);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
LocalPoolObjectBase* TestDevice::getPoolObjectHandle(lp_id_t localPoolId) {
|
||||
namespace td = testdevice;
|
||||
if (localPoolId == td::PoolIds::TEST_UINT8_ID) {
|
||||
return &dataset.testUint8Var;
|
||||
}
|
||||
else if (localPoolId == td::PoolIds::TEST_UINT32_ID) {
|
||||
return &dataset.testUint32Var;
|
||||
}
|
||||
else if(localPoolId == td::PoolIds::TEST_FLOAT_VEC_3_ID) {
|
||||
return &dataset.testFloat3Vec;
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
#ifndef TEST_TESTDEVICES_TESTDEVICEHANDLER_H_
|
||||
#define TEST_TESTDEVICES_TESTDEVICEHANDLER_H_
|
||||
|
||||
#include "devicedefinitions/testDeviceDefinitions.h"
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
|
||||
#include <fsfw/globalfunctions/PeriodicOperationDivider.h>
|
||||
#include <fsfw/timemanager/Countdown.h>
|
||||
|
||||
/**
|
||||
* @brief Basic dummy device handler to test device commanding without a physical device.
|
||||
* @details
|
||||
* This test device handler provided a basic demo for the device handler object.
|
||||
* It can also be commanded with the following PUS services, using
|
||||
* the specified object ID of the test device handler.
|
||||
*
|
||||
* 1. PUS Service 8 - Functional commanding
|
||||
* 2. PUS Service 2 - Device access, raw commanding
|
||||
* 3. PUS Service 20 - Parameter Management
|
||||
* 4. PUS Service 3 - Housekeeping
|
||||
|
||||
* @author R. Mueller
|
||||
* @ingroup devices
|
||||
*/
|
||||
class TestDevice: public DeviceHandlerBase {
|
||||
public:
|
||||
/**
|
||||
* Build the test device in the factory.
|
||||
* @param objectId This ID will be assigned to the test device handler.
|
||||
* @param comIF The ID of the Communication IF used by test device handler.
|
||||
* @param cookie Cookie object used by the test device handler. This is
|
||||
* also used and passed to the comIF object.
|
||||
* @param onImmediately This will start a transition to MODE_ON immediately
|
||||
* so the device handler jumps into #doStartUp. Should only be used
|
||||
* in development to reduce need of commanding while debugging.
|
||||
* @param changingDataset
|
||||
* Will be used later to change the local datasets containeds in the device.
|
||||
*/
|
||||
TestDevice(object_id_t objectId, object_id_t comIF, CookieIF * cookie,
|
||||
testdevice::DeviceIndex deviceIdx = testdevice::DeviceIndex::DEVICE_0,
|
||||
bool fullInfoPrintout = false, bool changingDataset = true);
|
||||
|
||||
/**
|
||||
* This can be used to enable and disable a lot of demo print output.
|
||||
* @param enable
|
||||
*/
|
||||
void enableFullDebugOutput(bool enable);
|
||||
|
||||
virtual ~ TestDevice();
|
||||
|
||||
//! Size of internal buffer used for communication.
|
||||
static constexpr uint8_t MAX_BUFFER_SIZE = 255;
|
||||
|
||||
//! Unique index if the device handler is created multiple times.
|
||||
testdevice::DeviceIndex deviceIdx = testdevice::DeviceIndex::DEVICE_0;
|
||||
|
||||
protected:
|
||||
testdevice::TestDataSet dataset;
|
||||
//! This is used to reset the dataset after a commanded change has been made.
|
||||
bool resetAfterChange = false;
|
||||
bool commandSent = false;
|
||||
|
||||
/** DeviceHandlerBase overrides (see DHB documentation) */
|
||||
|
||||
/**
|
||||
* Hook into the DHB #performOperation call which is executed
|
||||
* periodically.
|
||||
*/
|
||||
void performOperationHook() override;
|
||||
|
||||
virtual void doStartUp() override;
|
||||
virtual void doShutDown() override;
|
||||
|
||||
virtual ReturnValue_t buildNormalDeviceCommand(
|
||||
DeviceCommandId_t * id) override;
|
||||
virtual ReturnValue_t buildTransitionDeviceCommand(
|
||||
DeviceCommandId_t * id) override;
|
||||
virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t
|
||||
deviceCommand, const uint8_t * commandData,
|
||||
size_t commandDataLen) override;
|
||||
|
||||
virtual void fillCommandAndReplyMap() override;
|
||||
|
||||
virtual ReturnValue_t scanForReply(const uint8_t *start, size_t len,
|
||||
DeviceCommandId_t *foundId, size_t *foundLen) override;
|
||||
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id,
|
||||
const uint8_t *packet) override;
|
||||
virtual uint32_t getTransitionDelayMs(Mode_t modeFrom,
|
||||
Mode_t modeTo) override;
|
||||
|
||||
virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override;
|
||||
|
||||
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) override;
|
||||
virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) override;
|
||||
|
||||
/* HasParametersIF overrides */
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
const ParameterWrapper *newValues, uint16_t startAtIndex) override;
|
||||
|
||||
uint8_t commandBuffer[MAX_BUFFER_SIZE];
|
||||
|
||||
bool fullInfoPrintout = false;
|
||||
bool oneShot = true;
|
||||
|
||||
/* Variables for parameter service */
|
||||
uint32_t testParameter0 = 0;
|
||||
int32_t testParameter1 = -2;
|
||||
float vectorFloatParams2[3] = {};
|
||||
|
||||
/* Change device handler functionality, changeable via parameter service */
|
||||
uint8_t periodicPrintout = false;
|
||||
uint8_t changingDatasets = false;
|
||||
|
||||
ReturnValue_t buildNormalModeCommand(DeviceCommandId_t deviceCommand,
|
||||
const uint8_t* commandData, size_t commandDataLen);
|
||||
ReturnValue_t buildTestCommand0(DeviceCommandId_t deviceCommand, const uint8_t* commandData,
|
||||
size_t commandDataLen);
|
||||
ReturnValue_t buildTestCommand1(DeviceCommandId_t deviceCommand, const uint8_t* commandData,
|
||||
size_t commandDataLen);
|
||||
void passOnCommand(DeviceCommandId_t command, const uint8_t* commandData,
|
||||
size_t commandDataLen);
|
||||
|
||||
ReturnValue_t interpretingNormalModeReply();
|
||||
ReturnValue_t interpretingTestReply0(DeviceCommandId_t id,
|
||||
const uint8_t* packet);
|
||||
ReturnValue_t interpretingTestReply1(DeviceCommandId_t id,
|
||||
const uint8_t* packet);
|
||||
ReturnValue_t interpretingTestReply2(DeviceCommandId_t id, const uint8_t* packet);
|
||||
|
||||
/* Some timer utilities */
|
||||
static constexpr uint8_t divider1 = 2;
|
||||
PeriodicOperationDivider opDivider1 = PeriodicOperationDivider(divider1);
|
||||
static constexpr uint8_t divider2 = 10;
|
||||
PeriodicOperationDivider opDivider2 = PeriodicOperationDivider(divider2);
|
||||
static constexpr uint32_t initTimeout = 2000;
|
||||
Countdown countdown1 = Countdown(initTimeout);
|
||||
};
|
||||
|
||||
|
||||
#endif /* TEST_TESTDEVICES_TESTDEVICEHANDLER_H_ */
|
@ -1,86 +0,0 @@
|
||||
#include "TestEchoComIF.h"
|
||||
#include "TestCookie.h"
|
||||
|
||||
#include <fsfw/serialize/SerializeAdapter.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
#include <fsfw/tmtcservices/CommandingServiceBase.h>
|
||||
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
|
||||
|
||||
|
||||
TestEchoComIF::TestEchoComIF(object_id_t objectId):
|
||||
SystemObject(objectId) {
|
||||
}
|
||||
|
||||
TestEchoComIF::~TestEchoComIF() {}
|
||||
|
||||
ReturnValue_t TestEchoComIF::initializeInterface(CookieIF * cookie) {
|
||||
DummyCookie* dummyCookie = dynamic_cast<DummyCookie*>(cookie);
|
||||
if(dummyCookie == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TestEchoComIF::initializeInterface: Invalid cookie!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("TestEchoComIF::initializeInterface: Invalid cookie!\n");
|
||||
#endif
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
auto resultPair = replyMap.emplace(
|
||||
dummyCookie->getAddress(), ReplyBuffer(dummyCookie->getReplyMaxLen()));
|
||||
if(not resultPair.second) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestEchoComIF::sendMessage(CookieIF *cookie,
|
||||
const uint8_t * sendData, size_t sendLen) {
|
||||
DummyCookie* dummyCookie = dynamic_cast<DummyCookie*>(cookie);
|
||||
if(dummyCookie == nullptr) {
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
ReplyBuffer& replyBuffer = replyMap.find(dummyCookie->getAddress())->second;
|
||||
if(sendLen > replyBuffer.capacity()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TestEchoComIF::sendMessage: Send length " << sendLen << " larger than "
|
||||
"current reply buffer length!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("TestEchoComIF::sendMessage: Send length %d larger than current "
|
||||
"reply buffer length!\n", sendLen);
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
replyBuffer.resize(sendLen);
|
||||
memcpy(replyBuffer.data(), sendData, sendLen);
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestEchoComIF::getSendSuccess(CookieIF *cookie) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestEchoComIF::requestReceiveMessage(CookieIF *cookie,
|
||||
size_t requestLen) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestEchoComIF::readReceivedMessage(CookieIF *cookie,
|
||||
uint8_t **buffer, size_t *size) {
|
||||
DummyCookie* dummyCookie = dynamic_cast<DummyCookie*>(cookie);
|
||||
if(dummyCookie == nullptr) {
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
ReplyBuffer& replyBuffer = replyMap.find(dummyCookie->getAddress())->second;
|
||||
*buffer = replyBuffer.data();
|
||||
*size = replyBuffer.size();
|
||||
|
||||
dummyReplyCounter ++;
|
||||
if(dummyReplyCounter == 10) {
|
||||
// add anything that needs to be read periodically by dummy handler
|
||||
dummyReplyCounter = 0;
|
||||
}
|
||||
return RETURN_OK;
|
||||
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
#ifndef TEST_TESTDEVICES_TESTECHOCOMIF_H_
|
||||
#define TEST_TESTDEVICES_TESTECHOCOMIF_H_
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/ipc/MessageQueueIF.h>
|
||||
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief Used to simply returned sent data from device handler
|
||||
* @details Assign this com IF in the factory when creating the device handler
|
||||
* @ingroup test
|
||||
*/
|
||||
class TestEchoComIF: public DeviceCommunicationIF, public SystemObject {
|
||||
public:
|
||||
TestEchoComIF(object_id_t objectId);
|
||||
virtual ~TestEchoComIF();
|
||||
|
||||
/**
|
||||
* DeviceCommunicationIF overrides
|
||||
* (see DeviceCommunicationIF documentation
|
||||
*/
|
||||
ReturnValue_t initializeInterface(CookieIF * cookie) override;
|
||||
ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData,
|
||||
size_t sendLen) override;
|
||||
ReturnValue_t getSendSuccess(CookieIF *cookie) override;
|
||||
ReturnValue_t requestReceiveMessage(CookieIF *cookie,
|
||||
size_t requestLen) override;
|
||||
ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
|
||||
size_t *size) override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Send TM packet which contains received data as TM[17,130].
|
||||
* Wiretapping will do the same.
|
||||
* @param data
|
||||
* @param len
|
||||
*/
|
||||
void sendTmPacket(const uint8_t *data,uint32_t len);
|
||||
|
||||
AcceptsTelemetryIF* funnel = nullptr;
|
||||
MessageQueueIF* tmQueue = nullptr;
|
||||
size_t replyMaxLen = 0;
|
||||
|
||||
using ReplyBuffer = std::vector<uint8_t>;
|
||||
std::map<address_t, ReplyBuffer> replyMap;
|
||||
|
||||
uint8_t dummyReplyCounter = 0;
|
||||
|
||||
uint16_t packetSubCounter = 0;
|
||||
};
|
||||
|
||||
#endif /* TEST_TESTDEVICES_TESTECHOCOMIF_H_ */
|
@ -1,100 +0,0 @@
|
||||
#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_TESTDEVICEDEFINITIONS_H_
|
||||
#define MISSION_DEVICES_DEVICEDEFINITIONS_TESTDEVICEDEFINITIONS_H_
|
||||
|
||||
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
|
||||
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||
#include <commonSystemObjects.h>
|
||||
|
||||
namespace testdevice {
|
||||
|
||||
enum ParameterUniqueIds: uint8_t {
|
||||
TEST_UINT32_0,
|
||||
TEST_INT32_1,
|
||||
TEST_FLOAT_VEC3_2,
|
||||
PERIODIC_PRINT_ENABLED,
|
||||
CHANGING_DATASETS
|
||||
};
|
||||
|
||||
enum DeviceIndex: uint32_t {
|
||||
DEVICE_0,
|
||||
DEVICE_1
|
||||
};
|
||||
|
||||
/** Normal mode command. This ID is also used to access the set variable via the housekeeping
|
||||
service */
|
||||
static constexpr DeviceCommandId_t TEST_NORMAL_MODE_CMD = 0;
|
||||
|
||||
//! Test completion reply
|
||||
static constexpr DeviceCommandId_t TEST_COMMAND_0 = 1;
|
||||
//! Test data reply
|
||||
static constexpr DeviceCommandId_t TEST_COMMAND_1 = 2;
|
||||
|
||||
/**
|
||||
* Can be used to trigger a notification to the demo controller. For DEVICE_0, only notifications
|
||||
* messages will be generated while for DEVICE_1, snapshot messages will be generated.
|
||||
*
|
||||
* DEVICE_0 VAR: Sets the set variable 0 above a treshold (200) to trigger a variable
|
||||
* notification.
|
||||
* DEVICE_0 SET: Sets the vector mean values above a treshold (mean larger than 20) to trigger a
|
||||
* set notification.
|
||||
*
|
||||
* DEVICE_1 VAR: Sets the set variable 0 below a treshold (less than 50 but not 0) to trigger a
|
||||
* variable snapshot.
|
||||
* DEVICE_1 SET: Sets the set vector mean values below a treshold (mean smaller than -20) to
|
||||
* trigger a set snapshot message.
|
||||
*/
|
||||
static constexpr DeviceCommandId_t TEST_NOTIF_SNAPSHOT_VAR = 3;
|
||||
static constexpr DeviceCommandId_t TEST_NOTIF_SNAPSHOT_SET = 4;
|
||||
|
||||
/**
|
||||
* Can be used to trigger a snapshot message to the demo controller.
|
||||
* Depending on the device index, a notification will be triggered for different set variables.
|
||||
*
|
||||
* DEVICE_0: Sets the set variable 0 below a treshold (below 50 but not 0) to trigger
|
||||
* a variable snapshot
|
||||
* DEVICE_1: Sets the vector mean values below a treshold (mean less than -20) to trigger a
|
||||
* set snapshot
|
||||
*/
|
||||
static constexpr DeviceCommandId_t TEST_SNAPSHOT = 5;
|
||||
|
||||
//! Generates a random value for variable 1 of the dataset.
|
||||
static constexpr DeviceCommandId_t GENERATE_SET_VAR_1_RNG_VALUE = 6;
|
||||
|
||||
|
||||
/**
|
||||
* These parameters are sent back with the command ID as a data reply
|
||||
*/
|
||||
static constexpr uint16_t COMMAND_1_PARAM1 = 0xBAB0; //!< param1, 2 bytes
|
||||
//! param2, 8 bytes
|
||||
static constexpr uint64_t COMMAND_1_PARAM2 = 0x000000524F42494E;
|
||||
|
||||
static constexpr size_t TEST_COMMAND_0_SIZE = sizeof(TEST_COMMAND_0);
|
||||
static constexpr size_t TEST_COMMAND_1_SIZE = sizeof(TEST_COMMAND_1) + sizeof(COMMAND_1_PARAM1) +
|
||||
sizeof(COMMAND_1_PARAM2);
|
||||
|
||||
enum PoolIds: lp_id_t {
|
||||
TEST_UINT8_ID = 0,
|
||||
TEST_UINT32_ID = 1,
|
||||
TEST_FLOAT_VEC_3_ID = 2
|
||||
};
|
||||
|
||||
static constexpr uint8_t TEST_SET_ID = TEST_NORMAL_MODE_CMD;
|
||||
static const sid_t TEST_SET_DEV_0_SID = sid_t(objects::TEST_DEVICE_HANDLER_0, TEST_SET_ID);
|
||||
static const sid_t TEST_SET_DEV_1_SID = sid_t(objects::TEST_DEVICE_HANDLER_1, TEST_SET_ID);
|
||||
|
||||
class TestDataSet: public StaticLocalDataSet<3> {
|
||||
public:
|
||||
TestDataSet(HasLocalDataPoolIF* owner): StaticLocalDataSet(owner, TEST_SET_ID) {}
|
||||
TestDataSet(object_id_t owner): StaticLocalDataSet(sid_t(owner, TEST_SET_ID)) {}
|
||||
|
||||
lp_var_t<uint8_t> testUint8Var = lp_var_t<uint8_t>(
|
||||
gp_id_t(this->getCreatorObjectId(), PoolIds::TEST_UINT8_ID), this);
|
||||
lp_var_t<uint32_t> testUint32Var = lp_var_t<uint32_t>(
|
||||
gp_id_t(this->getCreatorObjectId(), PoolIds::TEST_UINT32_ID), this);
|
||||
lp_vec_t<float ,3> testFloat3Vec = lp_vec_t<float, 3>(
|
||||
gp_id_t(this->getCreatorObjectId(), PoolIds::TEST_FLOAT_VEC_3_ID), this);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_TESTDEVICEDEFINITIONS_H_ */
|
@ -1,17 +0,0 @@
|
||||
# add main and others
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/*.c)
|
||||
|
||||
CSRC += $(wildcard $(CURRENTPATH)/core/*.c)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/core/*.cpp)
|
||||
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/devices/*.cpp)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/devices/*.c)
|
||||
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/utility/*.cpp)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/utility/*.c)
|
||||
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/test/*.cpp)
|
||||
CSRC += $(wildcard $(CURRENTPATH)/test/*.c)
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
target_sources(${TARGET_NAME}
|
||||
PRIVATE
|
||||
PusPacketCreator.cpp
|
||||
TmFunnel.cpp
|
||||
)
|
@ -1,19 +0,0 @@
|
||||
#include <fsfw/tmtcpacket/pus/TcPacketBase.h>
|
||||
#include <fsfw/tmtcpacket/pus/TmPacketBase.h>
|
||||
#include <fsfw/globalfunctions/arrayprinter.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
#include <mission/utility/PusPacketCreator.h>
|
||||
|
||||
void PusPacketCreator::createPusPacketAndPrint() {
|
||||
// TODO: use TC packet stored here instead..
|
||||
|
||||
// uint8_t packetStore[TcPacketBase::TC_PACKET_MIN_SIZE];
|
||||
// TcPacketBase packet(packetStore);
|
||||
// packet.initSpacePacketHeader(true, true, 0x73, 25);
|
||||
// packet.initializeTcPacket(0x73, 25, 0, 17, 1);
|
||||
// packet.setPacketDataLength(sizeof(PUSTcDataFieldHeader)
|
||||
// + TcPacketBase::CRC_SIZE-1);
|
||||
// packet.setErrorControl();
|
||||
// sif::info << "PUS packet created: " << std::endl;
|
||||
// arrayprinter::print(packet.getWholeData(), packet.getFullSize());
|
||||
}
|
9
stm32h7/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
STM32TestTask.cpp
|
||||
)
|
||||
|
||||
option(STM32_ADD_NETWORKING_CODE "Add networking code requiring lwIP" ON)
|
||||
|
||||
if(STM32_ADD_NETWORKING_CODE)
|
||||
add_subdirectory(networking)
|
||||
endif()
|
22
stm32h7/STM32TestTask.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "STM32TestTask.h"
|
||||
#include "stm32h7xx_nucleo.h"
|
||||
#include "OBSWConfig.h"
|
||||
|
||||
STM32TestTask::STM32TestTask(object_id_t objectId, bool enablePrintout,
|
||||
bool blinkyLed): TestTask(objectId, enablePrintout),
|
||||
blinkyLed(blinkyLed) {
|
||||
BSP_LED_Init(LED1);
|
||||
BSP_LED_Init(LED2);
|
||||
BSP_LED_Init(LED3);
|
||||
}
|
||||
|
||||
ReturnValue_t STM32TestTask::performPeriodicAction() {
|
||||
if(blinkyLed) {
|
||||
#if OBSW_ETHERNET_USE_LEDS == 0
|
||||
BSP_LED_Toggle(LED1);
|
||||
BSP_LED_Toggle(LED2);
|
||||
#endif
|
||||
BSP_LED_Toggle(LED3);
|
||||
}
|
||||
return TestTask::performPeriodicAction();
|
||||
}
|
19
stm32h7/STM32TestTask.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef BSP_STM32_BOARDTEST_STM32TESTTASK_H_
|
||||
#define BSP_STM32_BOARDTEST_STM32TESTTASK_H_
|
||||
|
||||
#include "../test/TestTask.h"
|
||||
|
||||
class STM32TestTask: public TestTask {
|
||||
public:
|
||||
STM32TestTask(object_id_t objectId, bool enablePrintout, bool blinkyLed = true);
|
||||
|
||||
ReturnValue_t performPeriodicAction() override;
|
||||
private:
|
||||
|
||||
bool blinkyLed = false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* BSP_STM32_BOARDTEST_STM32TESTTASK_H_ */
|
14
stm32h7/networking/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# These are part of the RTEMS BSP for RTEMS
|
||||
if(FSFW_OSAL MATCHES freertos)
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
ethernetif.c
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
UdpTcLwIpPollingTask.cpp
|
||||
TmTcLwIpUdpBridge.cpp
|
||||
networking.cpp
|
||||
app_dhcp.cpp
|
||||
app_ethernet.cpp
|
||||
)
|
204
stm32h7/networking/TmTcLwIpUdpBridge.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
#include "TmTcLwIpUdpBridge.h"
|
||||
#include "udp_config.h"
|
||||
#include "app_ethernet.h"
|
||||
#include "ethernetif.h"
|
||||
#include <OBSWConfig.h>
|
||||
|
||||
#include <fsfw/ipc/MutexGuard.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
#include <fsfw/serialize/EndianConverter.h>
|
||||
|
||||
|
||||
TmTcLwIpUdpBridge::TmTcLwIpUdpBridge(object_id_t objectId,
|
||||
object_id_t ccsdsPacketDistributor, object_id_t tmStoreId,
|
||||
object_id_t tcStoreId):
|
||||
TmTcBridge(objectId, ccsdsPacketDistributor, tmStoreId, tcStoreId) {
|
||||
TmTcLwIpUdpBridge::lastAdd.addr = IPADDR_TYPE_ANY;
|
||||
}
|
||||
|
||||
TmTcLwIpUdpBridge::~TmTcLwIpUdpBridge() {}
|
||||
|
||||
ReturnValue_t TmTcLwIpUdpBridge::initialize() {
|
||||
TmTcBridge::initialize();
|
||||
bridgeLock = MutexFactory::instance()->createMutex();
|
||||
if(bridgeLock == nullptr) {
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
ReturnValue_t result = udp_server_init();
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t TmTcLwIpUdpBridge::udp_server_init(void) {
|
||||
err_t err;
|
||||
/* Create a new UDP control block */
|
||||
TmTcLwIpUdpBridge::upcb = udp_new();
|
||||
if (TmTcLwIpUdpBridge::upcb)
|
||||
{
|
||||
/* Bind the upcb to the UDP_PORT port */
|
||||
/* Using IP_ADDR_ANY allow the upcb to be used by any local interface */
|
||||
err = udp_bind(TmTcLwIpUdpBridge::upcb, IP_ADDR_ANY, UDP_SERVER_PORT);
|
||||
|
||||
if(err == ERR_OK)
|
||||
{
|
||||
/* Set a receive callback for the upcb */
|
||||
udp_recv(TmTcLwIpUdpBridge::upcb, &udp_server_receive_callback,
|
||||
(void*) this);
|
||||
return RETURN_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
udp_remove(TmTcLwIpUdpBridge::upcb);
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
} else {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t TmTcLwIpUdpBridge::performOperation(uint8_t operationCode) {
|
||||
TmTcBridge::performOperation();
|
||||
|
||||
#if TCPIP_RECV_WIRETAPPING == 1
|
||||
if(connectFlag) {
|
||||
uint32_t ipAddress = ((ip4_addr*) &lastAdd)->addr;
|
||||
int ipAddress1 = (ipAddress & 0xFF000000) >> 24;
|
||||
int ipAddress2 = (ipAddress & 0xFF0000) >> 16;
|
||||
int ipAddress3 = (ipAddress & 0xFF00) >> 8;
|
||||
int ipAddress4 = ipAddress & 0xFF;
|
||||
#if OBSW_VERBOSE_LEVEL == 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TmTcLwIpUdpBridge: Client IP Address " << std::dec
|
||||
<< ipAddress4 << "." << ipAddress3 << "." << ipAddress2 << "."
|
||||
<< ipAddress1 << std::endl;
|
||||
uint16_t portSwapped = EndianConverter::convertBigEndian(lastPort);
|
||||
sif::info << "TmTcLwIpUdpBridge: Client IP Port "
|
||||
<< (int)portSwapped << std::endl;
|
||||
#else
|
||||
sif::printInfo("TmTcLwIpUdpBridge: Client IP Address %d.%d.%d.%d\n",
|
||||
ipAddress4, ipAddress3, ipAddress2, ipAddress1);
|
||||
uint16_t portSwapped = EndianConverter::convertBigEndian(lastPort);
|
||||
sif::printInfo("TmTcLwIpUdpBridge: Client IP Port: %d\n", portSwapped);
|
||||
#endif
|
||||
#endif
|
||||
connectFlag = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TmTcLwIpUdpBridge::sendTm(const uint8_t * data, size_t dataLen) {
|
||||
struct pbuf *p_tx = pbuf_alloc(PBUF_TRANSPORT, dataLen, PBUF_RAM);
|
||||
if ((p_tx != nullptr) && (lastAdd.addr != IPADDR_TYPE_ANY) && (upcb != nullptr)) {
|
||||
/* copy data to pbuf */
|
||||
err_t err = pbuf_take(p_tx, (char*) data, dataLen);
|
||||
if(err!=ERR_OK){
|
||||
pbuf_free(p_tx);
|
||||
return err;
|
||||
}
|
||||
/* Connect to the remote client */
|
||||
err = udp_connect(TmTcLwIpUdpBridge::upcb, &lastAdd , lastPort);
|
||||
if(err != ERR_OK){
|
||||
pbuf_free(p_tx);
|
||||
return err;
|
||||
}
|
||||
/* Tell the client that we have accepted it */
|
||||
err = udp_send(TmTcLwIpUdpBridge::upcb, p_tx);
|
||||
pbuf_free(p_tx);
|
||||
if(err!=ERR_OK){
|
||||
return err;
|
||||
}
|
||||
|
||||
/* free the UDP connection, so we can accept new clients */
|
||||
udp_disconnect (TmTcLwIpUdpBridge::upcb);
|
||||
}
|
||||
else{
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
void TmTcLwIpUdpBridge::udp_server_receive_callback(void* arg,
|
||||
struct udp_pcb* upcb_, struct pbuf* p, const ip_addr_t* addr,
|
||||
u16_t port) {
|
||||
struct pbuf *p_tx = nullptr;
|
||||
auto udpBridge = reinterpret_cast<TmTcLwIpUdpBridge*>(arg);
|
||||
if(udpBridge == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TmTcLwIpUdpBridge::udp_server_receive_callback: Invalid UDP bridge!" <<
|
||||
std::endl;
|
||||
#else
|
||||
sif::printWarning("TmTcLwIpUdpBridge::udp_server_receive_callback: Invalid UDP bridge!\n");
|
||||
#endif
|
||||
}
|
||||
/* allocate pbuf from RAM*/
|
||||
p_tx = pbuf_alloc(PBUF_TRANSPORT,p->len, PBUF_RAM);
|
||||
|
||||
if(p_tx != NULL)
|
||||
{
|
||||
if(udpBridge != nullptr) {
|
||||
MutexGuard lg(udpBridge->bridgeLock);
|
||||
udpBridge->upcb = upcb_;
|
||||
udpBridge->lastAdd = *addr;
|
||||
udpBridge->lastPort = port;
|
||||
if(not udpBridge->comLinkUp()) {
|
||||
udpBridge->registerCommConnect();
|
||||
#if TCPIP_RECV_WIRETAPPING == 1
|
||||
udpBridge->connectFlag = true;
|
||||
#endif
|
||||
/* This should have already been done, but we will still do it */
|
||||
udpBridge->physicalConnectStatusChange(true);
|
||||
}
|
||||
}
|
||||
pbuf_take(p_tx, (char*)p->payload, p->len);
|
||||
/* send the received data to the uart port */
|
||||
char* data = reinterpret_cast<char*>(p_tx->payload);
|
||||
*(data+p_tx->len) = '\0';
|
||||
|
||||
#if TCPIP_RECV_WIRETAPPING == 1
|
||||
udpBridge->printData(p,data);
|
||||
#endif
|
||||
|
||||
store_address_t storeId;
|
||||
ReturnValue_t returnValue = udpBridge->tcStore->addData(&storeId,
|
||||
reinterpret_cast<uint8_t*>(p->payload), p->len);
|
||||
if (returnValue != RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UDP Server: Data storage failed" << std::endl;
|
||||
#endif
|
||||
pbuf_free(p_tx);
|
||||
return;
|
||||
}
|
||||
TmTcMessage message(storeId);
|
||||
if (udpBridge->tmTcReceptionQueue->sendToDefault(&message)
|
||||
!= RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TmTcLwIpUdpBridgw::udp_server_receive_callback:"
|
||||
<< " Sending message to queue failed" << std::endl;
|
||||
#endif
|
||||
udpBridge->tcStore->deleteData(storeId);
|
||||
}
|
||||
}
|
||||
/* Free the p_tx buffer */
|
||||
pbuf_free(p_tx);
|
||||
}
|
||||
|
||||
/* Caller must ensure thread-safety */
|
||||
bool TmTcLwIpUdpBridge::comLinkUp() const {
|
||||
return communicationLinkUp;
|
||||
}
|
||||
|
||||
/* Caller must ensure thread-safety */
|
||||
void TmTcLwIpUdpBridge::physicalConnectStatusChange(bool connect) {
|
||||
if(connect) {
|
||||
/* Physical connection does not mean there is a recipient to send packets too.
|
||||
This will be done by the receive callback! */
|
||||
physicalConnection = true;
|
||||
}
|
||||
else {
|
||||
physicalConnection = false;
|
||||
/* If there is no physical connection, we can't send anything back */
|
||||
registerCommDisconnect();
|
||||
}
|
||||
}
|
79
stm32h7/networking/TmTcLwIpUdpBridge.h
Normal file
@ -0,0 +1,79 @@
|
||||
#ifndef BSP_STM32_RTEMS_NETWORKING_TMTCUDPBRIDGE_H_
|
||||
#define BSP_STM32_RTEMS_NETWORKING_TMTCUDPBRIDGE_H_
|
||||
|
||||
#include <fsfw/tmtcservices/TmTcBridge.h>
|
||||
|
||||
#include <lwip/udp.h>
|
||||
#include <lwip/ip_addr.h>
|
||||
|
||||
#define TCPIP_RECV_WIRETAPPING 0
|
||||
|
||||
/**
|
||||
* This bridge is used to forward TMTC packets received via LwIP UDP to the internal software bus.
|
||||
*/
|
||||
class TmTcLwIpUdpBridge : public TmTcBridge {
|
||||
friend class UdpTcLwIpPollingTask;
|
||||
public:
|
||||
TmTcLwIpUdpBridge(object_id_t objectId,
|
||||
object_id_t ccsdsPacketDistributor, object_id_t tmStoreId,
|
||||
object_id_t tcStoreId);
|
||||
virtual ~TmTcLwIpUdpBridge();
|
||||
|
||||
virtual ReturnValue_t initialize() override;
|
||||
ReturnValue_t udp_server_init();
|
||||
|
||||
/**
|
||||
* In addition to default implementation, ethernet link status is checked.
|
||||
* @param operationCode
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override;
|
||||
|
||||
/** TM Send implementation uses udp_send function from lwIP stack
|
||||
* @param data
|
||||
* @param dataLen
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
||||
|
||||
/**
|
||||
* @brief This function is called when an UDP datagram has been
|
||||
* received on the port UDP_PORT.
|
||||
* @param arg
|
||||
* @param upcb_
|
||||
* @param p
|
||||
* @param addr Source address which will be bound to TmTcUdpBridge::lastAdd
|
||||
* @param port
|
||||
*/
|
||||
static void udp_server_receive_callback(void *arg,
|
||||
struct udp_pcb *upcb_, struct pbuf *p, const ip_addr_t *addr,
|
||||
u16_t port);
|
||||
|
||||
/**
|
||||
* Check whether the communication link is up.
|
||||
* Caller must ensure thread-safety by using the bridge lock.
|
||||
* @return
|
||||
*/
|
||||
bool comLinkUp() const;
|
||||
|
||||
private:
|
||||
struct udp_pcb *upcb = nullptr;
|
||||
ip_addr_t lastAdd;
|
||||
u16_t lastPort = 0;
|
||||
bool physicalConnection = false;
|
||||
MutexIF* bridgeLock = nullptr;
|
||||
|
||||
#if TCPIP_RECV_WIRETAPPING == 1
|
||||
bool connectFlag = false;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Used to notify bridge about change in the physical ethernet connection.
|
||||
* Connection does not mean that replies are possible (recipient not set yet), but
|
||||
* disconnect means that we can't send anything. Caller must ensure thread-safety
|
||||
* by using the bridge lock.
|
||||
*/
|
||||
void physicalConnectStatusChange(bool connect);
|
||||
};
|
||||
|
||||
#endif /* BSP_STM32_RTEMS_NETWORKING_TMTCUDPBRIDGE_H_ */
|
66
stm32h7/networking/UdpTcLwIpPollingTask.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include "UdpTcLwIpPollingTask.h"
|
||||
#include "TmTcLwIpUdpBridge.h"
|
||||
#include "app_ethernet.h"
|
||||
#include "ethernetif.h"
|
||||
#include "app_dhcp.h"
|
||||
#include "networking.h"
|
||||
#include <hardware_init.h>
|
||||
|
||||
#include "fsfw/ipc/MutexGuard.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
|
||||
|
||||
|
||||
#include "lwip/timeouts.h"
|
||||
|
||||
UdpTcLwIpPollingTask::UdpTcLwIpPollingTask(object_id_t objectId, object_id_t bridgeId,
|
||||
struct netif* gnetif):
|
||||
SystemObject(objectId), periodicHandleCounter(0), bridgeId(bridgeId), gnetif(gnetif) {
|
||||
}
|
||||
|
||||
UdpTcLwIpPollingTask::~UdpTcLwIpPollingTask() {
|
||||
}
|
||||
|
||||
ReturnValue_t UdpTcLwIpPollingTask::initialize() {
|
||||
udpBridge = ObjectManager::instance()->get<TmTcLwIpUdpBridge>(bridgeId);
|
||||
if(udpBridge == nullptr) {
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
}
|
||||
if (netif_is_link_up(gnetif)) {
|
||||
networking::setEthCableConnected(true);
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Poll the EMAC Interface and pass content to the network interface (lwIP) */
|
||||
ReturnValue_t UdpTcLwIpPollingTask::performOperation(uint8_t operationCode) {
|
||||
/* Read a received packet from the Ethernet buffers and send it
|
||||
to the lwIP for handling */
|
||||
ethernetif_input(gnetif);
|
||||
|
||||
/* Handle timeouts */
|
||||
sys_check_timeouts();
|
||||
|
||||
#if LWIP_NETIF_LINK_CALLBACK == 1
|
||||
networking::ethernetLinkPeriodicHandle(gnetif);
|
||||
#endif
|
||||
|
||||
if(udpBridge != nullptr) {
|
||||
MutexGuard lg(udpBridge->bridgeLock);
|
||||
/* In case ethernet cable is disconnected */
|
||||
if(not networking::getEthCableConnected() and udpBridge->comLinkUp()) {
|
||||
udpBridge->physicalConnectStatusChange(false);
|
||||
}
|
||||
else if(networking::getEthCableConnected() and not udpBridge->comLinkUp()) {
|
||||
udpBridge->physicalConnectStatusChange(true);
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_DHCP == 1
|
||||
DHCP_Periodic_Handle(gnetif);
|
||||
#endif
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
41
stm32h7/networking/UdpTcLwIpPollingTask.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef BSP_STM32_RTEMS_EMACPOLLINGTASK_H_
|
||||
#define BSP_STM32_RTEMS_EMACPOLLINGTASK_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
#include <lwip/netif.h>
|
||||
|
||||
class TmTcLwIpUdpBridge;
|
||||
|
||||
/**
|
||||
* @brief Separate task to poll EMAC interface.
|
||||
* Polled data is passed to the netif (lwIP)
|
||||
*/
|
||||
class UdpTcLwIpPollingTask:
|
||||
public SystemObject,
|
||||
public ExecutableObjectIF,
|
||||
public HasReturnvaluesIF {
|
||||
public:
|
||||
UdpTcLwIpPollingTask(object_id_t objectId, object_id_t bridgeId, struct netif* gnetif);
|
||||
virtual ~UdpTcLwIpPollingTask();
|
||||
|
||||
virtual ReturnValue_t initialize() override;
|
||||
|
||||
/**
|
||||
* Executed periodically.
|
||||
* @param operationCode
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override;
|
||||
private:
|
||||
static const uint8_t PERIODIC_HANDLE_TRIGGER = 5;
|
||||
uint8_t periodicHandleCounter;
|
||||
object_id_t bridgeId = 0;
|
||||
TmTcLwIpUdpBridge* udpBridge = nullptr;
|
||||
struct netif* gnetif = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif /* BSP_STM32_RTEMS_EMACPOLLINGTASK_H_ */
|
157
stm32h7/networking/app_dhcp.cpp
Normal file
@ -0,0 +1,157 @@
|
||||
#include "OBSWConfig.h"
|
||||
|
||||
#include "app_dhcp.h"
|
||||
#include "app_ethernet.h"
|
||||
#include "networking.h"
|
||||
#include "udp_config.h"
|
||||
#include "ethernetif.h"
|
||||
|
||||
#include "lwip/dhcp.h"
|
||||
#include "stm32h7xx_nucleo.h"
|
||||
|
||||
#if LWIP_DHCP == 1
|
||||
|
||||
uint8_t DHCP_state = DHCP_OFF;
|
||||
uint32_t DHCPfineTimer = 0;
|
||||
|
||||
void handle_dhcp_timeout(struct netif* netif);
|
||||
void handle_dhcp_start(struct netif* netif);
|
||||
void handle_dhcp_wait(struct netif* netif, struct dhcp** dhcp);
|
||||
void handle_dhcp_down(struct netif* netif);
|
||||
|
||||
/**
|
||||
* @brief DHCP_Process_Handle
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void DHCP_Process(struct netif *netif)
|
||||
{
|
||||
struct dhcp* dhcp = NULL;
|
||||
switch (DHCP_state) {
|
||||
case DHCP_START: {
|
||||
handle_dhcp_start(netif);
|
||||
break;
|
||||
}
|
||||
case DHCP_WAIT_ADDRESS: {
|
||||
handle_dhcp_wait(netif, &dhcp);
|
||||
break;
|
||||
}
|
||||
|
||||
case DHCP_LINK_DOWN: {
|
||||
handle_dhcp_down(netif);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_dhcp_timeout(struct netif* netif) {
|
||||
ip_addr_t ipaddr;
|
||||
ip_addr_t netmask;
|
||||
ip_addr_t gw;
|
||||
|
||||
DHCP_state = DHCP_TIMEOUT;
|
||||
|
||||
/* Stop DHCP */
|
||||
dhcp_stop(netif);
|
||||
|
||||
/* Static address used */
|
||||
networking::setLwipAddresses(&ipaddr, &netmask, &gw);
|
||||
netif_set_addr(netif, &ipaddr, &netmask, &gw);
|
||||
|
||||
printf("DHCP Timeout\n\r");
|
||||
uint8_t iptxt[20];
|
||||
sprintf((char *)iptxt, "%s", ip4addr_ntoa(netif_ip4_addr(netif)));
|
||||
printf("Assigning static IP address: %s\n", iptxt);
|
||||
|
||||
#if defined FSFW_OSAL_FREERTOS
|
||||
ETH_HandleTypeDef* handle = getEthernetHandle();
|
||||
handle->gState = HAL_ETH_STATE_READY;
|
||||
#endif
|
||||
|
||||
#if OBSW_ETHERNET_TMTC_COMMANDING == 1
|
||||
#if OBSW_ETHERNET_USE_LED1_LED2 == 1
|
||||
BSP_LED_On(LED1);
|
||||
BSP_LED_Off(LED2);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DHCP periodic check
|
||||
* @param netif
|
||||
* @retval None
|
||||
*/
|
||||
void DHCP_Periodic_Handle(struct netif *netif)
|
||||
{
|
||||
/* Fine DHCP periodic process every 500ms */
|
||||
if (HAL_GetTick() - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS) {
|
||||
DHCPfineTimer = HAL_GetTick();
|
||||
/* process DHCP state machine */
|
||||
DHCP_Process(netif);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_dhcp_start(struct netif* netif) {
|
||||
printf("handle_dhcp_start: Looking for DHCP server ...\n\r");
|
||||
#if OBSW_ETHERNET_TMTC_COMMANDING == 1
|
||||
#if OBSW_ETHERNET_USE_LED1_LED2 == 1
|
||||
BSP_LED_Off(LED1);
|
||||
BSP_LED_Off(LED2);
|
||||
#endif
|
||||
#endif
|
||||
ip_addr_set_zero_ip4(&netif->ip_addr);
|
||||
ip_addr_set_zero_ip4(&netif->netmask);
|
||||
ip_addr_set_zero_ip4(&netif->gw);
|
||||
dhcp_start(netif);
|
||||
DHCP_state = DHCP_WAIT_ADDRESS;
|
||||
}
|
||||
|
||||
void handle_dhcp_wait(struct netif* netif, struct dhcp** dhcp) {
|
||||
if (dhcp_supplied_address(netif)) {
|
||||
DHCP_state = DHCP_ADDRESS_ASSIGNED;
|
||||
printf("IP address assigned by a DHCP server: %s\n\r", ip4addr_ntoa(netif_ip4_addr(netif)));
|
||||
printf("Listener port: %d\n\r", UDP_SERVER_PORT);
|
||||
#if OBSW_ETHERNET_TMTC_COMMANDING == 1
|
||||
#if OBSW_ETHERNET_USE_LED1_LED2 == 1
|
||||
BSP_LED_On(LED1);
|
||||
BSP_LED_Off(LED2);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
*dhcp = (struct dhcp*) netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
|
||||
|
||||
/* DHCP timeout */
|
||||
if ((*dhcp)->tries > MAX_DHCP_TRIES)
|
||||
{
|
||||
handle_dhcp_timeout(netif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_dhcp_down(struct netif* netif) {
|
||||
DHCP_state = DHCP_OFF;
|
||||
#if OBSW_ETHERNET_TMTC_COMMANDING == 1
|
||||
printf("DHCP_Process: The network cable is not connected.\n\r");
|
||||
#if OBSW_ETHERNET_USE_LED1_LED2 == 1
|
||||
BSP_LED_Off(LED1);
|
||||
BSP_LED_On(LED2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Global boolean to track ethernet connection */
|
||||
networking::setEthCableConnected(false);
|
||||
}
|
||||
|
||||
uint8_t get_dhcp_state() {
|
||||
return DHCP_state;
|
||||
}
|
||||
|
||||
void set_dhcp_state(uint8_t new_state) {
|
||||
DHCP_state = new_state;
|
||||
}
|
||||
|
||||
#endif /* LWIP_DHCP == 1 */
|
34
stm32h7/networking/app_dhcp.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef BSP_STM32_STM32CUBEH7_BOARDS_NUCLEO_H743ZI_INC_APP_DHCP_H_
|
||||
#define BSP_STM32_STM32CUBEH7_BOARDS_NUCLEO_H743ZI_INC_APP_DHCP_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lwipopts.h"
|
||||
|
||||
#if LWIP_DHCP == 1
|
||||
|
||||
#include "lwip/netif.h"
|
||||
|
||||
/* DHCP process states */
|
||||
#define DHCP_OFF (uint8_t) 0
|
||||
#define DHCP_START (uint8_t) 1
|
||||
#define DHCP_WAIT_ADDRESS (uint8_t) 2
|
||||
#define DHCP_ADDRESS_ASSIGNED (uint8_t) 3
|
||||
#define DHCP_TIMEOUT (uint8_t) 4
|
||||
#define DHCP_LINK_DOWN (uint8_t) 5
|
||||
|
||||
uint8_t get_dhcp_state();
|
||||
void set_dhcp_state(uint8_t new_state);
|
||||
|
||||
void DHCP_Process(struct netif *netif);
|
||||
void DHCP_Periodic_Handle(struct netif *netif);
|
||||
|
||||
#endif /* LWIP_DHCP == 1 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BSP_STM32_STM32CUBEH7_BOARDS_NUCLEO_H743ZI_INC_APP_DHCP_H_ */
|
93
stm32h7/networking/app_ethernet.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "app_ethernet.h"
|
||||
#include "ethernetif.h"
|
||||
#include "udp_config.h"
|
||||
#include "networking.h"
|
||||
|
||||
#if LWIP_DHCP
|
||||
#include "app_dhcp.h"
|
||||
#endif
|
||||
|
||||
#include <lwipopts.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <stm32h7xx_nucleo.h>
|
||||
#include <OBSWConfig.h>
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
uint32_t ethernetLinkTimer = 0;
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
void handle_status_change(struct netif* netif, bool link_up);
|
||||
|
||||
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Notify the User about the network interface config status
|
||||
* @param netif: the network interface
|
||||
* @retval None
|
||||
*/
|
||||
void networking::ethernetLinkStatusUpdated(struct netif *netif)
|
||||
{
|
||||
if (netif_is_link_up(netif))
|
||||
{
|
||||
networking::setEthCableConnected(true);
|
||||
handle_status_change(netif, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
networking::setEthCableConnected(false);
|
||||
handle_status_change(netif, false);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_status_change(struct netif* netif, bool link_up) {
|
||||
if(link_up) {
|
||||
#if LWIP_DHCP
|
||||
/* Update DHCP state machine */
|
||||
set_dhcp_state(DHCP_START);
|
||||
#else
|
||||
uint8_t iptxt[20];
|
||||
sprintf((char *)iptxt, "%s", ip4addr_ntoa(netif_ip4_addr(netif)));
|
||||
printf("\rNetwork cable connected. Static IP address: %s | Port: %d\n\r", iptxt,
|
||||
UDP_SERVER_PORT);
|
||||
#if OBSW_ETHERNET_USE_LED1_LED2 == 1
|
||||
BSP_LED_On(LED1);
|
||||
BSP_LED_Off(LED2);
|
||||
#endif
|
||||
#endif /* LWIP_DHCP */
|
||||
}
|
||||
else {
|
||||
printf("Network cable disconnected\n\r");
|
||||
#if LWIP_DHCP
|
||||
/* Update DHCP state machine */
|
||||
set_dhcp_state(DHCP_LINK_DOWN);
|
||||
#else
|
||||
#if OBSW_ETHERNET_USE_LED1_LED2 == 1
|
||||
BSP_LED_Off(LED1);
|
||||
BSP_LED_On(LED2);
|
||||
#endif
|
||||
#endif /* LWIP_DHCP */
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
|
||||
/**
|
||||
* @brief Ethernet Link periodic check
|
||||
* @param netif
|
||||
* @retval None
|
||||
*/
|
||||
void networking::ethernetLinkPeriodicHandle(struct netif *netif)
|
||||
{
|
||||
/* Ethernet Link every 100ms */
|
||||
if (HAL_GetTick() - ethernetLinkTimer >= 100)
|
||||
{
|
||||
ethernetLinkTimer = HAL_GetTick();
|
||||
ethernet_link_check_state(netif);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
78
stm32h7/networking/app_ethernet.h
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file LwIP/LwIP_UDP_Echo_Client/Inc/app_ethernet.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header for app_ethernet.c module
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted, provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef EXAMPLE_COMMON_APP_ETHERNET_H
|
||||
#define EXAMPLE_COMMON_APP_ETHERNET_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <lwip/netif.h>
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
namespace networking {
|
||||
|
||||
void ethernetLinkStatusUpdated(struct netif *netif);
|
||||
void ethernetLinkPeriodicHandle(struct netif *netif);
|
||||
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EXAMPLE_COMMON_APP_ETHERNET_H */
|
||||
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
613
stm32h7/networking/ethernetif.c
Normal file
@ -0,0 +1,613 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file LwIP/LwIP_UDP_Echo_Client/Src/ethernetif.c
|
||||
* @author MCD Application Team
|
||||
* @brief This file implements Ethernet network interface drivers for lwIP
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted, provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "ethernetif.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <lan8742.h>
|
||||
#include <stm32h7xx_hal.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <lwip/opt.h>
|
||||
#include <lwip/timeouts.h>
|
||||
#include <netif/etharp.h>
|
||||
|
||||
#ifdef FSFW_OSAL_RTEMS
|
||||
#include <rtems.h>
|
||||
#endif
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Network interface name */
|
||||
#define IFNAME0 's'
|
||||
#define IFNAME1 't'
|
||||
|
||||
#define DMA_DESCRIPTOR_ALIGNMENT 0x20
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/*
|
||||
@Note: This interface is implemented to operate in zero-copy mode only:
|
||||
- Rx buffers are allocated statically and passed directly to the LwIP stack
|
||||
they will return back to DMA after been processed by the stack.
|
||||
- Tx Buffers will be allocated from LwIP stack memory heap,
|
||||
then passed to ETH HAL driver.
|
||||
|
||||
@Notes:
|
||||
1.a. ETH DMA Rx descriptors must be contiguous, the default count is 4,
|
||||
to customize it please redefine ETH_RX_DESC_CNT in stm32xxxx_hal_conf.h
|
||||
1.b. ETH DMA Tx descriptors must be contiguous, the default count is 4,
|
||||
to customize it please redefine ETH_TX_DESC_CNT in stm32xxxx_hal_conf.h
|
||||
|
||||
2.a. Rx Buffers number must be between ETH_RX_DESC_CNT and 2*ETH_RX_DESC_CNT
|
||||
2.b. Rx Buffers must have the same size: ETH_RX_BUFFER_SIZE, this value must
|
||||
passed to ETH DMA in the init field (EthHandle.Init.RxBuffLen)
|
||||
*/
|
||||
|
||||
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
|
||||
|
||||
#pragma location=0x30040000
|
||||
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
|
||||
#pragma location=0x30040060
|
||||
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
|
||||
#pragma location=0x30040200
|
||||
uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE]; /* Ethernet Receive Buffers */
|
||||
|
||||
#elif defined ( __CC_ARM ) /* MDK ARM Compiler */
|
||||
|
||||
__attribute__((section(".RxDecripSection"))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
|
||||
__attribute__((section(".TxDecripSection"))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
|
||||
__attribute__((section(".RxArraySection"))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE]; /* Ethernet Receive Buffer */
|
||||
|
||||
#elif defined ( __GNUC__ ) /* GNU Compiler */
|
||||
|
||||
#ifdef FSFW_OSAL_RTEMS
|
||||
/* Put into special RTEMS section and align correctly */
|
||||
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".bsp_nocache"), __aligned__(DMA_DESCRIPTOR_ALIGNMENT))); /* Ethernet Rx DMA Descriptors */
|
||||
/* Put into special RTEMS section and align correctly */
|
||||
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".bsp_nocache"), __aligned__(DMA_DESCRIPTOR_ALIGNMENT))); /* Ethernet Tx DMA Descriptors */
|
||||
/* Ethernet Receive Buffers. Just place somewhere is BSS instead of explicitely placing it */
|
||||
uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE];
|
||||
#elif defined FSFW_OSAL_FREERTOS
|
||||
/* Placement and alignment specified in linker script here */
|
||||
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */
|
||||
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection"))); /* Ethernet Tx DMA Descriptors */
|
||||
uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE] __attribute__((section(".RxArraySection"))); /* Ethernet Receive Buffers */
|
||||
#endif /* FSFW_FREERTOS */
|
||||
|
||||
#endif /* defined ( __GNUC__ ) */
|
||||
|
||||
/* Global boolean to track ethernet connection */
|
||||
bool ethernet_cable_connected;
|
||||
|
||||
struct pbuf_custom rx_pbuf[ETH_RX_DESC_CNT];
|
||||
uint32_t current_pbuf_idx =0;
|
||||
|
||||
ETH_HandleTypeDef EthHandle;
|
||||
ETH_TxPacketConfig TxConfig;
|
||||
|
||||
lan8742_Object_t LAN8742;
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
u32_t sys_now(void);
|
||||
void pbuf_free_custom(struct pbuf *p);
|
||||
|
||||
int32_t ETH_PHY_IO_Init(void);
|
||||
int32_t ETH_PHY_IO_DeInit (void);
|
||||
int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal);
|
||||
int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal);
|
||||
int32_t ETH_PHY_IO_GetTick(void);
|
||||
|
||||
|
||||
lan8742_IOCtx_t LAN8742_IOCtx = {ETH_PHY_IO_Init,
|
||||
ETH_PHY_IO_DeInit,
|
||||
ETH_PHY_IO_WriteReg,
|
||||
ETH_PHY_IO_ReadReg,
|
||||
ETH_PHY_IO_GetTick};
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
/*******************************************************************************
|
||||
LL Driver Interface ( LwIP stack --> ETH)
|
||||
*******************************************************************************/
|
||||
/**
|
||||
* @brief In this function, the hardware should be initialized.
|
||||
* Called from ethernetif_init().
|
||||
*
|
||||
* @param netif the already initialized lwip network interface structure
|
||||
* for this ethernetif
|
||||
*/
|
||||
static void low_level_init(struct netif *netif)
|
||||
{
|
||||
uint32_t idx = 0;
|
||||
uint8_t macaddress[6]= {ETH_MAC_ADDR0, ETH_MAC_ADDR1, ETH_MAC_ADDR2, ETH_MAC_ADDR3, ETH_MAC_ADDR4, ETH_MAC_ADDR5};
|
||||
|
||||
EthHandle.Instance = ETH;
|
||||
EthHandle.Init.MACAddr = macaddress;
|
||||
EthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE;
|
||||
EthHandle.Init.RxDesc = DMARxDscrTab;
|
||||
EthHandle.Init.TxDesc = DMATxDscrTab;
|
||||
EthHandle.Init.RxBuffLen = ETH_RX_BUFFER_SIZE;
|
||||
|
||||
/* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */
|
||||
HAL_ETH_Init(&EthHandle);
|
||||
|
||||
/* set MAC hardware address length */
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
|
||||
/* set MAC hardware address */
|
||||
netif->hwaddr[0] = 0x02;
|
||||
netif->hwaddr[1] = 0x00;
|
||||
netif->hwaddr[2] = 0x00;
|
||||
netif->hwaddr[3] = 0x00;
|
||||
netif->hwaddr[4] = 0x00;
|
||||
netif->hwaddr[5] = 0x00;
|
||||
|
||||
/* maximum transfer unit */
|
||||
netif->mtu = ETH_MAX_PAYLOAD;
|
||||
|
||||
/* device capabilities */
|
||||
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
|
||||
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
|
||||
|
||||
for(idx = 0; idx < ETH_RX_DESC_CNT; idx ++)
|
||||
{
|
||||
HAL_ETH_DescAssignMemory(&EthHandle, idx, Rx_Buff[idx], NULL);
|
||||
|
||||
/* Set Custom pbuf free function */
|
||||
rx_pbuf[idx].custom_free_function = pbuf_free_custom;
|
||||
}
|
||||
|
||||
/* Set Tx packet config common parameters */
|
||||
memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
|
||||
TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
|
||||
TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
|
||||
TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
|
||||
|
||||
/* Set PHY IO functions */
|
||||
LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx);
|
||||
|
||||
/* Initialize the LAN8742 ETH PHY */
|
||||
LAN8742_Init(&LAN8742);
|
||||
|
||||
ethernet_link_check_state(netif);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function should do the actual transmission of the packet. The packet is
|
||||
* contained in the pbuf that is passed to the function. This pbuf
|
||||
* might be chained.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
|
||||
* @return ERR_OK if the packet could be sent
|
||||
* an err_t value if the packet couldn't be sent
|
||||
*
|
||||
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
|
||||
* strange results. You might consider waiting for space in the DMA queue
|
||||
* to become availale since the stack doesn't retry to send a packet
|
||||
* dropped because of memory failure (except for the TCP timers).
|
||||
*/
|
||||
static err_t low_level_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
uint32_t i=0, framelen = 0;
|
||||
struct pbuf *q;
|
||||
err_t errval = ERR_OK;
|
||||
ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];
|
||||
|
||||
for(q = p; q != NULL; q = q->next)
|
||||
{
|
||||
if(i >= ETH_TX_DESC_CNT)
|
||||
return ERR_IF;
|
||||
|
||||
Txbuffer[i].buffer = q->payload;
|
||||
Txbuffer[i].len = q->len;
|
||||
framelen += q->len;
|
||||
|
||||
if(i>0)
|
||||
{
|
||||
Txbuffer[i-1].next = &Txbuffer[i];
|
||||
}
|
||||
|
||||
if(q->next == NULL)
|
||||
{
|
||||
Txbuffer[i].next = NULL;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
TxConfig.Length = framelen;
|
||||
TxConfig.TxBuffer = Txbuffer;
|
||||
|
||||
HAL_StatusTypeDef ret = HAL_ETH_Transmit(&EthHandle, &TxConfig, 20);
|
||||
|
||||
if(ret != HAL_OK) {
|
||||
printf("low_level_output: Could not transmit ethernet packet, code %d!\n\r", ret);
|
||||
}
|
||||
|
||||
return errval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Should allocate a pbuf and transfer the bytes of the incoming
|
||||
* packet from the interface into the pbuf.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return a pbuf filled with the received packet (including MAC header)
|
||||
* NULL on memory error
|
||||
*/
|
||||
static struct pbuf * low_level_input(struct netif *netif)
|
||||
{
|
||||
struct pbuf *p = NULL;
|
||||
ETH_BufferTypeDef RxBuff;
|
||||
uint32_t framelength = 0;
|
||||
|
||||
if (HAL_ETH_IsRxDataAvailable(&EthHandle))
|
||||
{
|
||||
HAL_ETH_GetRxDataBuffer(&EthHandle, &RxBuff);
|
||||
HAL_ETH_GetRxDataLength(&EthHandle, &framelength);
|
||||
|
||||
/* Invalidate data cache for ETH Rx Buffers */
|
||||
SCB_InvalidateDCache_by_Addr((uint32_t *)Rx_Buff, (ETH_RX_DESC_CNT*ETH_RX_BUFFER_SIZE));
|
||||
|
||||
p = pbuf_alloced_custom(PBUF_RAW, framelength, PBUF_POOL, &rx_pbuf[current_pbuf_idx], RxBuff.buffer, ETH_RX_BUFFER_SIZE);
|
||||
if(current_pbuf_idx < (ETH_RX_DESC_CNT -1))
|
||||
{
|
||||
current_pbuf_idx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_pbuf_idx = 0;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is the ethernetif_input task, it is processed when a packet
|
||||
* is ready to be read from the interface. It uses the function low_level_input()
|
||||
* that should handle the actual reception of bytes from the network
|
||||
* interface. Then the type of the received packet is determined and
|
||||
* the appropriate input function is called.
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
*/
|
||||
void ethernetif_input(struct netif *netif)
|
||||
{
|
||||
err_t err;
|
||||
struct pbuf *p;
|
||||
|
||||
/* move received packet into a new pbuf */
|
||||
p = low_level_input(netif);
|
||||
|
||||
/* no packet could be read, silently ignore this */
|
||||
if (p == NULL) return;
|
||||
|
||||
/* entry point to the LwIP stack */
|
||||
err = netif->input(p, netif);
|
||||
|
||||
if (err != ERR_OK)
|
||||
{
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
HAL_ETH_BuildRxDescriptors(&EthHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Should be called at the beginning of the program to set up the
|
||||
* network interface. It calls the function low_level_init() to do the
|
||||
* actual setup of the hardware.
|
||||
*
|
||||
* This function should be passed as a parameter to netif_add().
|
||||
*
|
||||
* @param netif the lwip network interface structure for this ethernetif
|
||||
* @return ERR_OK if the loopif is initialized
|
||||
* ERR_MEM if private data couldn't be allocated
|
||||
* any other err_t on error
|
||||
*/
|
||||
err_t ethernetif_init(struct netif *netif)
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
#if LWIP_NETIF_HOSTNAME
|
||||
/* Initialize interface hostname */
|
||||
netif->hostname = "lwip";
|
||||
#endif /* LWIP_NETIF_HOSTNAME */
|
||||
|
||||
netif->name[0] = IFNAME0;
|
||||
netif->name[1] = IFNAME1;
|
||||
/* We directly use etharp_output() here to save a function call.
|
||||
* You can instead declare your own function an call etharp_output()
|
||||
* from it if you have to do some checks before sending (e.g. if link
|
||||
* is available...) */
|
||||
netif->output = etharp_output;
|
||||
netif->linkoutput = low_level_output;
|
||||
|
||||
/* initialize the hardware */
|
||||
low_level_init(netif);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Custom Rx pbuf free callback
|
||||
* @param pbuf: pbuf to be freed
|
||||
* @retval None
|
||||
*/
|
||||
void pbuf_free_custom(struct pbuf *p)
|
||||
{
|
||||
if(p != NULL)
|
||||
{
|
||||
p->flags = 0;
|
||||
p->next = NULL;
|
||||
p->len = p->tot_len = 0;
|
||||
p->ref = 0;
|
||||
p->payload = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current time in milliseconds
|
||||
* when LWIP_TIMERS == 1 and NO_SYS == 1
|
||||
* @param None
|
||||
* @retval Current Time value
|
||||
*/
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
return HAL_GetTick();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Ethernet MSP Routines
|
||||
*******************************************************************************/
|
||||
/**
|
||||
* @brief Initializes the ETH MSP.
|
||||
* @param heth: ETH handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
/* Ethernett MSP init: RMII Mode */
|
||||
|
||||
/* Enable GPIOs clocks */
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOG_CLK_ENABLE();
|
||||
|
||||
/* Ethernet pins configuration ************************************************/
|
||||
/*
|
||||
RMII_REF_CLK ----------------------> PA1
|
||||
RMII_MDIO -------------------------> PA2
|
||||
RMII_MDC --------------------------> PC1
|
||||
RMII_MII_CRS_DV -------------------> PA7
|
||||
RMII_MII_RXD0 ---------------------> PC4
|
||||
RMII_MII_RXD1 ---------------------> PC5
|
||||
RMII_MII_RXER ---------------------> PG2
|
||||
RMII_MII_TX_EN --------------------> PG11
|
||||
RMII_MII_TXD0 ---------------------> PG13
|
||||
RMII_MII_TXD1 ---------------------> PB13
|
||||
*/
|
||||
|
||||
/* Configure PA1, PA2 and PA7 */
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
/* Configure PB13 */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_13;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
/* Configure PC1, PC4 and PC5 */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
|
||||
|
||||
/* Configure PG2, PG11, PG13 and PG14 */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_11 | GPIO_PIN_13;
|
||||
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
|
||||
|
||||
#if NO_SYS == 0
|
||||
/* Enable the Ethernet global Interrupt */
|
||||
HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0);
|
||||
HAL_NVIC_EnableIRQ(ETH_IRQn);
|
||||
#endif
|
||||
|
||||
/* Enable Ethernet clocks */
|
||||
__HAL_RCC_ETH1MAC_CLK_ENABLE();
|
||||
__HAL_RCC_ETH1TX_CLK_ENABLE();
|
||||
__HAL_RCC_ETH1RX_CLK_ENABLE();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
PHI IO Functions
|
||||
*******************************************************************************/
|
||||
/**
|
||||
* @brief Initializes the MDIO interface GPIO and clocks.
|
||||
* @param None
|
||||
* @retval 0 if OK, -1 if ERROR
|
||||
*/
|
||||
int32_t ETH_PHY_IO_Init(void)
|
||||
{
|
||||
/* We assume that MDIO GPIO configuration is already done
|
||||
in the ETH_MspInit() else it should be done here
|
||||
*/
|
||||
|
||||
/* Configure the MDIO Clock */
|
||||
HAL_ETH_SetMDIOClockRange(&EthHandle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief De-Initializes the MDIO interface .
|
||||
* @param None
|
||||
* @retval 0 if OK, -1 if ERROR
|
||||
*/
|
||||
int32_t ETH_PHY_IO_DeInit (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a PHY register through the MDIO interface.
|
||||
* @param DevAddr: PHY port address
|
||||
* @param RegAddr: PHY register address
|
||||
* @param pRegVal: pointer to hold the register value
|
||||
* @retval 0 if OK -1 if Error
|
||||
*/
|
||||
int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal)
|
||||
{
|
||||
if(HAL_ETH_ReadPHYRegister(&EthHandle, DevAddr, RegAddr, pRegVal) != HAL_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a value to a PHY register through the MDIO interface.
|
||||
* @param DevAddr: PHY port address
|
||||
* @param RegAddr: PHY register address
|
||||
* @param RegVal: Value to be written
|
||||
* @retval 0 if OK -1 if Error
|
||||
*/
|
||||
int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal)
|
||||
{
|
||||
if(HAL_ETH_WritePHYRegister(&EthHandle, DevAddr, RegAddr, RegVal) != HAL_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the time in millisecons used for internal PHY driver process.
|
||||
* @retval Time value
|
||||
*/
|
||||
int32_t ETH_PHY_IO_GetTick(void)
|
||||
{
|
||||
return HAL_GetTick();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @retval None
|
||||
*/
|
||||
void ethernet_link_check_state(struct netif *netif)
|
||||
{
|
||||
ETH_MACConfigTypeDef MACConf;
|
||||
uint32_t PHYLinkState;
|
||||
uint32_t linkchanged = 0, speed = 0, duplex =0;
|
||||
|
||||
PHYLinkState = LAN8742_GetLinkState(&LAN8742);
|
||||
|
||||
if(netif_is_link_up(netif) && (PHYLinkState <= LAN8742_STATUS_LINK_DOWN))
|
||||
{
|
||||
HAL_ETH_Stop(&EthHandle);
|
||||
netif_set_down(netif);
|
||||
netif_set_link_down(netif);
|
||||
}
|
||||
else if(!netif_is_link_up(netif) && (PHYLinkState > LAN8742_STATUS_LINK_DOWN))
|
||||
{
|
||||
switch (PHYLinkState)
|
||||
{
|
||||
case LAN8742_STATUS_100MBITS_FULLDUPLEX:
|
||||
duplex = ETH_FULLDUPLEX_MODE;
|
||||
speed = ETH_SPEED_100M;
|
||||
linkchanged = 1;
|
||||
break;
|
||||
case LAN8742_STATUS_100MBITS_HALFDUPLEX:
|
||||
duplex = ETH_HALFDUPLEX_MODE;
|
||||
speed = ETH_SPEED_100M;
|
||||
linkchanged = 1;
|
||||
break;
|
||||
case LAN8742_STATUS_10MBITS_FULLDUPLEX:
|
||||
duplex = ETH_FULLDUPLEX_MODE;
|
||||
speed = ETH_SPEED_10M;
|
||||
linkchanged = 1;
|
||||
break;
|
||||
case LAN8742_STATUS_10MBITS_HALFDUPLEX:
|
||||
duplex = ETH_HALFDUPLEX_MODE;
|
||||
speed = ETH_SPEED_10M;
|
||||
linkchanged = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(linkchanged)
|
||||
{
|
||||
/* Get MAC Config MAC */
|
||||
HAL_ETH_GetMACConfig(&EthHandle, &MACConf);
|
||||
MACConf.DuplexMode = duplex;
|
||||
MACConf.Speed = speed;
|
||||
HAL_ETH_SetMACConfig(&EthHandle, &MACConf);
|
||||
HAL_ETH_Start(&EthHandle);
|
||||
netif_set_up(netif);
|
||||
netif_set_link_up(netif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ETH_HandleTypeDef* getEthernetHandle() {
|
||||
return &EthHandle;
|
||||
}
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
75
stm32h7/networking/ethernetif.h
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file LwIP/LwIP_HTTP_Server_Netconn_RTOS/Inc/ethernetif.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header for ethernetif.c module
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted, provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __ETHERNETIF_H__
|
||||
#define __ETHERNETIF_H__
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/netif.h"
|
||||
#include <stm32h7xx_hal.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ETH_RX_BUFFER_SIZE (1536UL)
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
|
||||
ETH_HandleTypeDef* getEthernetHandle();
|
||||
err_t ethernetif_init(struct netif *netif);
|
||||
void ethernetif_input(struct netif *netif);
|
||||
void ethernet_link_check_state(struct netif *netif);
|
||||
|
||||
extern ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT];
|
||||
extern ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT];
|
||||
extern uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ETHERNETIF_H__ */
|
19
stm32h7/networking/networking.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "udp_config.h"
|
||||
#include "networking.h"
|
||||
|
||||
bool ethernetCableConnected = false;
|
||||
|
||||
void networking::setEthCableConnected(bool status) {
|
||||
ethernetCableConnected = status;
|
||||
}
|
||||
|
||||
bool networking::getEthCableConnected() {
|
||||
return ethernetCableConnected;
|
||||
}
|
||||
|
||||
void networking::setLwipAddresses(ip_addr_t* ipaddr, ip_addr_t* netmask, ip_addr_t* gw) {
|
||||
IP4_ADDR(ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
|
||||
IP4_ADDR(netmask, NETMASK_ADDR0, NETMASK_ADDR1 ,
|
||||
NETMASK_ADDR2, NETMASK_ADDR3);
|
||||
IP4_ADDR(gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
|
||||
}
|
14
stm32h7/networking/networking.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef BSP_STM32H7_RTEMS_NETWORKING_NETWORKING_H_
|
||||
#define BSP_STM32H7_RTEMS_NETWORKING_NETWORKING_H_
|
||||
|
||||
#include <lwip/netif.h>
|
||||
|
||||
namespace networking {
|
||||
|
||||
void setEthCableConnected(bool status);
|
||||
bool getEthCableConnected();
|
||||
void setLwipAddresses(ip_addr_t* ipaddr, ip_addr_t* netmask, ip_addr_t* gw);
|
||||
|
||||
}
|
||||
|
||||
#endif /* BSP_STM32H7_RTEMS_NETWORKING_NETWORKING_H_ */
|
39
stm32h7/networking/udp_config.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef COMMON_STM32_NUCLEO_NETWORKING_UDP_CONFIG_H_
|
||||
#define COMMON_STM32_NUCLEO_NETWORKING_UDP_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* UDP local connection port. Client needs to bind to this port */
|
||||
#define UDP_SERVER_PORT 7
|
||||
|
||||
/*Static DEST IP ADDRESS: DEST_IP_ADDR0.DEST_IP_ADDR1.DEST_IP_ADDR2.DEST_IP_ADDR3 */
|
||||
#define DEST_IP_ADDR0 ((uint8_t)169U)
|
||||
#define DEST_IP_ADDR1 ((uint8_t)254U)
|
||||
#define DEST_IP_ADDR2 ((uint8_t)39U)
|
||||
#define DEST_IP_ADDR3 ((uint8_t)2U)
|
||||
|
||||
/*Static IP ADDRESS*/
|
||||
#define IP_ADDR0 169
|
||||
#define IP_ADDR1 254
|
||||
#define IP_ADDR2 1
|
||||
#define IP_ADDR3 38
|
||||
|
||||
/*NETMASK*/
|
||||
#define NETMASK_ADDR0 255
|
||||
#define NETMASK_ADDR1 255
|
||||
#define NETMASK_ADDR2 0
|
||||
#define NETMASK_ADDR3 0
|
||||
|
||||
/*Gateway Address*/
|
||||
#define GW_ADDR0 192
|
||||
#define GW_ADDR1 168
|
||||
#define GW_ADDR2 178
|
||||
#define GW_ADDR3 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COMMON_STM32_NUCLEO_NETWORKING_UDP_CONFIG_H_ */
|
@ -1,7 +0,0 @@
|
||||
target_sources(${TARGET_NAME}
|
||||
PRIVATE
|
||||
TestTask.cpp
|
||||
FsfwReaderTask.cpp
|
||||
FsfwExampleTask.cpp
|
||||
MutexExample.cpp
|
||||
)
|
@ -1,77 +0,0 @@
|
||||
#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):
|
||||
SystemObject(objectId), testMode(testModes::A),
|
||||
periodicPrinout(periodicPrintout) {
|
||||
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
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -1,50 +0,0 @@
|
||||
#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>
|
||||
|
||||
|
||||
/**
|
||||
* @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);
|
||||
virtual ~TestTask();
|
||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0);
|
||||
|
||||
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 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_ */
|