Merge branch 'master' into development
This commit is contained in:
commit
59c200254d
11
FSFWVersion.h
Normal file
11
FSFWVersion.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef FSFW_DEFAULTCFG_VERSION_H_
|
||||||
|
#define FSFW_DEFAULTCFG_VERSION_H_
|
||||||
|
|
||||||
|
const char* const FSFW_VERSION_NAME = "fsfw";
|
||||||
|
|
||||||
|
#define FSFW_VERSION 0
|
||||||
|
#define FSFW_SUBVERSION 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_DEFAULTCFG_VERSION_H_ */
|
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Flight Software Framework (FSFW)
|
||||||
|
======
|
||||||
|
|
||||||
|
I want to be written!
|
6
defaultcfg/README.md
Normal file
6
defaultcfg/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# How to setup configuration folder for FSFW
|
||||||
|
|
||||||
|
It is recommended to copy the content of the defaultcfg folder
|
||||||
|
into a config folder which is in the same directory as the Flight
|
||||||
|
Software Framework submodule. After that, the config.mk folder should be
|
||||||
|
included by the primary Makefile with CURRENTPATH set correctly.
|
54
defaultcfg/config/FSFWConfig.h
Normal file
54
defaultcfg/config/FSFWConfig.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef CONFIG_FSFWCONFIG_H_
|
||||||
|
#define CONFIG_FSFWCONFIG_H_
|
||||||
|
|
||||||
|
#include <FSFWVersion.h>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
//! Used to determine whether C++ ostreams are used
|
||||||
|
//! Those can lead to code bloat.
|
||||||
|
#define FSFW_CPP_OSTREAM_ENABLED 1
|
||||||
|
|
||||||
|
//! Reduced printout to further decrese code size
|
||||||
|
//! Be careful, this also turns off most diagnostic prinouts!
|
||||||
|
#define FSFW_REDUCED_PRINTOUT 0
|
||||||
|
|
||||||
|
//! Can be used to enable debugging printouts for developing the FSFW
|
||||||
|
#define FSFW_DEBUGGING 0
|
||||||
|
|
||||||
|
//! Defines the FIFO depth of each commanding service base which
|
||||||
|
//! also determines how many commands a CSB service can handle in one cycle
|
||||||
|
//! simulataneously. This will increase the required RAM for
|
||||||
|
//! each CSB service !
|
||||||
|
#define FSFW_CSB_FIFO_DEPTH 6
|
||||||
|
|
||||||
|
//! If FSFW_OBJ_EVENT_TRANSLATION is set to one,
|
||||||
|
//! additional output which requires the translation files translateObjects
|
||||||
|
//! and translateEvents (and their compiled source files)
|
||||||
|
#define FSFW_OBJ_EVENT_TRANSLATION 0
|
||||||
|
|
||||||
|
#if FSFW_OBJ_EVENT_TRANSLATION == 1
|
||||||
|
#define FSFW_DEBUG_OUTPUT 1
|
||||||
|
//! Specify whether info events are printed too.
|
||||||
|
#define FSFW_DEBUG_INFO 1
|
||||||
|
#include <translateObjects.h>
|
||||||
|
#include <translateEvents.h>
|
||||||
|
#else
|
||||||
|
#define FSFW_DEBUG_OUTPUT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! When using the newlib nano library, C99 support for stdio facilities
|
||||||
|
//! will not be provided. This define should be set to 1 if this is the case.
|
||||||
|
#define FSFW_NO_C99_IO 1
|
||||||
|
|
||||||
|
namespace fsfwconfig {
|
||||||
|
//! Default timestamp size. The default timestamp will be an eight byte CDC
|
||||||
|
//! short timestamp.
|
||||||
|
static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8;
|
||||||
|
|
||||||
|
//! Configure the allocated pool sizes for the event manager.
|
||||||
|
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
|
||||||
|
static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
|
||||||
|
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_FSFWCONFIG_H_ */
|
16
defaultcfg/config/OBSWConfig.h
Normal file
16
defaultcfg/config/OBSWConfig.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef CONFIG_OBSWCONFIG_H_
|
||||||
|
#define CONFIG_OBSWCONFIG_H_
|
||||||
|
|
||||||
|
#include "OBSWVersion.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
namespace config {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Add mission configuration flags here */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CONFIG_OBSWCONFIG_H_ */
|
9
defaultcfg/config/OBSWVersion.h
Normal file
9
defaultcfg/config/OBSWVersion.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef CONFIG_VERSION_H_
|
||||||
|
#define CONFIG_VERSION_H_
|
||||||
|
|
||||||
|
/* OBSW versioning can be specified in this file */
|
||||||
|
|
||||||
|
#define OBSW_VERSION 0
|
||||||
|
#define OBSW_SUBVERSION 0
|
||||||
|
|
||||||
|
#endif /* CONFIG_VERSION_H_ */
|
15
defaultcfg/config/config.mk
Normal file
15
defaultcfg/config/config.mk
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/tmtc/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/devices/*.cpp)
|
||||||
|
|
||||||
|
INCLUDES += $(CURRENTPATH)
|
||||||
|
INCLUDES += $(CURRENTPATH)/objects
|
||||||
|
INCLUDES += $(CURRENTPATH)/returnvalues
|
||||||
|
INCLUDES += $(CURRENTPATH)/tmtc
|
||||||
|
INCLUDES += $(CURRENTPATH)/events
|
||||||
|
INCLUDES += $(CURRENTPATH)/devices
|
||||||
|
INCLUDES += $(CURRENTPATH)/pollingsequence
|
||||||
|
INCLUDES += $(CURRENTPATH)/ipc
|
5
defaultcfg/config/devices/logicalAddresses.cpp
Normal file
5
defaultcfg/config/devices/logicalAddresses.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "logicalAddresses.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
18
defaultcfg/config/devices/logicalAddresses.h
Normal file
18
defaultcfg/config/devices/logicalAddresses.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||||
|
#define CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||||
|
|
||||||
|
#include <config/objects/systemObjectList.h>
|
||||||
|
#include <fsfw/devicehandlers/CookieIF.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used for addresses for physical devices like I2C adresses.
|
||||||
|
*/
|
||||||
|
namespace addresses {
|
||||||
|
/* Logical addresses have uint32_t datatype */
|
||||||
|
enum logicalAddresses: address_t {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */
|
4
defaultcfg/config/devices/powerSwitcherList.cpp
Normal file
4
defaultcfg/config/devices/powerSwitcherList.cpp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#include "powerSwitcherList.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
12
defaultcfg/config/devices/powerSwitcherList.h
Normal file
12
defaultcfg/config/devices/powerSwitcherList.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||||
|
#define CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||||
|
|
||||||
|
namespace switches {
|
||||||
|
/* Switches are uint8_t datatype and go from 0 to 255 */
|
||||||
|
enum switcherList {
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_DEVICES_POWERSWITCHERLIST_H_ */
|
18
defaultcfg/config/events/subsystemIdRanges.h
Normal file
18
defaultcfg/config/events/subsystemIdRanges.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
|
||||||
|
#define CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <fsfw/events/fwSubsystemIdRanges.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Custom subsystem IDs can be added here
|
||||||
|
* @details
|
||||||
|
* Subsystem IDs are used to create unique events.
|
||||||
|
*/
|
||||||
|
namespace SUBSYSTEM_ID {
|
||||||
|
enum: uint8_t {
|
||||||
|
SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ */
|
11
defaultcfg/config/ipc/missionMessageTypes.cpp
Normal file
11
defaultcfg/config/ipc/missionMessageTypes.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include <config/ipc/MissionMessageTypes.h>
|
||||||
|
#include <fsfw/ipc/CommandMessageIF.h>
|
||||||
|
|
||||||
|
void messagetypes::clearMissionMessage(CommandMessage* message) {
|
||||||
|
switch(message->getMessageType()) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
21
defaultcfg/config/ipc/missionMessageTypes.h
Normal file
21
defaultcfg/config/ipc/missionMessageTypes.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||||
|
#define CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/CommandMessage.h>
|
||||||
|
#include <fsfw/ipc/FwMessageTypes.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom command messages are specified here.
|
||||||
|
* Most messages needed to use FSFW are already located in
|
||||||
|
* <fsfw/ipc/FwMessageTypes.h>
|
||||||
|
* @param message Generic Command Message
|
||||||
|
*/
|
||||||
|
namespace messagetypes {
|
||||||
|
enum CustomMessageTypes {
|
||||||
|
MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
void clearMissionMessage(CommandMessage* message);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_IPC_MISSIONMESSAGETYPES_H_ */
|
54
defaultcfg/config/objects/Factory.cpp
Normal file
54
defaultcfg/config/objects/Factory.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "Factory.h"
|
||||||
|
#include "../tmtc/apid.h"
|
||||||
|
#include "../tmtc/pusIds.h"
|
||||||
|
#include "../objects/systemObjectList.h"
|
||||||
|
#include "../devices/logicalAddresses.h"
|
||||||
|
#include "../devices/powerSwitcherList.h"
|
||||||
|
|
||||||
|
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
|
||||||
|
#include <fsfw/events/EventManager.h>
|
||||||
|
#include <fsfw/health/HealthTable.h>
|
||||||
|
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
|
||||||
|
#include <fsfw/tmtcservices/CommandingServiceBase.h>
|
||||||
|
#include <fsfw/tmtcservices/PusServiceBase.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class should be used to create all system objects required for
|
||||||
|
* the on-board software, using the object ID list from the configuration
|
||||||
|
* folder.
|
||||||
|
*
|
||||||
|
* The objects are registered in the internal object manager automatically.
|
||||||
|
* This is used later to add objects to tasks.
|
||||||
|
*
|
||||||
|
* This file also sets static framework IDs.
|
||||||
|
*
|
||||||
|
* Framework objects are created first.
|
||||||
|
* @ingroup init
|
||||||
|
*/
|
||||||
|
void Factory::produce(void) {
|
||||||
|
setStaticFrameworkObjectIds();
|
||||||
|
new EventManager(objects::EVENT_MANAGER);
|
||||||
|
new HealthTable(objects::HEALTH_TABLE);
|
||||||
|
//new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Factory::setStaticFrameworkObjectIds() {
|
||||||
|
PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR;
|
||||||
|
PusServiceBase::packetDestination = objects::TM_FUNNEL;
|
||||||
|
|
||||||
|
CommandingServiceBase::defaultPacketSource = objects::PUS_PACKET_DISTRIBUTOR;
|
||||||
|
CommandingServiceBase::defaultPacketDestination = objects::TM_FUNNEL;
|
||||||
|
|
||||||
|
VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION;
|
||||||
|
|
||||||
|
DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
||||||
|
DeviceHandlerBase::rawDataReceiverId = objects::PUS_SERVICE_2_DEVICE_ACCESS;
|
||||||
|
|
||||||
|
DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
|
||||||
|
|
||||||
|
TmPacketStored::timeStamperId = objects::PUS_TIME;
|
||||||
|
//TmFunnel::downlinkDestination = objects::NO_OBJECT;
|
||||||
|
}
|
||||||
|
|
17
defaultcfg/config/objects/Factory.h
Normal file
17
defaultcfg/config/objects/Factory.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef FACTORY_H_
|
||||||
|
#define FACTORY_H_
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace Factory {
|
||||||
|
/**
|
||||||
|
* @brief Creates all SystemObject elements which are persistent
|
||||||
|
* during execution.
|
||||||
|
*/
|
||||||
|
void produce();
|
||||||
|
void setStaticFrameworkObjectIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FACTORY_H_ */
|
16
defaultcfg/config/objects/systemObjectList.h
Normal file
16
defaultcfg/config/objects/systemObjectList.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||||
|
#define CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||||
|
|
||||||
|
// The objects will be instantiated in the ID order
|
||||||
|
namespace objects {
|
||||||
|
enum sourceObjects: uint32_t {
|
||||||
|
/* All addresses between start and end are reserved for the FSFW */
|
||||||
|
FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION,
|
||||||
|
FSFW_CONFIG_RESERVED_END = TM_STORE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */
|
23
defaultcfg/config/pollingsequence/PollingSequenceFactory.cpp
Normal file
23
defaultcfg/config/pollingsequence/PollingSequenceFactory.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "PollingSequenceFactory.h"
|
||||||
|
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||||
|
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
|
||||||
|
|
||||||
|
ReturnValue_t pst::pollingSequenceInitDefault(
|
||||||
|
FixedTimeslotTaskIF *thisSequence) {
|
||||||
|
/* Length of a communication cycle */
|
||||||
|
uint32_t length = thisSequence->getPeriodMs();
|
||||||
|
|
||||||
|
/* Add polling sequence table here */
|
||||||
|
|
||||||
|
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!"
|
||||||
|
<< std::endl;
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
32
defaultcfg/config/pollingsequence/PollingSequenceFactory.h
Normal file
32
defaultcfg/config/pollingsequence/PollingSequenceFactory.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef POLLINGSEQUENCEFACTORY_H_
|
||||||
|
#define POLLINGSEQUENCEFACTORY_H_
|
||||||
|
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
class FixedTimeslotTaskIF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All device handlers are scheduled by adding them into Polling Sequence Tables (PST)
|
||||||
|
* to satisfy stricter timing requirements of device communication,
|
||||||
|
* A device handler has four different communication steps:
|
||||||
|
* 1. DeviceHandlerIF::SEND_WRITE -> Send write via interface
|
||||||
|
* 2. DeviceHandlerIF::GET_WRITE -> Get confirmation for write
|
||||||
|
* 3. DeviceHandlerIF::SEND_READ -> Send read request
|
||||||
|
* 4. DeviceHandlerIF::GET_READ -> Read from interface
|
||||||
|
* The PST specifies precisely when the respective ComIF functions are called
|
||||||
|
* during the communication cycle time.
|
||||||
|
* The task is created using the FixedTimeslotTaskIF,
|
||||||
|
* which utilises the underlying Operating System Abstraction Layer (OSAL)
|
||||||
|
*
|
||||||
|
* @param thisSequence FixedTimeslotTaskIF * object is passed inside the Factory class when creating the PST
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
namespace pst {
|
||||||
|
|
||||||
|
/* Default PST */
|
||||||
|
ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* POLLINGSEQUENCEINIT_H_ */
|
16
defaultcfg/config/returnvalues/classIds.h
Normal file
16
defaultcfg/config/returnvalues/classIds.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||||
|
#define CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||||
|
|
||||||
|
#include <fsfw/returnvalues/FwClassIds.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CLASS_ID defintions which are required for custom returnvalues.
|
||||||
|
*/
|
||||||
|
namespace CLASS_ID {
|
||||||
|
enum {
|
||||||
|
MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_RETURNVALUES_CLASSIDS_H_ */
|
18
defaultcfg/config/tmtc/apid.h
Normal file
18
defaultcfg/config/tmtc/apid.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef CONFIG_TMTC_APID_H_
|
||||||
|
#define CONFIG_TMTC_APID_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application Process Definition: entity, uniquely identified by an
|
||||||
|
* application process ID (APID), capable of generating telemetry source
|
||||||
|
* packets and receiving telecommand packets.
|
||||||
|
*
|
||||||
|
* Chose APID(s) for mission and define it here.
|
||||||
|
*/
|
||||||
|
namespace apid {
|
||||||
|
static const uint16_t DEFAULT_APID = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_TMTC_APID_H_ */
|
23
defaultcfg/config/tmtc/pusIds.h
Normal file
23
defaultcfg/config/tmtc/pusIds.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef CONFIG_TMTC_PUSIDS_HPP_
|
||||||
|
#define CONFIG_TMTC_PUSIDS_HPP_
|
||||||
|
|
||||||
|
namespace pus {
|
||||||
|
enum Ids: uint8_t {
|
||||||
|
PUS_SERVICE_1 = 1,
|
||||||
|
PUS_SERVICE_2 = 2,
|
||||||
|
PUS_SERVICE_3 = 3,
|
||||||
|
PUS_SERVICE_5 = 5,
|
||||||
|
PUS_SERVICE_6 = 6,
|
||||||
|
PUS_SERVICE_8 = 8,
|
||||||
|
PUS_SERVICE_9 = 9,
|
||||||
|
PUS_SERVICE_11 = 11,
|
||||||
|
PUS_SERVICE_17 = 17,
|
||||||
|
PUS_SERVICE_19 = 19,
|
||||||
|
PUS_SERVICE_20 = 20,
|
||||||
|
PUS_SERVICE_23 = 23,
|
||||||
|
PUS_SERVICE_200 = 200,
|
||||||
|
PUS_SERVICE_201 = 201,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONFIG_TMTC_PUSIDS_HPP_ */
|
@ -1,5 +1,7 @@
|
|||||||
#include "EventManager.h"
|
#include "EventManager.h"
|
||||||
#include "EventMessage.h"
|
#include "EventMessage.h"
|
||||||
|
#include <FSFWConfig.h>
|
||||||
|
|
||||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
#include "../serviceinterface/ServiceInterfaceStream.h"
|
||||||
#include "../ipc/QueueFactory.h"
|
#include "../ipc/QueueFactory.h"
|
||||||
#include "../ipc/MutexFactory.h"
|
#include "../ipc/MutexFactory.h"
|
||||||
@ -12,8 +14,10 @@ const uint16_t EventManager::POOL_SIZES[N_POOLS] = {
|
|||||||
// objects registering for certain events.
|
// objects registering for certain events.
|
||||||
// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher.
|
// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher.
|
||||||
// So a good guess is 75 to a max of 100 pools required for each, which fits well.
|
// So a good guess is 75 to a max of 100 pools required for each, which fits well.
|
||||||
// SHOULDDO: Shouldn't this be in the config folder and passed via ctor?
|
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = {
|
||||||
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 };
|
fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES ,
|
||||||
|
fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS,
|
||||||
|
fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS };
|
||||||
|
|
||||||
EventManager::EventManager(object_id_t setObjectId) :
|
EventManager::EventManager(object_id_t setObjectId) :
|
||||||
SystemObject(setObjectId),
|
SystemObject(setObjectId),
|
||||||
|
13
fsfw.mk
13
fsfw.mk
@ -28,12 +28,25 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/*.cpp)
|
|||||||
# select the OS
|
# select the OS
|
||||||
ifeq ($(OS_FSFW),rtems)
|
ifeq ($(OS_FSFW),rtems)
|
||||||
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/rtems/*.cpp)
|
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/rtems/*.cpp)
|
||||||
|
|
||||||
else ifeq ($(OS_FSFW),linux)
|
else ifeq ($(OS_FSFW),linux)
|
||||||
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/linux/*.cpp)
|
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/linux/*.cpp)
|
||||||
|
|
||||||
else ifeq ($(OS_FSFW),freeRTOS)
|
else ifeq ($(OS_FSFW),freeRTOS)
|
||||||
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/FreeRTOS/*.cpp)
|
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/FreeRTOS/*.cpp)
|
||||||
|
|
||||||
else ifeq ($(OS_FSFW),host)
|
else ifeq ($(OS_FSFW),host)
|
||||||
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/host/*.cpp)
|
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/host/*.cpp)
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/windows/*.cpp)
|
||||||
|
else
|
||||||
|
# For now, the linux UDP bridge sources needs to be included manually by upper makefile
|
||||||
|
# for host OS because we can't be sure the OS is linux.
|
||||||
|
# Following lines can be used to do this:
|
||||||
|
# CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TcUnixUdpPollingTask.cpp
|
||||||
|
# CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TmTcUnixUdpBridge.cpp
|
||||||
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
$(error invalid OS_FSFW specified, valid OS_FSFW are rtems, linux, freeRTOS, host)
|
$(error invalid OS_FSFW specified, valid OS_FSFW are rtems, linux, freeRTOS, host)
|
||||||
endif
|
endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef HASHEALTHIF_H_
|
#ifndef FSFW_HEALTH_HASHEALTHIF_H_
|
||||||
#define HASHEALTHIF_H_
|
#define FSFW_HEALTH_HASHEALTHIF_H_
|
||||||
|
|
||||||
#include "../events/Event.h"
|
#include "../events/Event.h"
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||||
@ -8,9 +8,13 @@
|
|||||||
class HasHealthIF {
|
class HasHealthIF {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef enum {
|
enum HealthState: uint8_t {
|
||||||
HEALTHY = 1, FAULTY = 0, EXTERNAL_CONTROL = 2, NEEDS_RECOVERY = 3, PERMANENT_FAULTY = 4
|
HEALTHY = 1,
|
||||||
} HealthState;
|
FAULTY = 0,
|
||||||
|
EXTERNAL_CONTROL = 2,
|
||||||
|
NEEDS_RECOVERY = 3,
|
||||||
|
PERMANENT_FAULTY = 4
|
||||||
|
};
|
||||||
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
||||||
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
|
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
|
||||||
@ -31,20 +35,17 @@ public:
|
|||||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the Health State
|
* @brief Set the Health State
|
||||||
*
|
|
||||||
* The parent will be informed, if the Health changes
|
* The parent will be informed, if the Health changes
|
||||||
*
|
|
||||||
* @param health
|
* @param health
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t setHealth(HealthState health) = 0;
|
virtual ReturnValue_t setHealth(HealthState health) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get Health State
|
* @brief Get Health State
|
||||||
*
|
|
||||||
* @return Health State of the object
|
* @return Health State of the object
|
||||||
*/
|
*/
|
||||||
virtual HasHealthIF::HealthState getHealth() = 0;
|
virtual HasHealthIF::HealthState getHealth() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* HASHEALTHIF_H_ */
|
#endif /* FSFW_HEALTH_HASHEALTHIF_H_ */
|
||||||
|
@ -12,13 +12,15 @@
|
|||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for Objects that implement HasHealthIF
|
* @brief Helper class for Objects that implement HasHealthIF
|
||||||
|
* @details
|
||||||
|
* It takes care of registering with the Health Table as well as handling
|
||||||
|
* health commands (including replying to the sender) and updating
|
||||||
|
* the Health Table.
|
||||||
*
|
*
|
||||||
* It takes care of registering with the Health Table as well as handling health commands
|
* If a parent is set in the ctor, the parent will be informed with a
|
||||||
* (including replying to the sender) and updating the Health Table.
|
* @c HEALTH_INFO message about changes in the health state.
|
||||||
*
|
* Note that a @c HEALTH_INFO is only generated if the Health
|
||||||
* If a parent is set in the ctor, the parent will be informed with a @c HEALTH_INFO message
|
|
||||||
* about changes in the health state. Note that a @c HEALTH_INFO is only generated if the Health
|
|
||||||
* changes, not for all @c HEALTH_SET commands received.
|
* changes, not for all @c HEALTH_SET commands received.
|
||||||
*
|
*
|
||||||
* It does NOT handle @c HEALTH_INFO messages
|
* It does NOT handle @c HEALTH_INFO messages
|
||||||
@ -27,10 +29,9 @@ class HealthHelper {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ctor
|
|
||||||
*
|
|
||||||
* @param owner
|
* @param owner
|
||||||
* @param objectId the object Id to use when communication with the HealthTable
|
* @param objectId The object Id to use when communication with
|
||||||
|
* the HealthTable
|
||||||
*/
|
*/
|
||||||
HealthHelper(HasHealthIF* owner, object_id_t objectId);
|
HealthHelper(HasHealthIF* owner, object_id_t objectId);
|
||||||
|
|
||||||
@ -57,7 +58,8 @@ public:
|
|||||||
* @param message
|
* @param message
|
||||||
* @return
|
* @return
|
||||||
* -@c RETURN_OK if the message was handled
|
* -@c RETURN_OK if the message was handled
|
||||||
* -@c RETURN_FAILED if the message could not be handled (ie it was not a @c HEALTH_SET or @c HEALTH_READ message)
|
* -@c RETURN_FAILED if the message could not be handled
|
||||||
|
* (ie it was not a @c HEALTH_SET or @c HEALTH_READ message)
|
||||||
*/
|
*/
|
||||||
ReturnValue_t handleHealthCommand(CommandMessage *message);
|
ReturnValue_t handleHealthCommand(CommandMessage *message);
|
||||||
|
|
||||||
@ -78,15 +80,18 @@ public:
|
|||||||
HasHealthIF::HealthState getHealth();
|
HasHealthIF::HealthState getHealth();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param parentQueue the Queue id of the parent object. Set to 0 if no parent present
|
* @param parentQueue The queue ID of the parent object.
|
||||||
|
* Set to 0 if no parent present
|
||||||
*/
|
*/
|
||||||
void setParentQueue(MessageQueueId_t parentQueue);
|
void setParentQueue(MessageQueueId_t parentQueue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param parentQueue the Queue id of the parent object. Set to 0 if no parent present
|
* @param parentQueue The queue ID of the parent object.
|
||||||
|
* Set to 0 if no parent present
|
||||||
* @return
|
* @return
|
||||||
* -@c RETURN_OK if the Health Table was found and the object could be registered
|
* -@c RETURN_OK if the Health Table was found and the object
|
||||||
|
* could be registered
|
||||||
* -@c RETURN_FAILED else
|
* -@c RETURN_FAILED else
|
||||||
*/
|
*/
|
||||||
ReturnValue_t initialize(MessageQueueId_t parentQueue );
|
ReturnValue_t initialize(MessageQueueId_t parentQueue );
|
||||||
@ -110,11 +115,15 @@ private:
|
|||||||
HasHealthIF* owner;
|
HasHealthIF* owner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if the #parentQueue is not NULL, a @c HEALTH_INFO message will be sent to this queue
|
* if the #parentQueue is not NULL, a @c HEALTH_INFO message
|
||||||
* @param health the health is passed as parameter so that the number of calls to the health table can be minimized
|
* will be sent to this queue
|
||||||
|
* @param health
|
||||||
|
* The health is passed as parameter so that the number of
|
||||||
|
* calls to the health table can be minimized
|
||||||
* @param oldHealth information of the previous health state.
|
* @param oldHealth information of the previous health state.
|
||||||
*/
|
*/
|
||||||
void informParent(HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth);
|
void informParent(HasHealthIF::HealthState health,
|
||||||
|
HasHealthIF::HealthState oldHealth);
|
||||||
|
|
||||||
void handleSetHealthCommand(CommandMessage *message);
|
void handleSetHealthCommand(CommandMessage *message);
|
||||||
};
|
};
|
||||||
|
@ -7,11 +7,13 @@ void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command,
|
|||||||
message->setParameter2(oldHealth);
|
message->setParameter2(oldHealth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command) {
|
void HealthMessage::setHealthMessage(CommandMessage* message,
|
||||||
|
Command_t command) {
|
||||||
message->setCommand(command);
|
message->setCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
HasHealthIF::HealthState HealthMessage::getHealth(const CommandMessage* message) {
|
HasHealthIF::HealthState HealthMessage::getHealth(
|
||||||
|
const CommandMessage* message) {
|
||||||
return (HasHealthIF::HealthState) message->getParameter();
|
return (HasHealthIF::HealthState) message->getParameter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef HEALTHMESSAGE_H_
|
#ifndef FSFW_HEALTH_HEALTHMESSAGE_H_
|
||||||
#define HEALTHMESSAGE_H_
|
#define FSFW_HEALTH_HEALTHMESSAGE_H_
|
||||||
|
|
||||||
#include "HasHealthIF.h"
|
#include "HasHealthIF.h"
|
||||||
#include "../ipc/CommandMessage.h"
|
#include "../ipc/CommandMessage.h"
|
||||||
@ -7,14 +7,20 @@
|
|||||||
class HealthMessage {
|
class HealthMessage {
|
||||||
public:
|
public:
|
||||||
static const uint8_t MESSAGE_ID = messagetypes::HEALTH_COMMAND;
|
static const uint8_t MESSAGE_ID = messagetypes::HEALTH_COMMAND;
|
||||||
static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);//REPLY_COMMAND_OK/REPLY_REJECTED
|
|
||||||
static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(3); //NO REPLY!
|
static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);
|
||||||
|
// No reply expected, health will be announced as event!
|
||||||
|
static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(2);
|
||||||
|
// Same as before, but all objects in health table will
|
||||||
|
// announce their health as events.
|
||||||
|
static const Command_t HEALTH_ANNOUNCE_ALL = MAKE_COMMAND_ID(3);
|
||||||
|
|
||||||
static const Command_t HEALTH_INFO = MAKE_COMMAND_ID(5);
|
static const Command_t HEALTH_INFO = MAKE_COMMAND_ID(5);
|
||||||
static const Command_t REPLY_HEALTH_SET = MAKE_COMMAND_ID(6);
|
static const Command_t REPLY_HEALTH_SET = MAKE_COMMAND_ID(6);
|
||||||
|
|
||||||
static void setHealthMessage(CommandMessage *message, Command_t command,
|
static void setHealthMessage(CommandMessage *message, Command_t command,
|
||||||
HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth = HasHealthIF::FAULTY);
|
HasHealthIF::HealthState health,
|
||||||
|
HasHealthIF::HealthState oldHealth = HasHealthIF::FAULTY);
|
||||||
static void setHealthMessage(CommandMessage *message, Command_t command);
|
static void setHealthMessage(CommandMessage *message, Command_t command);
|
||||||
|
|
||||||
static HasHealthIF::HealthState getHealth(const CommandMessage *message);
|
static HasHealthIF::HealthState getHealth(const CommandMessage *message);
|
||||||
@ -27,4 +33,4 @@ private:
|
|||||||
HealthMessage();
|
HealthMessage();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* HEALTHMESSAGE_H_ */
|
#endif /* FSFW_HEALTH_HEALTHMESSAGE_H_ */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "HealthTable.h"
|
#include "HealthTable.h"
|
||||||
#include "../serialize/SerializeAdapter.h"
|
#include "../ipc/MutexHelper.h"
|
||||||
#include "../ipc/MutexFactory.h"
|
#include "../ipc/MutexFactory.h"
|
||||||
|
#include "../serialize/SerializeAdapter.h"
|
||||||
|
|
||||||
HealthTable::HealthTable(object_id_t objectid) :
|
HealthTable::HealthTable(object_id_t objectid) :
|
||||||
SystemObject(objectid) {
|
SystemObject(objectid) {
|
||||||
@ -9,6 +10,12 @@ HealthTable::HealthTable(object_id_t objectid) :
|
|||||||
mapIterator = healthMap.begin();
|
mapIterator = healthMap.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HealthTable::setMutexTimeout(MutexIF::TimeoutType timeoutType,
|
||||||
|
uint32_t timeoutMs) {
|
||||||
|
this->timeoutType = timeoutType;
|
||||||
|
this->mutexTimeoutMs = timeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
HealthTable::~HealthTable() {
|
HealthTable::~HealthTable() {
|
||||||
MutexFactory::instance()->deleteMutex(mutex);
|
MutexFactory::instance()->deleteMutex(mutex);
|
||||||
}
|
}
|
||||||
@ -18,74 +25,63 @@ ReturnValue_t HealthTable::registerObject(object_id_t object,
|
|||||||
if (healthMap.count(object) != 0) {
|
if (healthMap.count(object) != 0) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
healthMap.insert(
|
healthMap.emplace(object, initilialState);
|
||||||
std::pair<object_id_t, HasHealthIF::HealthState>(object,
|
|
||||||
initilialState));
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HealthTable::setHealth(object_id_t object,
|
void HealthTable::setHealth(object_id_t object,
|
||||||
HasHealthIF::HealthState newState) {
|
HasHealthIF::HealthState newState) {
|
||||||
mutex->lockMutex(MutexIF::BLOCKING);
|
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||||
HealthMap::iterator iter = healthMap.find(object);
|
HealthMap::iterator iter = healthMap.find(object);
|
||||||
if (iter != healthMap.end()) {
|
if (iter != healthMap.end()) {
|
||||||
iter->second = newState;
|
iter->second = newState;
|
||||||
}
|
}
|
||||||
mutex->unlockMutex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) {
|
HasHealthIF::HealthState HealthTable::getHealth(object_id_t object) {
|
||||||
HasHealthIF::HealthState state = HasHealthIF::HEALTHY;
|
HasHealthIF::HealthState state = HasHealthIF::HEALTHY;
|
||||||
mutex->lockMutex(MutexIF::BLOCKING);
|
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||||
HealthMap::iterator iter = healthMap.find(object);
|
HealthMap::iterator iter = healthMap.find(object);
|
||||||
if (iter != healthMap.end()) {
|
if (iter != healthMap.end()) {
|
||||||
state = iter->second;
|
state = iter->second;
|
||||||
}
|
}
|
||||||
mutex->unlockMutex();
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HealthTable::getPrintSize() {
|
bool HealthTable::hasHealth(object_id_t object) {
|
||||||
mutex->lockMutex(MutexIF::BLOCKING);
|
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||||
uint32_t size = healthMap.size() * 5 + 2;
|
HealthMap::iterator iter = healthMap.find(object);
|
||||||
mutex->unlockMutex();
|
if (iter != healthMap.end()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HealthTable::getPrintSize() {
|
||||||
|
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||||
|
uint32_t size = healthMap.size() * sizeof(object_id_t) +
|
||||||
|
sizeof(HasHealthIF::HealthState) + sizeof(uint16_t);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HealthTable::hasHealth(object_id_t object) {
|
|
||||||
bool exits = false;
|
|
||||||
mutex->lockMutex(MutexIF::BLOCKING);
|
|
||||||
HealthMap::iterator iter = healthMap.find(object);
|
|
||||||
if (iter != healthMap.end()) {
|
|
||||||
exits = true;
|
|
||||||
}
|
|
||||||
mutex->unlockMutex();
|
|
||||||
return exits;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HealthTable::printAll(uint8_t* pointer, size_t maxSize) {
|
void HealthTable::printAll(uint8_t* pointer, size_t maxSize) {
|
||||||
mutex->lockMutex(MutexIF::BLOCKING);
|
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
uint16_t count = healthMap.size();
|
uint16_t count = healthMap.size();
|
||||||
ReturnValue_t result = SerializeAdapter::serialize(&count,
|
SerializeAdapter::serialize(&count,
|
||||||
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||||
HealthMap::iterator iter;
|
for (const auto& health: healthMap) {
|
||||||
for (iter = healthMap.begin();
|
SerializeAdapter::serialize(&health.first,
|
||||||
iter != healthMap.end() && result == HasReturnvaluesIF::RETURN_OK;
|
|
||||||
++iter) {
|
|
||||||
result = SerializeAdapter::serialize(&iter->first,
|
|
||||||
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
&pointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||||
uint8_t health = iter->second;
|
uint8_t healthValue = health.second;
|
||||||
result = SerializeAdapter::serialize(&health, &pointer, &size,
|
SerializeAdapter::serialize(&healthValue, &pointer, &size,
|
||||||
maxSize, SerializeIF::Endianness::BIG);
|
maxSize, SerializeIF::Endianness::BIG);
|
||||||
}
|
}
|
||||||
mutex->unlockMutex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t HealthTable::iterate(
|
ReturnValue_t HealthTable::iterate(HealthEntry *value, bool reset) {
|
||||||
std::pair<object_id_t, HasHealthIF::HealthState> *value, bool reset) {
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||||
mutex->lockMutex(MutexIF::BLOCKING);
|
MutexHelper(mutex, timeoutType, mutexTimeoutMs);
|
||||||
if (reset) {
|
if (reset) {
|
||||||
mapIterator = healthMap.begin();
|
mapIterator = healthMap.begin();
|
||||||
}
|
}
|
||||||
@ -94,7 +90,5 @@ ReturnValue_t HealthTable::iterate(
|
|||||||
}
|
}
|
||||||
*value = *mapIterator;
|
*value = *mapIterator;
|
||||||
mapIterator++;
|
mapIterator++;
|
||||||
mutex->unlockMutex();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,47 @@
|
|||||||
#ifndef HEALTHTABLE_H_
|
#ifndef FSFW_HEALTH_HEALTHTABLE_H_
|
||||||
#define HEALTHTABLE_H_
|
#define FSFW_HEALTH_HEALTHTABLE_H_
|
||||||
|
|
||||||
#include "HealthTableIF.h"
|
#include "HealthTableIF.h"
|
||||||
#include "../objectmanager/SystemObject.h"
|
#include "../objectmanager/SystemObject.h"
|
||||||
#include "../ipc/MutexIF.h"
|
#include "../ipc/MutexIF.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
typedef std::map<object_id_t, HasHealthIF::HealthState> HealthMap;
|
|
||||||
|
|
||||||
class HealthTable: public HealthTableIF, public SystemObject {
|
class HealthTable: public HealthTableIF, public SystemObject {
|
||||||
public:
|
public:
|
||||||
HealthTable(object_id_t objectid);
|
HealthTable(object_id_t objectid);
|
||||||
virtual ~HealthTable();
|
virtual ~HealthTable();
|
||||||
|
|
||||||
|
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
||||||
|
|
||||||
|
/** HealthTableIF overrides */
|
||||||
virtual ReturnValue_t registerObject(object_id_t object,
|
virtual ReturnValue_t registerObject(object_id_t object,
|
||||||
HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY);
|
HasHealthIF::HealthState initilialState =
|
||||||
|
HasHealthIF::HEALTHY) override;
|
||||||
|
virtual size_t getPrintSize() override;
|
||||||
|
virtual void printAll(uint8_t *pointer, size_t maxSize) override;
|
||||||
|
|
||||||
virtual bool hasHealth(object_id_t object);
|
/** ManagesHealthIF overrides */
|
||||||
virtual void setHealth(object_id_t object, HasHealthIF::HealthState newState);
|
virtual bool hasHealth(object_id_t object) override;
|
||||||
virtual HasHealthIF::HealthState getHealth(object_id_t);
|
virtual void setHealth(object_id_t object,
|
||||||
|
HasHealthIF::HealthState newState) override;
|
||||||
virtual uint32_t getPrintSize();
|
virtual HasHealthIF::HealthState getHealth(object_id_t) override;
|
||||||
virtual void printAll(uint8_t *pointer, size_t maxSize);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
using HealthMap = std::map<object_id_t, HasHealthIF::HealthState>;
|
||||||
|
using HealthEntry = std::pair<object_id_t, HasHealthIF::HealthState>;
|
||||||
|
|
||||||
MutexIF* mutex;
|
MutexIF* mutex;
|
||||||
|
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||||
|
uint32_t mutexTimeoutMs = 20;
|
||||||
|
|
||||||
HealthMap healthMap;
|
HealthMap healthMap;
|
||||||
|
|
||||||
HealthMap::iterator mapIterator;
|
HealthMap::iterator mapIterator;
|
||||||
|
|
||||||
virtual ReturnValue_t iterate(std::pair<object_id_t,HasHealthIF::HealthState> *value, bool reset = false);
|
virtual ReturnValue_t iterate(
|
||||||
|
HealthEntry* value,
|
||||||
|
bool reset = false) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* HEALTHTABLE_H_ */
|
#endif /* FSFW_HEALTH_HEALTHTABLE_H_ */
|
||||||
|
@ -1,26 +1,24 @@
|
|||||||
#ifndef HEALTHTABLEIF_H_
|
#ifndef FSFW_HEALTH_HEALTHTABLEIF_H_
|
||||||
#define HEALTHTABLEIF_H_
|
#define FSFW_HEALTH_HEALTHTABLEIF_H_
|
||||||
|
|
||||||
#include "ManagesHealthIF.h"
|
#include "ManagesHealthIF.h"
|
||||||
#include "../objectmanager/ObjectManagerIF.h"
|
#include "../objectmanager/ObjectManagerIF.h"
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
class HealthTableIF: public ManagesHealthIF {
|
class HealthTableIF: public ManagesHealthIF {
|
||||||
friend class HealthCommandingService;
|
|
||||||
public:
|
public:
|
||||||
virtual ~HealthTableIF() {
|
virtual ~HealthTableIF() {}
|
||||||
}
|
|
||||||
|
|
||||||
virtual ReturnValue_t registerObject(object_id_t object,
|
virtual ReturnValue_t registerObject(object_id_t object,
|
||||||
HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0;
|
HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0;
|
||||||
|
|
||||||
virtual uint32_t getPrintSize() = 0;
|
virtual size_t getPrintSize() = 0;
|
||||||
virtual void printAll(uint8_t *pointer, size_t maxSize) = 0;
|
virtual void printAll(uint8_t *pointer, size_t maxSize) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ReturnValue_t iterate(std::pair<object_id_t,HasHealthIF::HealthState> *value, bool reset = false) = 0;
|
virtual ReturnValue_t iterate(
|
||||||
|
std::pair<object_id_t,HasHealthIF::HealthState> *value,
|
||||||
|
bool reset = false) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* HEALTHTABLEIF_H_ */
|
#endif /* FRAMEWORK_HEALTH_HEALTHTABLEIF_H_ */
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#ifndef FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_
|
#ifndef FSFW_HEALTH_MANAGESHEALTHIF_H_
|
||||||
#define FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_
|
#define FSFW_HEALTH_MANAGESHEALTHIF_H_
|
||||||
|
|
||||||
#include "HasHealthIF.h"
|
#include "HasHealthIF.h"
|
||||||
#include "../objectmanager/ObjectManagerIF.h"
|
#include "../objectmanager/ObjectManagerIF.h"
|
||||||
|
|
||||||
class ManagesHealthIF {
|
class ManagesHealthIF {
|
||||||
public:
|
public:
|
||||||
virtual ~ManagesHealthIF() {
|
virtual ~ManagesHealthIF() {
|
||||||
@ -49,4 +50,4 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_HEALTH_MANAGESHEALTHIF_H_ */
|
#endif /* FSFW_HEALTH_MANAGESHEALTHIF_H_ */
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
|
|
||||||
|
#include "MessageQueue.h"
|
||||||
|
|
||||||
|
#include "../../ipc/MessageQueueSenderIF.h"
|
||||||
|
#include "../../ipc/MessageQueueMessageIF.h"
|
||||||
#include "../../ipc/QueueFactory.h"
|
#include "../../ipc/QueueFactory.h"
|
||||||
#include "../../osal/host/MessageQueue.h"
|
|
||||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
QueueFactory* QueueFactory::factoryInstance = nullptr;
|
QueueFactory* QueueFactory::factoryInstance = nullptr;
|
||||||
|
148
osal/windows/TcWinUdpPollingTask.cpp
Normal file
148
osal/windows/TcWinUdpPollingTask.cpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#include "TcWinUdpPollingTask.h"
|
||||||
|
#include "../../globalfunctions/arrayprinter.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
TcWinUdpPollingTask::TcWinUdpPollingTask(object_id_t objectId,
|
||||||
|
object_id_t tmtcUnixUdpBridge, size_t frameSize,
|
||||||
|
double timeoutSeconds): SystemObject(objectId),
|
||||||
|
tmtcBridgeId(tmtcUnixUdpBridge) {
|
||||||
|
if(frameSize > 0) {
|
||||||
|
this->frameSize = frameSize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up reception buffer with specified frame size.
|
||||||
|
// For now, it is assumed that only one frame is held in the buffer!
|
||||||
|
receptionBuffer.reserve(this->frameSize);
|
||||||
|
receptionBuffer.resize(this->frameSize);
|
||||||
|
|
||||||
|
if(timeoutSeconds == -1) {
|
||||||
|
receptionTimeout = DEFAULT_TIMEOUT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TcWinUdpPollingTask::~TcWinUdpPollingTask() {}
|
||||||
|
|
||||||
|
ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) {
|
||||||
|
// Poll for new UDP datagrams in permanent loop.
|
||||||
|
while(true) {
|
||||||
|
//! Sender Address is cached here.
|
||||||
|
struct sockaddr_in senderAddress;
|
||||||
|
int senderAddressSize = sizeof(senderAddress);
|
||||||
|
ssize_t bytesReceived = recvfrom(serverUdpSocket,
|
||||||
|
reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
|
||||||
|
receptionFlags, reinterpret_cast<sockaddr*>(&senderAddress),
|
||||||
|
&senderAddressSize);
|
||||||
|
if(bytesReceived == SOCKET_ERROR) {
|
||||||
|
// handle error
|
||||||
|
sif::error << "TcWinUdpPollingTask::performOperation: Reception"
|
||||||
|
" error." << std::endl;
|
||||||
|
handleReadError();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//sif::debug << "TcWinUdpPollingTask::performOperation: " << bytesReceived
|
||||||
|
// << " bytes received" << std::endl;
|
||||||
|
|
||||||
|
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
||||||
|
|
||||||
|
}
|
||||||
|
tmtcBridge->registerCommConnect();
|
||||||
|
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
||||||
|
store_address_t storeId;
|
||||||
|
ReturnValue_t result = tcStore->addData(&storeId,
|
||||||
|
receptionBuffer.data(), bytesRead);
|
||||||
|
// arrayprinter::print(receptionBuffer.data(), bytesRead);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
|
||||||
|
"storage failed" << std::endl;
|
||||||
|
sif::error << "Packet size: " << bytesRead << std::endl;
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
TmTcMessage message(storeId);
|
||||||
|
|
||||||
|
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
sif::error << "Serial Polling: Sending message to queue failed"
|
||||||
|
<< std::endl;
|
||||||
|
tcStore->deleteData(storeId);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TcWinUdpPollingTask::initialize() {
|
||||||
|
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
||||||
|
if (tcStore == nullptr) {
|
||||||
|
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
|
||||||
|
<< std::endl;
|
||||||
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmtcBridge = objectManager->get<TmTcWinUdpBridge>(tmtcBridgeId);
|
||||||
|
if(tmtcBridge == nullptr) {
|
||||||
|
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
|
||||||
|
" TMTC bridge object!" << std::endl;
|
||||||
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
serverUdpSocket = tmtcBridge->serverSocket;
|
||||||
|
//sif::info << "TcWinUdpPollingTask::initialize: Server UDP socket "
|
||||||
|
// << serverUdpSocket << std::endl;
|
||||||
|
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TcWinUdpPollingTask::initializeAfterTaskCreation() {
|
||||||
|
// Initialize the destination after task creation. This ensures
|
||||||
|
// that the destination has already been set in the TMTC bridge.
|
||||||
|
targetTcDestination = tmtcBridge->getRequestQueue();
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcWinUdpPollingTask::setTimeout(double timeoutSeconds) {
|
||||||
|
DWORD timeoutMs = timeoutSeconds * 1000.0;
|
||||||
|
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
|
||||||
|
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
|
||||||
|
if(result == -1) {
|
||||||
|
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
|
||||||
|
"receive timeout failed with " << strerror(errno) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcWinUdpPollingTask::handleReadError() {
|
||||||
|
int error = WSAGetLastError();
|
||||||
|
switch(error) {
|
||||||
|
case(WSANOTINITIALISED): {
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleReadError: WSANOTINITIALISED: "
|
||||||
|
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEFAULT): {
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleReadError: WSADEFAULT: "
|
||||||
|
<< "Bad address " << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleReadError: Error code: "
|
||||||
|
<< error << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// to prevent spam.
|
||||||
|
Sleep(1000);
|
||||||
|
}
|
67
osal/windows/TcWinUdpPollingTask.h
Normal file
67
osal/windows/TcWinUdpPollingTask.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
||||||
|
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
|
||||||
|
|
||||||
|
#include "TmTcWinUdpBridge.h"
|
||||||
|
#include "../../objectmanager/SystemObject.h"
|
||||||
|
#include "../../tasks/ExecutableObjectIF.h"
|
||||||
|
#include "../../storagemanager/StorageManagerIF.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This class can be used to implement the polling of a Unix socket,
|
||||||
|
* using UDP for now.
|
||||||
|
* @details
|
||||||
|
* The task will be blocked while the specified number of bytes has not been
|
||||||
|
* received, so TC reception is handled inside a separate task.
|
||||||
|
* This class caches the IP address of the sender. It is assumed there
|
||||||
|
* is only one sender for now.
|
||||||
|
*/
|
||||||
|
class TcWinUdpPollingTask: public SystemObject,
|
||||||
|
public ExecutableObjectIF {
|
||||||
|
friend class TmTcWinUdpBridge;
|
||||||
|
public:
|
||||||
|
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
|
||||||
|
//! 0.5 default milliseconds timeout for now.
|
||||||
|
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
|
||||||
|
|
||||||
|
TcWinUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
||||||
|
size_t frameSize = 0, double timeoutSeconds = -1);
|
||||||
|
virtual~ TcWinUdpPollingTask();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn on optional timeout for UDP polling. In the default mode,
|
||||||
|
* the receive function will block until a packet is received.
|
||||||
|
* @param timeoutSeconds
|
||||||
|
*/
|
||||||
|
void setTimeout(double timeoutSeconds);
|
||||||
|
|
||||||
|
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
|
virtual ReturnValue_t initialize() override;
|
||||||
|
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StorageManagerIF* tcStore = nullptr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//! TMTC bridge is cached.
|
||||||
|
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
||||||
|
TmTcWinUdpBridge* tmtcBridge = nullptr;
|
||||||
|
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||||
|
//! Reception flags: https://linux.die.net/man/2/recvfrom.
|
||||||
|
int receptionFlags = 0;
|
||||||
|
|
||||||
|
//! Server socket, which is member of TMTC bridge and is assigned in
|
||||||
|
//! constructor
|
||||||
|
SOCKET serverUdpSocket = 0;
|
||||||
|
|
||||||
|
std::vector<uint8_t> receptionBuffer;
|
||||||
|
|
||||||
|
size_t frameSize = 0;
|
||||||
|
timeval receptionTimeout;
|
||||||
|
|
||||||
|
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
||||||
|
void handleReadError();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
176
osal/windows/TmTcWinUdpBridge.cpp
Normal file
176
osal/windows/TmTcWinUdpBridge.cpp
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
#include <fsfw/ipc/MutexHelper.h>
|
||||||
|
#include "TmTcWinUdpBridge.h"
|
||||||
|
|
||||||
|
TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId,
|
||||||
|
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
|
||||||
|
uint16_t serverPort, uint16_t clientPort):
|
||||||
|
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||||
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
|
|
||||||
|
// Initiates Winsock DLL.
|
||||||
|
WSAData wsaData;
|
||||||
|
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||||
|
int err = WSAStartup(wVersionRequested, &wsaData);
|
||||||
|
if (err != 0) {
|
||||||
|
/* Tell the user that we could not find a usable */
|
||||||
|
/* Winsock DLL. */
|
||||||
|
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge:"
|
||||||
|
"WSAStartup failed with error: " << err << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
|
||||||
|
if(serverPort != 0xFFFF) {
|
||||||
|
setServerPort = serverPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
|
||||||
|
if(clientPort != 0xFFFF) {
|
||||||
|
setClientPort = clientPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
|
||||||
|
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
if(serverSocket == INVALID_SOCKET) {
|
||||||
|
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not open"
|
||||||
|
" UDP socket!" << std::endl;
|
||||||
|
handleSocketError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAddress.sin_family = AF_INET;
|
||||||
|
|
||||||
|
// Accept packets from any interface. (potentially insecure).
|
||||||
|
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
serverAddress.sin_port = htons(setServerPort);
|
||||||
|
serverAddressLen = sizeof(serverAddress);
|
||||||
|
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,
|
||||||
|
reinterpret_cast<const char*>(&serverSocketOptions),
|
||||||
|
sizeof(serverSocketOptions));
|
||||||
|
|
||||||
|
clientAddress.sin_family = AF_INET;
|
||||||
|
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
clientAddress.sin_port = htons(setClientPort);
|
||||||
|
clientAddressLen = sizeof(clientAddress);
|
||||||
|
|
||||||
|
int result = bind(serverSocket,
|
||||||
|
reinterpret_cast<struct sockaddr*>(&serverAddress),
|
||||||
|
serverAddressLen);
|
||||||
|
if(result != 0) {
|
||||||
|
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind "
|
||||||
|
"local port " << setServerPort << " to server socket!"
|
||||||
|
<< std::endl;
|
||||||
|
handleBindError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TmTcWinUdpBridge::~TmTcWinUdpBridge() {
|
||||||
|
WSACleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
//clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
|
||||||
|
//clientAddressLen = sizeof(serverAddress);
|
||||||
|
|
||||||
|
// char ipAddress [15];
|
||||||
|
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
||||||
|
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||||
|
|
||||||
|
ssize_t bytesSent = sendto(serverSocket,
|
||||||
|
reinterpret_cast<const char*>(data), dataLen, flags,
|
||||||
|
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
|
||||||
|
if(bytesSent == SOCKET_ERROR) {
|
||||||
|
sif::error << "TmTcWinUdpBridge::sendTm: Send operation failed."
|
||||||
|
<< std::endl;
|
||||||
|
handleSendError();
|
||||||
|
}
|
||||||
|
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
|
||||||
|
// " sent." << std::endl;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
|
||||||
|
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
|
||||||
|
|
||||||
|
// char ipAddress [15];
|
||||||
|
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
||||||
|
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||||
|
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
|
||||||
|
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||||
|
|
||||||
|
// Set new IP address if it has changed.
|
||||||
|
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
|
||||||
|
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
|
||||||
|
clientAddressLen = sizeof(clientAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TmTcWinUdpBridge::handleSocketError() {
|
||||||
|
int errCode = WSAGetLastError();
|
||||||
|
switch(errCode) {
|
||||||
|
case(WSANOTINITIALISED): {
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleSocketError: WSANOTINITIALISED: "
|
||||||
|
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
/*
|
||||||
|
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
||||||
|
windows-sockets-error-codes-2
|
||||||
|
*/
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleSocketError: Error code: "
|
||||||
|
<< errCode << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TmTcWinUdpBridge::handleBindError() {
|
||||||
|
int errCode = WSAGetLastError();
|
||||||
|
switch(errCode) {
|
||||||
|
case(WSANOTINITIALISED): {
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleBindError: WSANOTINITIALISED: "
|
||||||
|
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
/*
|
||||||
|
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
||||||
|
windows-sockets-error-codes-2
|
||||||
|
*/
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleBindError: Error code: "
|
||||||
|
<< errCode << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TmTcWinUdpBridge::handleSendError() {
|
||||||
|
int errCode = WSAGetLastError();
|
||||||
|
switch(errCode) {
|
||||||
|
case(WSANOTINITIALISED): {
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleSendError: WSANOTINITIALISED: "
|
||||||
|
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEADDRNOTAVAIL): {
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleReadError: WSAEADDRNOTAVAIL: "
|
||||||
|
<< "Check target address. " << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
/*
|
||||||
|
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
||||||
|
windows-sockets-error-codes-2
|
||||||
|
*/
|
||||||
|
sif::info << "TmTcWinUdpBridge::handleSendError: Error code: "
|
||||||
|
<< errCode << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
49
osal/windows/TmTcWinUdpBridge.h
Normal file
49
osal/windows/TmTcWinUdpBridge.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
|
||||||
|
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
|
||||||
|
|
||||||
|
#include "../../tmtcservices/TmTcBridge.h"
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
class TmTcWinUdpBridge: public TmTcBridge {
|
||||||
|
friend class TcWinUdpPollingTask;
|
||||||
|
public:
|
||||||
|
// The ports chosen here should not be used by any other process.
|
||||||
|
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
|
||||||
|
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
|
||||||
|
|
||||||
|
TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
|
object_id_t tmStoreId, object_id_t tcStoreId,
|
||||||
|
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
|
||||||
|
virtual~ TmTcWinUdpBridge();
|
||||||
|
|
||||||
|
void checkAndSetClientAddress(sockaddr_in clientAddress);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SOCKET serverSocket = 0;
|
||||||
|
|
||||||
|
const int serverSocketOptions = 0;
|
||||||
|
|
||||||
|
struct sockaddr_in clientAddress;
|
||||||
|
int clientAddressLen = 0;
|
||||||
|
|
||||||
|
struct sockaddr_in serverAddress;
|
||||||
|
int serverAddressLen = 0;
|
||||||
|
|
||||||
|
//! Access to the client address is mutex protected as it is set
|
||||||
|
//! by another task.
|
||||||
|
MutexIF* mutex;
|
||||||
|
|
||||||
|
void handleSocketError();
|
||||||
|
void handleBindError();
|
||||||
|
void handleSendError();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_
|
#ifndef FSFW_RETURNVALUES_HASRETURNVALUESIF_H_
|
||||||
#define FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_
|
#define FSFW_RETURNVALUES_HASRETURNVALUESIF_H_
|
||||||
|
|
||||||
#include "FwClassIds.h"
|
#include "FwClassIds.h"
|
||||||
#include <returnvalues/classIds.h>
|
#include <returnvalues/classIds.h>
|
||||||
@ -15,9 +15,17 @@ public:
|
|||||||
static const ReturnValue_t RETURN_FAILED = 1;
|
static const ReturnValue_t RETURN_FAILED = 1;
|
||||||
virtual ~HasReturnvaluesIF() {}
|
virtual ~HasReturnvaluesIF() {}
|
||||||
|
|
||||||
static ReturnValue_t makeReturnCode(uint8_t interfaceId, uint8_t number) {
|
/**
|
||||||
return (interfaceId << 8) + number;
|
* It is discouraged to use the input parameters 0,0 and 0,1 as this
|
||||||
|
* will generate the RETURN_OK and RETURN_FAILED returnvalues.
|
||||||
|
* @param interfaceId
|
||||||
|
* @param number
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static constexpr ReturnValue_t makeReturnCode(uint8_t interfaceId,
|
||||||
|
uint8_t number) {
|
||||||
|
return (static_cast<ReturnValue_t>(interfaceId) << 8) + number;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_RETURNVALUES_HASRETURNVALUESIF_H_ */
|
#endif /* FSFW_RETURNVALUES_HASRETURNVALUESIF_H_ */
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include "../timemanager/CCSDSTime.h"
|
#include "CCSDSTime.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <FSFWConfig.h>
|
||||||
|
|
||||||
CCSDSTime::CCSDSTime() {
|
CCSDSTime::CCSDSTime() {
|
||||||
}
|
}
|
||||||
@ -158,15 +159,16 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
|||||||
}
|
}
|
||||||
// Newlib nano can't parse uint8, see SCNu8 documentation and https://sourceware.org/newlib/README
|
// Newlib nano can't parse uint8, see SCNu8 documentation and https://sourceware.org/newlib/README
|
||||||
// Suggestion: use uint16 all the time. This should work on all systems.
|
// Suggestion: use uint16 all the time. This should work on all systems.
|
||||||
#ifdef NEWLIB_NANO_NO_C99_IO
|
#if FSFW_NO_C99_IO == 1
|
||||||
uint16_t year;
|
uint16_t year;
|
||||||
uint16_t month;
|
uint16_t month;
|
||||||
uint16_t day;
|
uint16_t day;
|
||||||
uint16_t hour;
|
uint16_t hour;
|
||||||
uint16_t minute;
|
uint16_t minute;
|
||||||
float second;
|
float second;
|
||||||
int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year,
|
int count = sscanf((char *) from, "%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16 "T%"
|
||||||
&month, &day, &hour, &minute, &second);
|
"2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &month, &day, &hour,
|
||||||
|
&minute, &second);
|
||||||
if (count == 6) {
|
if (count == 6) {
|
||||||
to->year = year;
|
to->year = year;
|
||||||
to->month = month;
|
to->month = month;
|
||||||
@ -179,12 +181,13 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try Code B (yyyy-ddd)
|
// try Code B (yyyy-ddd)
|
||||||
count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%2" SCNu16 ":%fZ", &year, &day,
|
count = sscanf((char *) from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16 ":%"
|
||||||
&hour, &minute, &second);
|
"2" SCNu16 ":%fZ", &year, &day, &hour, &minute, &second);
|
||||||
if (count == 5) {
|
if (count == 5) {
|
||||||
uint8_t tempDay;
|
uint8_t tempDay;
|
||||||
ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year,
|
ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year,
|
||||||
reinterpret_cast<uint8_t *>(&month), reinterpret_cast<uint8_t *>(&tempDay));
|
reinterpret_cast<uint8_t *>(&month),
|
||||||
|
reinterpret_cast<uint8_t *>(&tempDay));
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,16 @@ run in the terminal or in eclipse.
|
|||||||
|
|
||||||
### Instructions
|
### Instructions
|
||||||
|
|
||||||
|
To run the fsfw unittests in the project, perform following steps:
|
||||||
|
|
||||||
|
1. Copy the testcfg folder the project root (folder containing the FSFW).
|
||||||
|
2. There is a makefile inside the testcfg folder which can be used to have
|
||||||
|
a starting point to compile the unit tests. Copy that Makefile to the project
|
||||||
|
root
|
||||||
|
3. Create a folder named catch2 (can have other name which requires Makefile
|
||||||
|
adaption) and copy the Catch2 header files there (NOTE: CMake support
|
||||||
|
not enabled yet!)
|
||||||
|
|
||||||
### Eclipse CDT settings
|
### Eclipse CDT settings
|
||||||
|
|
||||||
The default eclipse terminal has issues displaying the colors used
|
The default eclipse terminal has issues displaying the colors used
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
#ifndef HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
||||||
#define HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
#define HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
||||||
|
|
||||||
#include <fsfw/datapoolglob/GlobalDataPool.h>
|
#include <fsfw/datapool/DataPool.h>
|
||||||
#include <fsfw/datapool/PoolEntryIF.h>
|
#include <fsfw/datapool/PoolEntryIF.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
Loading…
Reference in New Issue
Block a user