Merge branch 'mueller/timeman-update' of https://egit.irs.uni-stuttgart.de/KSat/fsfw into mueller/timeman-update

This commit is contained in:
Robin Müller 2020-12-22 15:30:03 +01:00
commit 5a4f453aaa
46 changed files with 791 additions and 587 deletions

View File

@ -3,30 +3,42 @@ cmake_minimum_required(VERSION 3.13)
set(LIB_FSFW_NAME fsfw)
add_library(${LIB_FSFW_NAME})
# Set options for FSFW OSAL selection.
if(UNIX)
set(OS_FSFW "linux" CACHE STRING "OS abstraction layer used in the FSFW")
elseif(WIN32)
set(OS_FSFW "host" CACHE STRING "OS abstraction layer used in the FSFW")
endif()
set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos)
if(${OS_FSFW} STREQUAL host)
set(OS_FSFW_NAME "Host")
elseif(${OS_FSFW} STREQUAL linux)
set(OS_FSFW_NAME "Linux")
elseif(${OS_FSFW} STREQUAL freertos)
set(OS_FSFW_NAME "FreeRTOS")
elseif(${OS_FSFW} STREQUAL rtems)
set(OS_FSFW_NAME "RTEMS")
else()
message(WARNING "Invalid operating system for FSFW specified! Setting to host..")
set(OS_FSFW_NAME "Host")
set(OS_FSFW "host")
if(NOT OS_FSFW)
message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS")
# Assume host OS and autodetermine from OS_FSFW
if(UNIX)
set(OS_FSFW "linux"
CACHE STRING
"OS abstraction layer used in the FSFW"
)
elseif(WIN32)
set(OS_FSFW "host"
CACHE STRING "OS abstraction layer used in the FSFW"
)
endif()
endif()
message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system")
if(${OS_FSFW} STREQUAL host)
set(OS_FSFW_NAME "Host")
elseif(${OS_FSFW} STREQUAL linux)
set(OS_FSFW_NAME "Linux")
elseif(${OS_FSFW} STREQUAL freertos)
set(OS_FSFW_NAME "FreeRTOS")
target_link_libraries(${LIB_FSFW_NAME} ${LIB_OS_NAME})
elseif(${OS_FSFW} STREQUAL rtems)
set(OS_FSFW_NAME "RTEMS")
else()
message(WARNING
"Invalid operating system for FSFW specified! Setting to host.."
)
set(OS_FSFW_NAME "Host")
set(OS_FSFW "host")
endif()
message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.")
# Options to exclude parts of the FSFW from compilation.
option(FSFW_USE_RMAP "Compile with RMAP" ON)
@ -36,8 +48,14 @@ add_subdirectory(action)
add_subdirectory(container)
add_subdirectory(controller)
add_subdirectory(coordinates)
add_subdirectory(datalinklayer)
if(FSFW_USE_DATALINKLAYER)
add_subdirectory(datalinklayer)
endif()
add_subdirectory(datapool)
add_subdirectory(datapoollocal)
add_subdirectory(housekeeping)
add_subdirectory(devicehandlers)
add_subdirectory(events)
add_subdirectory(fdir)
@ -55,7 +73,7 @@ add_subdirectory(power)
add_subdirectory(pus)
if(FSFW_USE_RMAP)
add_subdirectory(rmap)
add_subdirectory(rmap)
endif()
add_subdirectory(serialize)
@ -73,13 +91,53 @@ add_subdirectory(tmtcservices)
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
# If this is not given, we include the default configuration and emit a warning.
if(NOT FSFW_CONFIG_PATH)
message(WARNING "Flight Software Framework configuration path not set!")
message(WARNING "Setting default configuration!")
add_subdirectory(defaultcfg/fsfwconfig)
message(WARNING "Flight Software Framework configuration path not set!")
message(WARNING "Setting default configuration!")
add_subdirectory(defaultcfg/fsfwconfig)
endif()
# FSFW might be part of a possibly complicated folder structure, so we
# extract the absolute path of the fsfwconfig folder.
if(IS_ABSOLUTE ${FSFW_CONFIG_PATH})
set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH})
else()
get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE
${FSFW_CONFIG_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR}
)
endif()
if(CMAKE_COMPILER_IS_GNUCXX)
set(WARNING_FLAGS
-Wall
-Wextra
-Wshadow=local
-Wimplicit-fallthrough=1
-Wno-unused-parameter
-Wno-psabi
)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(COMPILER_FLAGS "/permissive-")
endif()
# Required include paths to compile the FSFW
target_include_directories(${LIB_FSFW_NAME}
INTERFACE
${FSFW_CONFIG_PATH}
target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_SOURCE_DIR}
${FSFW_CONFIG_PATH_ABSOLUTE}
)
# Includes path required to compile FSFW itself as well
# We assume that the fsfwconfig folder uses include relative to the project
# root here!
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_SOURCE_DIR}
${FSFW_CONFIG_PATH_ABSOLUTE}
)
# Machine specific options can be set with the ABI_FLAGS variable.
target_compile_options(${LIB_FSFW_NAME} PRIVATE
${WARNING_FLAGS}
${COMPILER_FLAGS}
${ABI_FLAGS}
)

View File

@ -1,7 +1,9 @@
#ifndef SGP4PROPAGATOR_H_
#define SGP4PROPAGATOR_H_
#ifndef WIN32
#include <sys/time.h>
#endif
#include "../contrib/sgp4/sgp4unit.h"
#include "../returnvalues/HasReturnvaluesIF.h"

View File

@ -1,11 +1,6 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
ControllerSet.cpp
DataPool.cpp
DataPoolAdmin.cpp
DataPoolParameterWrapper.cpp
DataSet.cpp
HkSwitchHelper.cpp
PoolDataSetBase.cpp
PoolEntry.cpp
PoolRawAccess.cpp
)

View File

@ -59,6 +59,11 @@ uint16_t PoolDataSetBase::getFillCount() const {
ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
if(registeredVariables[count] == nullptr) {
// configuration error.
return HasReturnvaluesIF::RETURN_FAILED;
}
// These checks are often performed by the respective
// variable implementation too, but I guess a double check does not hurt.
if (registeredVariables[count]->getReadWriteMode() !=

View File

@ -0,0 +1,8 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
LocalDataPoolManager.cpp
LocalDataSet.cpp
LocalPoolDataSetBase.cpp
LocalPoolObjectBase.cpp
SharedLocalDataSet.cpp
)

View File

@ -48,7 +48,7 @@ class HousekeepingPacketUpdate;
* @author R. Mueller
*/
class LocalDataPoolManager {
template<typename T> friend class LocalPoolVar;
template<typename T> friend class LocalPoolVariable;
template<typename T, uint16_t vecSize> friend class LocalPoolVector;
friend class LocalPoolDataSetBase;
friend void (Factory::setStaticFrameworkObjectIds)();

View File

@ -22,10 +22,10 @@
* @ingroup data_pool
*/
template<typename T>
class LocalPoolVar: public LocalPoolObjectBase {
class LocalPoolVariable: public LocalPoolObjectBase {
public:
//! Default ctor is forbidden.
LocalPoolVar() = delete;
LocalPoolVariable() = delete;
/**
* This constructor is used by the data creators to have pool variable
@ -43,7 +43,7 @@ public:
* If nullptr, the variable is not registered.
* @param setReadWriteMode Specify the read-write mode of the pool variable.
*/
LocalPoolVar(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
@ -64,7 +64,7 @@ public:
* @param setReadWriteMode Specify the read-write mode of the pool variable.
*
*/
LocalPoolVar(object_id_t poolOwner, lp_id_t poolId,
LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/**
@ -73,10 +73,10 @@ public:
* @param dataSet
* @param setReadWriteMode
*/
LocalPoolVar(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr,
LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
virtual~ LocalPoolVar() {};
virtual~ LocalPoolVariable() {};
/**
* @brief This is the local copy of the data pool entry.
@ -118,23 +118,23 @@ public:
ReturnValue_t commit(dur_millis_t lockTimeout = MutexIF::BLOCKING) override;
LocalPoolVar<T> &operator=(const T& newValue);
LocalPoolVar<T> &operator=(const LocalPoolVar<T>& newPoolVariable);
LocalPoolVariable<T> &operator=(const T& newValue);
LocalPoolVariable<T> &operator=(const LocalPoolVariable<T>& newPoolVariable);
//! Explicit type conversion operator. Allows casting the class to
//! its template type to perform operations on value.
explicit operator T() const;
bool operator==(const LocalPoolVar<T>& other) const;
bool operator==(const LocalPoolVariable<T>& other) const;
bool operator==(const T& other) const;
bool operator!=(const LocalPoolVar<T>& other) const;
bool operator!=(const LocalPoolVariable<T>& other) const;
bool operator!=(const T& other) const;
bool operator<(const LocalPoolVar<T>& other) const;
bool operator<(const LocalPoolVariable<T>& other) const;
bool operator<(const T& other) const;
bool operator>(const LocalPoolVar<T>& other) const;
bool operator>(const LocalPoolVariable<T>& other) const;
bool operator>(const T& other) const;
protected:
@ -160,7 +160,7 @@ protected:
// std::ostream is the type for object std::cout
template <typename U>
friend std::ostream& operator<< (std::ostream &out,
const LocalPoolVar<U> &var);
const LocalPoolVariable<U> &var);
private:
};
@ -168,18 +168,18 @@ private:
#include "LocalPoolVariable.tpp"
template<class T>
using lp_var_t = LocalPoolVar<T>;
using lp_var_t = LocalPoolVariable<T>;
using lp_bool_t = LocalPoolVar<uint8_t>;
using lp_uint8_t = LocalPoolVar<uint8_t>;
using lp_uint16_t = LocalPoolVar<uint16_t>;
using lp_uint32_t = LocalPoolVar<uint32_t>;
using lp_uint64_t = LocalPoolVar<uint64_t>;
using lp_int8_t = LocalPoolVar<int8_t>;
using lp_int16_t = LocalPoolVar<int16_t>;
using lp_int32_t = LocalPoolVar<int32_t>;
using lp_int64_t = LocalPoolVar<int64_t>;
using lp_float_t = LocalPoolVar<float>;
using lp_double_t = LocalPoolVar<double>;
using lp_bool_t = LocalPoolVariable<uint8_t>;
using lp_uint8_t = LocalPoolVariable<uint8_t>;
using lp_uint16_t = LocalPoolVariable<uint16_t>;
using lp_uint32_t = LocalPoolVariable<uint32_t>;
using lp_uint64_t = LocalPoolVariable<uint64_t>;
using lp_int8_t = LocalPoolVariable<int8_t>;
using lp_int16_t = LocalPoolVariable<int16_t>;
using lp_int32_t = LocalPoolVariable<int32_t>;
using lp_int64_t = LocalPoolVariable<int64_t>;
using lp_float_t = LocalPoolVariable<float>;
using lp_double_t = LocalPoolVariable<double>;
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ */

View File

@ -6,32 +6,32 @@
#endif
template<typename T>
inline LocalPoolVar<T>::LocalPoolVar(HasLocalDataPoolIF* hkOwner,
inline LocalPoolVariable<T>::LocalPoolVariable(HasLocalDataPoolIF* hkOwner,
lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
template<typename T>
inline LocalPoolVar<T>::LocalPoolVar(object_id_t poolOwner, lp_id_t poolId,
inline LocalPoolVariable<T>::LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId,
DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
template<typename T>
inline LocalPoolVar<T>::LocalPoolVar(gp_id_t globalPoolId, DataSetIF *dataSet,
inline LocalPoolVariable<T>::LocalPoolVariable(gp_id_t globalPoolId, DataSetIF *dataSet,
pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId,
dataSet, setReadWriteMode){}
template<typename T>
inline ReturnValue_t LocalPoolVar<T>::read(dur_millis_t lockTimeout) {
inline ReturnValue_t LocalPoolVariable<T>::read(dur_millis_t lockTimeout) {
MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING,
lockTimeout);
return readWithoutLock();
}
template<typename T>
inline ReturnValue_t LocalPoolVar<T>::readWithoutLock() {
inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_WRITE) {
sif::debug << "LocalPoolVar: Invalid read write "
"mode for read() call." << std::endl;
@ -53,14 +53,14 @@ inline ReturnValue_t LocalPoolVar<T>::readWithoutLock() {
}
template<typename T>
inline ReturnValue_t LocalPoolVar<T>::commit(dur_millis_t lockTimeout) {
inline ReturnValue_t LocalPoolVariable<T>::commit(dur_millis_t lockTimeout) {
MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING,
lockTimeout);
return commitWithoutLock();
}
template<typename T>
inline ReturnValue_t LocalPoolVar<T>::commitWithoutLock() {
inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_READ) {
sif::debug << "LocalPoolVar: Invalid read write "
"mode for commit() call." << std::endl;
@ -81,88 +81,88 @@ inline ReturnValue_t LocalPoolVar<T>::commitWithoutLock() {
}
template<typename T>
inline ReturnValue_t LocalPoolVar<T>::serialize(uint8_t** buffer, size_t* size,
inline ReturnValue_t LocalPoolVariable<T>::serialize(uint8_t** buffer, size_t* size,
const size_t max_size, SerializeIF::Endianness streamEndianness) const {
return SerializeAdapter::serialize(&value,
buffer, size ,max_size, streamEndianness);
}
template<typename T>
inline size_t LocalPoolVar<T>::getSerializedSize() const {
inline size_t LocalPoolVariable<T>::getSerializedSize() const {
return SerializeAdapter::getSerializedSize(&value);
}
template<typename T>
inline ReturnValue_t LocalPoolVar<T>::deSerialize(const uint8_t** buffer,
inline ReturnValue_t LocalPoolVariable<T>::deSerialize(const uint8_t** buffer,
size_t* size, SerializeIF::Endianness streamEndianness) {
return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness);
}
template<typename T>
inline std::ostream& operator<< (std::ostream &out,
const LocalPoolVar<T> &var) {
const LocalPoolVariable<T> &var) {
out << var.value;
return out;
}
template<typename T>
inline LocalPoolVar<T>::operator T() const {
inline LocalPoolVariable<T>::operator T() const {
return value;
}
template<typename T>
inline LocalPoolVar<T> & LocalPoolVar<T>::operator=(const T& newValue) {
inline LocalPoolVariable<T> & LocalPoolVariable<T>::operator=(const T& newValue) {
value = newValue;
return *this;
}
template<typename T>
inline LocalPoolVar<T>& LocalPoolVar<T>::operator =(
const LocalPoolVar<T>& newPoolVariable) {
inline LocalPoolVariable<T>& LocalPoolVariable<T>::operator =(
const LocalPoolVariable<T>& newPoolVariable) {
value = newPoolVariable.value;
return *this;
}
template<typename T>
inline bool LocalPoolVar<T>::operator ==(const LocalPoolVar<T> &other) const {
inline bool LocalPoolVariable<T>::operator ==(const LocalPoolVariable<T> &other) const {
return this->value == other.value;
}
template<typename T>
inline bool LocalPoolVar<T>::operator ==(const T &other) const {
inline bool LocalPoolVariable<T>::operator ==(const T &other) const {
return this->value == other;
}
template<typename T>
inline bool LocalPoolVar<T>::operator !=(const LocalPoolVar<T> &other) const {
inline bool LocalPoolVariable<T>::operator !=(const LocalPoolVariable<T> &other) const {
return not (*this == other);
}
template<typename T>
inline bool LocalPoolVar<T>::operator !=(const T &other) const {
inline bool LocalPoolVariable<T>::operator !=(const T &other) const {
return not (*this == other);
}
template<typename T>
inline bool LocalPoolVar<T>::operator <(const LocalPoolVar<T> &other) const {
inline bool LocalPoolVariable<T>::operator <(const LocalPoolVariable<T> &other) const {
return this->value < other.value;
}
template<typename T>
inline bool LocalPoolVar<T>::operator <(const T &other) const {
inline bool LocalPoolVariable<T>::operator <(const T &other) const {
return this->value < other;
}
template<typename T>
inline bool LocalPoolVar<T>::operator >(const LocalPoolVar<T> &other) const {
inline bool LocalPoolVariable<T>::operator >(const LocalPoolVariable<T> &other) const {
return not (*this < other);
}
template<typename T>
inline bool LocalPoolVar<T>::operator >(const T &other) const {
inline bool LocalPoolVariable<T>::operator >(const T &other) const {
return not (*this < other);
}

View File

@ -15,12 +15,6 @@
//! Can be used to enable additional debugging printouts for developing the FSFW
#define FSFW_PRINT_VERBOSITY_LEVEL 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)
@ -29,8 +23,8 @@
#if FSFW_OBJ_EVENT_TRANSLATION == 1
//! Specify whether info events are printed too.
#define FSFW_DEBUG_INFO 1
#include <translateObjects.h>
#include <translateEvents.h>
#include "objects/translateObjects.h"
#include "events/translateEvents.h"
#else
#endif
@ -50,6 +44,12 @@ static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8;
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;
//! 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 !
static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6;
}
#endif /* CONFIG_FSFWCONFIG_H_ */

View File

@ -3,6 +3,10 @@
#include "OBSWVersion.h"
#include "objects/systemObjectList.h"
#include "events/subsystemIdRanges.h"
#include "returnvalues/classIds.h"
#ifdef __cplusplus
namespace config {
#endif

View File

@ -1,6 +1,5 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
Event.cpp
EventManager.cpp
EventMessage.cpp
)

View File

@ -2,7 +2,12 @@
#define TIMEVALOPERATIONS_H_
#include <stdint.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/time.h>
#endif
timeval& operator+=(timeval& lhs, const timeval& rhs);

View File

@ -0,0 +1,5 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
HousekeepingMessage.cpp
PeriodicHousekeepingHelper.cpp
)

View File

@ -1,4 +1,4 @@
#include "../ipc/CommandMessageCleaner.h"
#include "CommandMessageCleaner.h"
#include "../devicehandlers/DeviceHandlerMessage.h"
#include "../health/HealthMessage.h"
@ -7,11 +7,12 @@
#include "../monitoring/MonitoringMessage.h"
#include "../subsystem/modes/ModeSequenceMessage.h"
#include "../tmstorage/TmStoreMessage.h"
#include "../housekeeping/HousekeepingMessage.h"
#include "../parameters/ParameterMessage.h"
void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) {
switch(message->getMessageType()){
case messagetypes::MODE_COMMAND:
case messagetypes::MODE_COMMAND:
ModeMessage::clear(message);
break;
case messagetypes::HEALTH_COMMAND:
@ -38,6 +39,9 @@ void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) {
case messagetypes::PARAMETER:
ParameterMessage::clear(message);
break;
case messagetypes::HOUSEKEEPING:
HousekeepingMessage::clear(message);
break;
default:
messagetypes::clearMissionMessage(message);
break;

View File

@ -1,7 +1,7 @@
#ifndef FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_
#define FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_
#include <fsfw/ipc/messageQueueDefinitions.h>
#include "messageQueueDefinitions.h"
#include <cstddef>
#include <cstdint>

View File

@ -1,5 +1,5 @@
#ifndef FRAMEWORK_IPC_MUTEXFACTORY_H_
#define FRAMEWORK_IPC_MUTEXFACTORY_H_
#ifndef FSFW_IPC_MUTEXFACTORY_H_
#define FSFW_IPC_MUTEXFACTORY_H_
#include "MutexIF.h"
/**
@ -31,4 +31,4 @@ private:
#endif /* FRAMEWORK_IPC_MUTEXFACTORY_H_ */
#endif /* FSFW_IPC_MUTEXFACTORY_H_ */

View File

@ -16,8 +16,8 @@ public:
<< timeoutMs << " milliseconds!" << std::endl;
}
else if(status != HasReturnvaluesIF::RETURN_OK){
sif::error << "MutexHelper: Lock of Mutex failed with code " <<
status << std::endl;
sif::error << "MutexHelper: Lock of Mutex failed with code "
<< status << std::endl;
}
}

View File

@ -72,7 +72,7 @@ protected:
return HasReturnvaluesIF::RETURN_OK;
}
LocalPoolVar<T> poolVariable;
LocalPoolVariable<T> poolVariable;
};
#endif /* FSFW_MONITORING_MONITORBASE_H_ */

View File

@ -22,9 +22,23 @@
#else
#error "Can't decide which end is which!"
#endif
#else
#ifdef WIN32
#include <Windows.h>
#if REG_DWORD == REG_DWORD_LITTLE_ENDIAN
#define BYTE_ORDER_SYSTEM LITTLE_ENDIAN
#else
#define BYTE_ORDER_SYSTEM BIG_ENDIAN
#endif
#else
#error __BYTE_ORDER__ not defined
#endif
#endif
#endif

View File

@ -0,0 +1,30 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
Clock.cpp
FixedTimeslotTask.cpp
BinarySemaphore.cpp
BinSemaphUsingTask.cpp
CountingSemaphore.cpp
CountingSemaphUsingTask.cpp
MessageQueue.cpp
Mutex.cpp
MutexFactory.cpp
PeriodicTask.cpp
QueueFactory.cpp
SemaphoreFactory.cpp
TaskFactory.cpp
Timekeeper.cpp
TaskManagement.cpp
)
# FreeRTOS is required to link the FSFW now. It is recommended to compile
# FreeRTOS as a static library and set LIB_OS_NAME to the target name of the
# library.
if(NOT LIB_OS_NAME)
message(FATAL_ERROR
"FreeRTOS needs to be linked as a target and "
"LIB_OS_NAME needs to be set to the target"
)
endif()
target_link_libraries(${LIB_FSWFW_NAME} ${LIB_OS_NAME})

View File

@ -13,9 +13,9 @@ target_sources(${LIB_FSFW_NAME}
)
if(UNIX)
add_definitions(-pthread)
target_link_libraries(${LIB_FSFW_NAME}
PRIVATE
rt
pthread
)
endif()

View File

@ -1,4 +1,4 @@
#include "../../osal/linux/BinarySemaphore.h"
#include "BinarySemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
extern "C" {

View File

@ -76,25 +76,25 @@ timeval Clock::getUptime() {
ReturnValue_t Clock::getUptime(timeval* uptime) {
//TODO This is not posix compatible and delivers only seconds precision
// is the OS not called Linux?
//Linux specific file read but more precise
// Linux specific file read but more precise.
double uptimeSeconds;
if(std::ifstream("/proc/uptime",std::ios::in) >> uptimeSeconds){
uptime->tv_sec = uptimeSeconds;
uptime->tv_usec = uptimeSeconds *(double) 1e6 - (uptime->tv_sec *1e6);
}
return HasReturnvaluesIF::RETURN_OK;
}
//TODO This is not posix compatible and delivers only seconds precision
// I suggest this is moved into another clock function which will
// deliver second precision later.
// Wait for new FSFW Clock function delivering seconds uptime.
//uint32_t Clock::getUptimeSeconds() {
// //TODO This is not posix compatible and delivers only seconds precision
// struct sysinfo sysInfo;
// int result = sysinfo(&sysInfo);
// if(result != 0){
// return HasReturnvaluesIF::RETURN_FAILED;
// }
// return sysInfo.uptime;
return HasReturnvaluesIF::RETURN_OK;
}
//}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime;

View File

@ -3,6 +3,7 @@
#include "../../objectmanager/ObjectManagerIF.h"
#include <fstream>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <cstring>

View File

@ -1,10 +1,9 @@
#ifndef OS_LINUX_MUTEX_H_
#define OS_LINUX_MUTEX_H_
#ifndef FSFW_OSAL_LINUX_MUTEX_H_
#define FSFW_OSAL_LINUX_MUTEX_H_
#include "../../ipc/MutexIF.h"
#include <pthread.h>
class Mutex : public MutexIF {
public:
Mutex();

View File

@ -1,6 +1,7 @@
#include "../../ipc/MutexFactory.h"
#include "Mutex.h"
#include "../../ipc/MutexFactory.h"
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
MutexFactory* MutexFactory::factoryInstance = new MutexFactory();

View File

@ -1,5 +1,7 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "PosixThread.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <cstring>
#include <errno.h>
@ -149,8 +151,10 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
status = pthread_attr_setstack(&attributes, stackPointer, stackSize);
if(status != 0){
sif::error << "Posix Thread attribute setStack failed with: " <<
strerror(status) << std::endl;
sif::error << "PosixThread::createTask: pthread_attr_setstack "
" failed with: " << strerror(status) << std::endl;
sif::error << "Make sure the specified stack size is valid and is "
"larger than the minimum allowed stack size." << std::endl;
}
status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED);

View File

@ -1,6 +1,7 @@
#include "../../tasks/SemaphoreFactory.h"
#include "BinarySemaphore.h"
#include "CountingSemaphore.h"
#include "../../tasks/SemaphoreFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;

View File

@ -1,5 +1,6 @@
#include "FixedTimeslotTask.h"
#include "PeriodicPosixTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h"

View File

@ -1,6 +1,7 @@
#include "Timer.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <errno.h>
#include "Timer.h"
Timer::Timer() {
sigevent sigEvent;

View File

@ -119,7 +119,7 @@ void TcWinUdpPollingTask::setTimeout(double timeoutSeconds) {
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
if(result == -1) {
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
}
}
@ -128,17 +128,22 @@ void TcWinUdpPollingTask::handleReadError() {
int error = WSAGetLastError();
switch(error) {
case(WSANOTINITIALISED): {
sif::info << "TmTcWinUdpBridge::handleReadError: WSANOTINITIALISED: "
sif::info << "TcWinUdpPollingTask::handleReadError: WSANOTINITIALISED: "
<< "WSAStartup(...) call " << "necessary" << std::endl;
break;
}
case(WSAEFAULT): {
sif::info << "TmTcWinUdpBridge::handleReadError: WSADEFAULT: "
sif::info << "TcWinUdpPollingTask::handleReadError: WSADEFAULT: "
<< "Bad address " << std::endl;
break;
}
case(WSAEINVAL): {
sif::info << "TcWinUdpPollingTask::handleReadError: WSAEINVAL: "
<< "Invalid input parameters. " << std::endl;
break;
}
default: {
sif::info << "TmTcWinUdpBridge::handleReadError: Error code: "
sif::info << "TcWinUdpPollingTask::handleReadError: Error code: "
<< error << std::endl;
break;
}

View File

@ -0,0 +1,295 @@
#include "Service3Housekeeping.h"
#include "servicepackets/Service3Packets.h"
#include "../datapoollocal/HasLocalDataPoolIF.h"
Service3Housekeeping::Service3Housekeeping(object_id_t objectId, uint16_t apid,
uint8_t serviceId):
CommandingServiceBase(objectId, apid, serviceId,
NUM_OF_PARALLEL_COMMANDS, COMMAND_TIMEOUT_SECONDS) {}
Service3Housekeeping::~Service3Housekeeping() {}
ReturnValue_t Service3Housekeeping::isValidSubservice(uint8_t subservice) {
switch(static_cast<Subservice>(subservice)) {
case Subservice::ENABLE_PERIODIC_HK_REPORT_GENERATION:
case Subservice::DISABLE_PERIODIC_HK_REPORT_GENERATION:
case Subservice::ENABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION:
case Subservice::DISABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION:
case Subservice::REPORT_HK_REPORT_STRUCTURES:
case Subservice::REPORT_DIAGNOSTICS_REPORT_STRUCTURES :
case Subservice::GENERATE_ONE_PARAMETER_REPORT:
case Subservice::GENERATE_ONE_DIAGNOSTICS_REPORT:
case Subservice::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL:
case Subservice::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL:
return HasReturnvaluesIF::RETURN_OK;
// Telemetry or invalid subservice.
case Subservice::HK_DEFINITIONS_REPORT:
case Subservice::DIAGNOSTICS_DEFINITION_REPORT:
case Subservice::HK_REPORT:
case Subservice::DIAGNOSTICS_REPORT:
default:
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
}
}
ReturnValue_t Service3Housekeeping::getMessageQueueAndObject(uint8_t subservice,
const uint8_t *tcData, size_t tcDataLen,
MessageQueueId_t *id, object_id_t *objectId) {
ReturnValue_t result = checkAndAcquireTargetID(objectId,tcData,tcDataLen);
if(result != RETURN_OK) {
return result;
}
return checkInterfaceAndAcquireMessageQueue(id,objectId);
}
ReturnValue_t Service3Housekeeping::checkAndAcquireTargetID(
object_id_t* objectIdToSet, const uint8_t* tcData, size_t tcDataLen) {
if(SerializeAdapter::deSerialize(objectIdToSet, &tcData, &tcDataLen,
SerializeIF::Endianness::BIG) != HasReturnvaluesIF::RETURN_OK) {
return CommandingServiceBase::INVALID_TC;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service3Housekeeping::checkInterfaceAndAcquireMessageQueue(
MessageQueueId_t* messageQueueToSet, object_id_t* objectId) {
// check HasLocalDataPoolIF property of target
HasLocalDataPoolIF* possibleTarget =
objectManager->get<HasLocalDataPoolIF>(*objectId);
if(possibleTarget == nullptr){
return CommandingServiceBase::INVALID_OBJECT;
}
*messageQueueToSet = possibleTarget->getCommandQueue();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service3Housekeeping::prepareCommand(CommandMessage* message,
uint8_t subservice, const uint8_t *tcData, size_t tcDataLen,
uint32_t *state, object_id_t objectId) {
switch(static_cast<Subservice>(subservice)) {
case Subservice::ENABLE_PERIODIC_HK_REPORT_GENERATION:
return prepareReportingTogglingCommand(message, objectId, true, false,
tcData, tcDataLen);
case Subservice::DISABLE_PERIODIC_HK_REPORT_GENERATION:
return prepareReportingTogglingCommand(message, objectId, false, false,
tcData, tcDataLen);
case Subservice::ENABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION:
return prepareReportingTogglingCommand(message, objectId, true, true,
tcData, tcDataLen);
case Subservice::DISABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION:
return prepareReportingTogglingCommand(message, objectId, false, true,
tcData, tcDataLen);
case Subservice::REPORT_HK_REPORT_STRUCTURES:
return prepareStructureReportingCommand(message, objectId, false, tcData,
tcDataLen);
case Subservice::REPORT_DIAGNOSTICS_REPORT_STRUCTURES:
return prepareStructureReportingCommand(message, objectId, true, tcData,
tcDataLen);
case Subservice::GENERATE_ONE_PARAMETER_REPORT:
return prepareOneShotReportCommand(message, objectId, false,
tcData, tcDataLen);
case Subservice::GENERATE_ONE_DIAGNOSTICS_REPORT:
return prepareOneShotReportCommand(message, objectId, true,
tcData, tcDataLen);
case Subservice::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL:
return prepareCollectionIntervalModificationCommand(message, objectId,
false, tcData, tcDataLen);
case Subservice::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL:
return prepareCollectionIntervalModificationCommand(message, objectId,
true, tcData, tcDataLen);
case Subservice::HK_DEFINITIONS_REPORT:
case Subservice::DIAGNOSTICS_DEFINITION_REPORT:
case Subservice::HK_REPORT:
case Subservice::DIAGNOSTICS_REPORT:
// Those are telemetry packets.
return CommandingServiceBase::INVALID_TC;
default:
// should never happen, subservice was already checked.
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service3Housekeeping::prepareReportingTogglingCommand(
CommandMessage *command, object_id_t objectId,
bool enableReporting, bool isDiagnostics,
const uint8_t* tcData, size_t tcDataLen) {
if(tcDataLen < sizeof(sid_t)) {
// TC data should consist of object ID and set ID.
return CommandingServiceBase::INVALID_TC;
}
sid_t targetSid = buildSid(objectId, &tcData, &tcDataLen);
HousekeepingMessage::setToggleReportingCommand(command, targetSid,
enableReporting, isDiagnostics);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service3Housekeeping::prepareStructureReportingCommand(
CommandMessage *command, object_id_t objectId, bool isDiagnostics,
const uint8_t* tcData, size_t tcDataLen) {
if(tcDataLen < sizeof(sid_t)) {
// TC data should consist of object ID and set ID.
return CommandingServiceBase::INVALID_TC;
}
sid_t targetSid = buildSid(objectId, &tcData, &tcDataLen);
HousekeepingMessage::setStructureReportingCommand(command, targetSid,
isDiagnostics);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service3Housekeeping::prepareOneShotReportCommand(
CommandMessage *command, object_id_t objectId, bool isDiagnostics,
const uint8_t *tcData, size_t tcDataLen) {
if(tcDataLen < sizeof(sid_t)) {
// TC data should consist of object ID and set ID.
return CommandingServiceBase::INVALID_TC;
}
sid_t targetSid = buildSid(objectId, &tcData, &tcDataLen);
HousekeepingMessage::setOneShotReportCommand(command, targetSid,
isDiagnostics);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service3Housekeeping::prepareCollectionIntervalModificationCommand(
CommandMessage *command, object_id_t objectId, bool isDiagnostics,
const uint8_t *tcData, size_t tcDataLen) {
if(tcDataLen < sizeof(sid_t) + sizeof(float)) {
// SID plus the size of the new collection intervL.
return CommandingServiceBase::INVALID_TC;
}
sid_t targetSid = buildSid(objectId, &tcData, &tcDataLen);
float newCollectionInterval = 0;
SerializeAdapter::deSerialize(&newCollectionInterval, &tcData, &tcDataLen,
SerializeIF::Endianness::BIG);
HousekeepingMessage::setCollectionIntervalModificationCommand(command,
targetSid, newCollectionInterval, isDiagnostics);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply,
Command_t previousCommand, uint32_t *state,
CommandMessage* optionalNextCommand, object_id_t objectId,
bool *isStep) {
Command_t command = reply->getCommand();
switch(command) {
case(HousekeepingMessage::HK_REPORT): {
ReturnValue_t result = generateHkReply(reply,
static_cast<uint8_t>(Subservice::HK_REPORT));
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return CommandingServiceBase::EXECUTION_COMPLETE;
}
case(HousekeepingMessage::DIAGNOSTICS_REPORT): {
ReturnValue_t result = generateHkReply(reply,
static_cast<uint8_t>(Subservice::DIAGNOSTICS_REPORT));
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return CommandingServiceBase::EXECUTION_COMPLETE;
}
case(HousekeepingMessage::HK_DEFINITIONS_REPORT): {
return generateHkReply(reply, static_cast<uint8_t>(
Subservice::HK_DEFINITIONS_REPORT));
break;
}
case(HousekeepingMessage::DIAGNOSTICS_DEFINITION_REPORT): {
return generateHkReply(reply, static_cast<uint8_t>(
Subservice::DIAGNOSTICS_DEFINITION_REPORT));
break;
}
case(HousekeepingMessage::HK_REQUEST_SUCCESS): {
return CommandingServiceBase::EXECUTION_COMPLETE;
}
case(HousekeepingMessage::HK_REQUEST_FAILURE): {
failureParameter1 = objectId;
ReturnValue_t error = HasReturnvaluesIF::RETURN_FAILED;
HousekeepingMessage::getHkRequestFailureReply(reply,&error);
failureParameter2 = error;
return CommandingServiceBase::EXECUTION_COMPLETE;
}
default:
sif::error << "Service3Housekeeping::handleReply: Invalid reply with "
<< "reply command " << command << "!" << std::endl;
return CommandingServiceBase::INVALID_REPLY;
}
return HasReturnvaluesIF::RETURN_OK;
}
void Service3Housekeeping::handleUnrequestedReply(
CommandMessage* reply) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
Command_t command = reply->getCommand();
switch(command) {
case(HousekeepingMessage::DIAGNOSTICS_REPORT): {
result = generateHkReply(reply,
static_cast<uint8_t>(Subservice::DIAGNOSTICS_REPORT));
break;
}
case(HousekeepingMessage::HK_REPORT): {
result = generateHkReply(reply,
static_cast<uint8_t>(Subservice::HK_REPORT));
break;
}
default:
sif::error << "Service3Housekeeping::handleUnrequestedReply: Invalid "
<< "reply with " << "reply command " << command << "!"
<< std::endl;
return;
}
if(result != HasReturnvaluesIF::RETURN_OK) {
// Configuration error
sif::debug << "Service3Housekeeping::handleUnrequestedReply:"
<< "Could not generate reply!" << std::endl;
}
}
MessageQueueId_t Service3Housekeeping::getHkQueue() const {
return commandQueue->getId();
}
ReturnValue_t Service3Housekeeping::generateHkReply(
const CommandMessage* hkMessage, uint8_t subserviceId) {
store_address_t storeId;
sid_t sid = HousekeepingMessage::getHkDataReply(hkMessage, &storeId);
auto resultPair = IPCStore->getData(storeId);
if(resultPair.first != HasReturnvaluesIF::RETURN_OK) {
return resultPair.first;
}
HkPacket hkPacket(sid, resultPair.second.data(), resultPair.second.size());
return sendTmPacket(static_cast<uint8_t>(subserviceId),
hkPacket.hkData, hkPacket.hkSize, nullptr, 0);
}
sid_t Service3Housekeeping::buildSid(object_id_t objectId,
const uint8_t** tcData, size_t* tcDataLen) {
sid_t targetSid;
targetSid.objectId = objectId;
// skip deserialization of object ID, was already done.
*tcData += sizeof(object_id_t);
*tcDataLen -= sizeof(object_id_t);
// size check is expected to be performed beforehand!
SerializeAdapter::deSerialize(&targetSid.ownerSetId, tcData, tcDataLen,
SerializeIF::Endianness::BIG);
return targetSid;
}

105
pus/Service3Housekeeping.h Normal file
View File

@ -0,0 +1,105 @@
#ifndef FSFW_PUS_SERVICE3HOUSEKEEPINGSERVICE_H_
#define FSFW_PUS_SERVICE3HOUSEKEEPINGSERVICE_H_
#include "../housekeeping/AcceptsHkPacketsIF.h"
#include "../housekeeping/HousekeepingMessage.h"
#include "../tmtcservices/CommandingServiceBase.h"
/**
* @brief Manges spacecraft housekeeping reports and
* sends pool variables (temperature, GPS data ...) to ground.
*
* @details Full Documentation: ECSS-E70-41A or ECSS-E-ST-70-41C.
* Implementation based on PUS-C
*
* The housekeeping service type provides means to control and adapt the
* spacecraft reporting plan according to the mission phases.
* The housekeeping service type provides the visibility of any
* on-board parameters assembled in housekeeping parameter report structures
* or diagnostic parameter report structures as required for the mission.
* The parameter report structures used by the housekeeping service can
* be predefined on-board or created when needed.
*
* @author R. Mueller
* @ingroup pus_services
*/
class Service3Housekeeping: public CommandingServiceBase,
public AcceptsHkPacketsIF {
public: