#ifndef TEMPERATURESENSOR_H_ #define TEMPERATURESENSOR_H_ #include "tcsDefinitions.h" #include "AbstractTemperatureSensor.h" #include "../datapoollocal/LocalPoolDataSetBase.h" #include "../datapoollocal/LocalPoolVariable.h" #include "../monitoring/LimitMonitor.h" /** * @brief This building block handles non-linear value conversion and * range checks for analog temperature sensors. * @details This class can be used to perform all necessary tasks for temperature sensors. * A sensor can be instantiated by calling the constructor. * The temperature is calculated from an input value with * the calculateOutputTemperature() function. Range checking and * limit monitoring is performed automatically. * The inputType specifies the type of the raw input while the * limitType specifies the type of the upper and lower limit to check against. * @ingroup thermal */ template class TemperatureSensor: public AbstractTemperatureSensor { public: /** * This structure contains parameters required for range checking * and the conversion from the input value to the output temperature. * a, b and c can be any parameters required to calculate the output * temperature from the input value, depending on the formula used. * * The parameters a,b and c are used in the calculateOutputTemperature() call. * * The lower and upper limits can be specified in any type, for example float for C values * or any other type for raw values. */ struct Parameters { float a; float b; float c; limitType lowerLimit; limitType upperLimit; float maxGradient; }; /** * Forward declaration for explicit instantiation of used parameters. */ struct UsedParameters { UsedParameters(Parameters parameters) : a(parameters.a), b(parameters.b), c(parameters.c), gradient(parameters.maxGradient) {} float a; float b; float c; float gradient; }; /** * Instantiate Temperature Sensor Object. * @param setObjectid objectId of the sensor object * @param inputValue Pointer to input value which is converted to a temperature * @param variableGpid Global Pool ID of the output value * @param inputVariable Input variable handle * @param vectorIndex Vector Index for the sensor monitor * @param parameters Calculation parameters, temperature limits, gradient limit * @param outputSet Output dataset for the output temperature to fetch it with read() * @param thermalModule respective thermal module, if it has one */ TemperatureSensor(object_id_t setObjectid, inputType *inputValue, gp_id_t variableGpid, PoolVariableIF* inputVariable, uint8_t vectorIndex, Parameters parameters = {0, 0, 0, 0, 0, 0}, LocalPoolDataSetBase *outputSet = NULL, ThermalModuleIF *thermalModule = NULL) : AbstractTemperatureSensor(setObjectid, thermalModule), parameters(parameters), inputValue(inputValue), poolVariable(inputVariable), outputTemperature(variableGpid, outputSet, PoolVariableIF::VAR_WRITE), sensorMonitor(setObjectid, DOMAIN_ID_SENSOR, poolVariable, DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, parameters.upperLimit, TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), oldTemperature(20), uptimeOfOldTemperature({ thermal::INVALID_TEMPERATURE, 0 }) { } protected: /** * This formula is used to calculate the temperature from an input value * with an arbitrary type. * A default implementation is provided but can be replaced depending * on the required calculation. * @param inputTemperature * @return */ virtual float calculateOutputTemperature(inputType inputValue) { return parameters.a * inputValue * inputValue + parameters.b * inputValue + parameters.c; } private: void setInvalid() { outputTemperature = thermal::INVALID_TEMPERATURE; outputTemperature.setValid(false); uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; sensorMonitor.setToInvalid(); } protected: static const int32_t INVALID_UPTIME = 0; UsedParameters parameters; inputType* inputValue; PoolVariableIF* poolVariable; lp_var_t outputTemperature; LimitMonitor sensorMonitor; float oldTemperature; timeval uptimeOfOldTemperature; void doChildOperation() { if ((not poolVariable->isValid()) or (not healthHelper.healthTable->isHealthy(getObjectId()))) { setInvalid(); return; } outputTemperature = calculateOutputTemperature(*inputValue); outputTemperature.setValid(PoolVariableIF::VALID); timeval uptime; Clock::getUptime(&uptime); if (uptimeOfOldTemperature.tv_sec != INVALID_UPTIME) { //In theory, we could use an AbsValueMonitor to monitor the gradient. //But this would require storing the maxGradient in DP and quite some overhead. //The concept of delta limits is a bit strange anyway. float deltaTime; float deltaTemp; deltaTime = (uptime.tv_sec + uptime.tv_usec / 1000000.) - (uptimeOfOldTemperature.tv_sec + uptimeOfOldTemperature.tv_usec / 1000000.); deltaTemp = oldTemperature - outputTemperature; if (deltaTemp < 0) { deltaTemp = -deltaTemp; } if (parameters.gradient < deltaTemp / deltaTime) { triggerEvent(TEMP_SENSOR_GRADIENT); //Don't set invalid, as we did not recognize it as invalid with full authority, let FDIR handle it } } //Check is done against raw limits. SHOULDDO: Why? Using C would be more easy to handle. sensorMonitor.doCheck(outputTemperature.value); if (sensorMonitor.isOutOfLimits()) { uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; outputTemperature.setValid(PoolVariableIF::INVALID); outputTemperature = thermal::INVALID_TEMPERATURE; } else { oldTemperature = outputTemperature; uptimeOfOldTemperature = uptime; } } public: float getTemperature() { return outputTemperature; } bool isValid() { return outputTemperature.isValid(); } static const uint16_t ADDRESS_A = 0; static const uint16_t ADDRESS_B = 1; static const uint16_t ADDRESS_C = 2; static const uint16_t ADDRESS_GRADIENT = 3; static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.) static const uint8_t DOMAIN_ID_SENSOR = 1; virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex) { ReturnValue_t result = sensorMonitor.getParameter(domainId, uniqueId, parameterWrapper, newValues, startAtIndex); if (result != INVALID_DOMAIN_ID) { return result; } if (domainId != this->DOMAIN_ID_BASE) { return INVALID_DOMAIN_ID; } switch (uniqueId) { case ADDRESS_A: parameterWrapper->set(parameters.a); break; case ADDRESS_B: parameterWrapper->set(parameters.b); break; case ADDRESS_C: parameterWrapper->set(parameters.c); break; case ADDRESS_GRADIENT: parameterWrapper->set(parameters.gradient); break; default: return INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } virtual void resetOldState() { sensorMonitor.setToUnchecked(); } }; #endif /* TEMPERATURESENSOR_H_ */