diff --git a/src/fsfw/CMakeLists.txt b/src/fsfw/CMakeLists.txt index 1daad714..100c2a5b 100644 --- a/src/fsfw/CMakeLists.txt +++ b/src/fsfw/CMakeLists.txt @@ -15,6 +15,7 @@ add_subdirectory(globalfunctions) add_subdirectory(health) add_subdirectory(housekeeping) add_subdirectory(internalerror) +add_subdirectory(introspection) add_subdirectory(ipc) add_subdirectory(memory) add_subdirectory(modes) diff --git a/src/fsfw/introspection/CMakeLists.txt b/src/fsfw/introspection/CMakeLists.txt new file mode 100644 index 00000000..de99d508 --- /dev/null +++ b/src/fsfw/introspection/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE ParameterTypeSelector.cpp) diff --git a/src/fsfw/introspection/ClasslessEnum.h b/src/fsfw/introspection/ClasslessEnum.h new file mode 100644 index 00000000..5c3f3635 --- /dev/null +++ b/src/fsfw/introspection/ClasslessEnum.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include + +// TODO ifdef EnumIF, consistent naming of functions arrays and macros (probably enum values and +// descriptions) + +#include "EnumIF.h" +#include "EnumCommon.h" + +#ifdef FSFW_INTROSPECTION + +#define FSFW_CLASSLESS_ENUM(name, type, elements) \ + enum : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) }; \ + \ + class name : public EnumIF { \ + public: \ + enum : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) }; \ + name(type value) : value(value) {} \ + name() : value(-1) {} \ + name(const name &other) : value(other.value) {} \ + int64_t getValue() const override { return value; } \ + operator type() { return value; } \ + name &operator=(name other) { \ + value = other.value; \ + return *this; \ + } \ + name &operator=(type value) { \ + this->value = value; \ + return *this; \ + } \ + CREATE_KEY_ARRAY(elements, type) \ + VALUE_CHECK(type) \ + GET_INDEX() \ + CREATE_DESCRIPTION_ARRAY(elements) \ + GET_DESCRIPTION_FUNC() \ + private: \ + type value; \ + }; + +#else + +#define FSFW_CLASSLESS_ENUM(name, type, elements) \ + enum name : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) }; + +#endif \ No newline at end of file diff --git a/src/fsfw/introspection/Enum.h b/src/fsfw/introspection/Enum.h new file mode 100644 index 00000000..93b01bdd --- /dev/null +++ b/src/fsfw/introspection/Enum.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include + +#include + +// TODO ifdef EnumIF, consistent naming of functions arrays and macros (probably enum values and +// descriptions) + +#include "EnumIF.h" +#include "EnumCommon.h" + + +#ifdef FSFW_INTROSPECTION + +#define FSFW_ENUM(name, type, elements) \ + class name : public EnumIF, public SerializeIF { \ + public: \ + enum : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) }; \ + name(type value) : value(value) {} \ + name() : value(-1) {} \ + name(const name &other) : value(other.value) {} \ + int64_t getValue() const override { return value; } \ + operator type() { return value; } \ + name &operator=(name other) { \ + value = other.value; \ + return *this; \ + } \ + name &operator=(type value) { \ + this->value = value; \ + return *this; \ + } \ + CREATE_KEY_ARRAY(elements, type) \ + VALUE_CHECK(type) \ + GET_INDEX() \ + CREATE_DESCRIPTION_ARRAY(elements) \ + GET_DESCRIPTION_FUNC() \ + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, \ + Endianness streamEndianness) const override { \ + return SerializeAdapter::serialize<>(&value, buffer, size, maxSize, streamEndianness); \ + } \ + virtual size_t getSerializedSize() const override { \ + return SerializeAdapter::getSerializedSize<>(&value); \ + } \ + virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, \ + Endianness streamEndianness) override { \ + return SerializeAdapter::deSerialize<>(&value, buffer, size, streamEndianness); \ + } \ + \ + private: \ + type value; \ + }; + + +#else + +#define FSFW_ENUM(name, type, elements) \ + enum class name : type { \ + BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) \ + }; + + +#endif \ No newline at end of file diff --git a/src/fsfw/introspection/EnumCommon.h b/src/fsfw/introspection/EnumCommon.h new file mode 100644 index 00000000..7d5523b4 --- /dev/null +++ b/src/fsfw/introspection/EnumCommon.h @@ -0,0 +1,62 @@ +#define CLEAN_ENUM_ITEM(r, data, element) \ + BOOST_PP_IF(BOOST_PP_SUB(BOOST_PP_TUPLE_SIZE(element), 2), \ + (BOOST_PP_TUPLE_ELEM(0, element) = BOOST_PP_TUPLE_ELEM(1, element)), \ + (BOOST_PP_TUPLE_ELEM(0, element))) + +#if defined FSFW_ENUM_VALUE_CHECKS || defined FSFW_INTROSPECTION + + +#define GET_KEY(r, data, element) (BOOST_PP_TUPLE_ELEM(0, element)) +#define GET_DESCRIPTION(r, data, element) \ + BOOST_PP_IF(BOOST_PP_SUB(BOOST_PP_TUPLE_SIZE(element), 2), (BOOST_PP_TUPLE_ELEM(2, element)), \ + (BOOST_PP_TUPLE_ELEM(1, element))) + +#define CREATE_KEY_ARRAY(enum_elements, type) \ + /*was static constexpr, but clang won't compile that*/ \ + int64_t elements[BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_FOR_EACH(GET_KEY, "", enum_elements))] = { \ + BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(GET_KEY, "", enum_elements))}; \ + const int64_t *getElements() const override { return elements; } \ + size_t getSize() const override { \ + return BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_FOR_EACH(GET_KEY, "", enum_elements)); \ + } +#define VALUE_CHECK(type) \ + bool isValid() const override { \ + for (size_t i = 0; i < sizeof(elements) / sizeof(elements[0]); i++) { \ + if (value == elements[i]) { \ + return true; \ + } \ + } \ + return false; \ + } + +#ifdef FSFW_INTROSPECTION +#define CREATE_DESCRIPTION_ARRAY(elements) \ + /*was static constexpr, but clang won't compile that*/ \ + const char \ + *descriptions[BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_FOR_EACH(GET_DESCRIPTION, "", elements))] = { \ + BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(GET_DESCRIPTION, "", elements))}; \ + const char *const *getDescriptions() const override { return descriptions; } +#define GET_INDEX() \ + size_t getIndex(int64_t value) const override { \ + for (size_t i = 0; i < sizeof(elements) / sizeof(elements[0]); i++) { \ + if (value == elements[i]) { \ + return i; \ + } \ + } \ + return -1; \ + } +#define GET_DESCRIPTION_FUNC() \ + const char *getDescription() const override { \ + if (getIndex(value) == static_cast(-1)) { \ + return nullptr; \ + } else { \ + return descriptions[getIndex(value)]; \ + } \ + } +#else +#define GET_INDEX() +#define CREATE_DESCRIPTION_ARRAY(elements) +#define GET_DESCRIPTION_FUNC() +#endif + +#endif \ No newline at end of file diff --git a/src/fsfw/introspection/EnumIF.h b/src/fsfw/introspection/EnumIF.h new file mode 100644 index 00000000..64040415 --- /dev/null +++ b/src/fsfw/introspection/EnumIF.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +class EnumIF { + public: + virtual int64_t getValue() const = 0; + virtual bool isValid() const = 0; + virtual size_t getSize() const = 0; + virtual size_t getIndex(int64_t value) const = 0; + virtual const int64_t *getElements() const = 0; + virtual const char *const *getDescriptions() const = 0; + virtual const char *getDescription() const = 0; +}; \ No newline at end of file diff --git a/src/fsfw/introspection/ParameterTypeSelector.cpp b/src/fsfw/introspection/ParameterTypeSelector.cpp new file mode 100644 index 00000000..f678271e --- /dev/null +++ b/src/fsfw/introspection/ParameterTypeSelector.cpp @@ -0,0 +1,56 @@ +#include "ParameterTypeSelector.h" + +#include + +#include "Types.h" + +#ifdef FSFW_INTROSPECTION + +template +Types::ParameterType ParameterTypeSelector::getType() { + return Types::UNSUPPORTED; + } + +template <> +Types::ParameterType ParameterTypeSelector::getType() { + return Types::SIGNED; +} +template <> +Types::ParameterType ParameterTypeSelector::getType() { + return Types::SIGNED; +} + +template <> +Types::ParameterType ParameterTypeSelector::getType() { + return Types::SIGNED; +} +template <> +Types::ParameterType ParameterTypeSelector::getType() { + return Types::SIGNED; +} +template <> +Types::ParameterType ParameterTypeSelector::getType() { + return Types::SIGNED; +} +template <> +Types::ParameterType ParameterTypeSelector::getType() { + return Types::SIGNED; +} +// template <> +// Types::ParameterType ParameterTypeSelector::getType() { +// return Types::UNSIGNED; +// } +template <> +Types::ParameterType ParameterTypeSelector::getType() { + return Types::SIGNED; +} +template <> +Types::ParameterType ParameterTypeSelector::getType() { + return Types::FLOATING; +} +template <> +Types::ParameterType ParameterTypeSelector::getType() { + return Types::FLOATING; +} + +#endif \ No newline at end of file diff --git a/src/fsfw/introspection/ParameterTypeSelector.h b/src/fsfw/introspection/ParameterTypeSelector.h new file mode 100644 index 00000000..934cd2c3 --- /dev/null +++ b/src/fsfw/introspection/ParameterTypeSelector.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Types.h" + +#ifdef FSFW_INTROSPECTION + +class ParameterTypeSelector { + public: + template + static Types::ParameterType getType(); +}; + +#endif \ No newline at end of file diff --git a/src/fsfw/introspection/Types.h b/src/fsfw/introspection/Types.h new file mode 100644 index 00000000..0fa9640d --- /dev/null +++ b/src/fsfw/introspection/Types.h @@ -0,0 +1,8 @@ +#pragma once + +//maybe call them MIB types as these are the ones exposed to the MIB? +// Note: some DBs (Postgress, Mongo) only support signed 64bit integers. To have a common denominator, all integers are int64_t. +// As such, ther is no unsigned Type, as there can not be a uint64_t and uint32_t completely fits into int64_t +namespace Types { +enum ParameterType { SIGNED, FLOATING, ENUM, UNSUPPORTED }; +} // namespace Types \ No newline at end of file diff --git a/src/fsfw/introspection/TypesHelper.h b/src/fsfw/introspection/TypesHelper.h new file mode 100644 index 00000000..30ef3635 --- /dev/null +++ b/src/fsfw/introspection/TypesHelper.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include + +#include "Enum.h" +#include "Types.h" +#include "ParameterTypeSelector.h" + +template +class enumHelper; + +template <> +class enumHelper { + public: + static bool isValid(EnumIF *anEnum) { return anEnum->isValid(); } + +#ifdef FSFW_INTROSPECTION + template + static Types::ParameterType getType() { + return Types::ENUM; + } + + template + static T getMin() { + return 0; + } + + template + static T getMax() { + return 0; + } + + static std::vector getEnumValues() { return std::vector(); } + + static std::vector getEnumValues(EnumIF *anEnum) { + std::vector vector; + for (size_t i = 0; i < anEnum->getSize(); i++) { + vector.push_back(anEnum->getElements()[i]); + } + return vector; + } + + static const char *const *getEnumDescriptions(EnumIF *anEnum) { + return anEnum->getDescriptions(); + } +#endif +}; + +template <> +class enumHelper { + public: + static bool isValid(void *) { return true; } + +#ifdef FSFW_INTROSPECTION + template + static Types::ParameterType getType() { + return ParameterTypeSelector::getType(); + } + + template + static T getMin() { + return std::numeric_limits::lowest(); + } + template + static T getMax() { + return std::numeric_limits::max(); + } + + static std::vector getEnumValues(void *) { return std::vector(); } + + static const char *const *getEnumDescriptions(void *) { return nullptr; } +#endif +}; \ No newline at end of file