#ifndef ECSS_SERVICES_PARAMETER_HPP #define ECSS_SERVICES_PARAMETER_HPP #include "etl/String.hpp" #include "ECSS_Definitions.hpp" #include <iostream> /** * Implementation of a Parameter field, as specified in ECSS-E-ST-70-41C. * Fully compliant with the standard's requirements. * * @author Grigoris Pavlakis <grigpavl@ece.auth.gr> */ /** * Useful type definitions * * @typedef ParamId: the unique ID of a parameter, used for searching */ typedef uint16_t ParamId; /** * Parameter class - Breakdown of fields * * @private ptr: Pointer of the function that will update the parameter * @private currentValue: The current (as in last good) value of the parameter * * * * Methods: * @public Parameter(uint32_t initialValue = 0, UpdatePtr newPtr = nullptr): * Create a new Parameter object with initialValue as its starting value and newPtr * as its update function pointer. Arguments initialValue and newPtr are optional, and have default values of * 0 and nullptr respectively. * * @public setCurrentValue(): Changes the current value of the parameter * @public getCurrentValue(): Gets the current value of the parameter */ // class DataField { // protected: // uint8_t sizeInBytes; // void* dataFieldAddress; // // possible race: setCurrentValue may be ran when dataFieldAddress is uninitialized // public: // template <typename DataType> // void setCurrentValue(DataType newValue) { // DataType* typedDataFieldAddress = reinterpret_cast<DataType*>(dataFieldAddress); // *typedDataFieldAddress = newValue; // } // }; /** * Highly likely that valuePtr is redundant! Then, ParameterBase could only contain * virtual methods and act as a mere interface, moving all specific functionality to * the Parameter class and ensuring type safety. */ class ParameterBase { protected: uint8_t sizeInBytes; void* valuePtr = nullptr; public: virtual String<ECSS_ST_20_MAX_STRING_LENGTH> getValueAsString() = 0; template <typename ValueType> void setCurrentValue(ValueType newVal) { if (valuePtr == nullptr) { std::cout << "THIS IS NULL!" << std::endl; } *reinterpret_cast<ValueType*>(valuePtr) = newVal; } }; /** * MILLION DOLLAR QUESTIONS: * setCurrentValue is templated. Since Parameter (a template class) inherits ParameterBase * (a class containing a template member), does a specialization of Parameter also specialize * setCurrentValue? If not, we have a problem, since Parameter won't necessarily specialize * setCurrentValue with the correct type => our setter is *not* typesafe. */ template <typename ValueType> class Parameter : public ParameterBase { void (* ptr)(ValueType*); ValueType currentValue; public: Parameter(ValueType initialValue = 0, void(* newPtr)(ValueType*) = nullptr) { ptr = newPtr; sizeInBytes = sizeof(initialValue); // previously null valuePtr now points to the currentValue field valuePtr = static_cast<void*>(¤tValue); if (ptr != nullptr) { (*ptr)(¤tValue); // call the update function for the initial value } else { currentValue = initialValue; } } String<ECSS_ST_20_MAX_STRING_LENGTH> getValueAsString() override { String<ECSS_ST_20_MAX_STRING_LENGTH> contents(reinterpret_cast<uint8_t*>(¤tValue), sizeInBytes); return contents; } }; #endif //ECSS_SERVICES_PARAMETER_HPP