2018-07-12 16:29:32 +02:00
# ifndef TEMPERATURESENSOR_H_
# define TEMPERATURESENSOR_H_
2021-04-07 22:12:01 +02:00
# include "tcsDefinitions.h"
# include "AbstractTemperatureSensor.h"
# include "../datapoollocal/LocalPoolDataSetBase.h"
# include "../datapoollocal/LocalPoolVariable.h"
2020-08-13 20:53:35 +02:00
# include "../monitoring/LimitMonitor.h"
2018-07-12 16:29:32 +02:00
2021-04-07 22:12:01 +02:00
2020-12-03 18:32:32 +01:00
/**
* @ 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 < typename inputType , typename limitType = inputType >
2018-07-12 16:29:32 +02:00
class TemperatureSensor : public AbstractTemperatureSensor {
public :
2020-12-03 18:32:32 +01:00
/**
* 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 .
*/
2018-07-12 16:29:32 +02:00
struct Parameters {
float a ;
float b ;
float c ;
2020-12-03 18:32:32 +01:00
limitType lowerLimit ;
limitType upperLimit ;
float maxGradient ;
2018-07-12 16:29:32 +02:00
} ;
2020-12-03 18:32:32 +01:00
/**
* Forward declaration for explicit instantiation of used parameters .
*/
2018-07-12 16:29:32 +02:00
struct UsedParameters {
UsedParameters ( Parameters parameters ) :
2020-12-03 18:32:32 +01:00
a ( parameters . a ) , b ( parameters . b ) , c ( parameters . c ) ,
gradient ( parameters . maxGradient ) { }
2018-07-12 16:29:32 +02:00
float a ;
float b ;
float c ;
float gradient ;
} ;
2020-12-03 18:32:32 +01:00
/**
* Instantiate Temperature Sensor Object .
2021-04-07 22:12:01 +02:00
* @ 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 ( )
2020-12-03 18:32:32 +01:00
* @ param thermalModule respective thermal module , if it has one
*/
TemperatureSensor ( object_id_t setObjectid ,
2021-04-07 22:12:01 +02:00
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 ) :
2020-12-03 18:32:32 +01:00
AbstractTemperatureSensor ( setObjectid , thermalModule ) , parameters ( parameters ) ,
2021-04-07 22:12:01 +02:00
inputValue ( inputValue ) , poolVariable ( inputVariable ) ,
outputTemperature ( variableGpid , outputSet , PoolVariableIF : : VAR_WRITE ) ,
sensorMonitor ( setObjectid , DOMAIN_ID_SENSOR , poolVariable ,
2020-12-03 18:32:32 +01:00
DEFAULT_CONFIRMATION_COUNT , parameters . lowerLimit , parameters . upperLimit ,
TEMP_SENSOR_LOW , TEMP_SENSOR_HIGH ) ,
2021-04-07 22:12:01 +02:00
oldTemperature ( 20 ) , uptimeOfOldTemperature ( { thermal : : INVALID_TEMPERATURE , 0 } ) {
2020-12-03 18:32:32 +01:00
}
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 ;
}
2018-07-12 16:29:32 +02:00
private :
void setInvalid ( ) {
2021-04-07 22:12:01 +02:00
outputTemperature = thermal : : INVALID_TEMPERATURE ;
2018-07-12 16:29:32 +02:00
outputTemperature . setValid ( false ) ;
uptimeOfOldTemperature . tv_sec = INVALID_UPTIME ;
sensorMonitor . setToInvalid ( ) ;
}
protected :
static const int32_t INVALID_UPTIME = 0 ;
UsedParameters parameters ;
2021-04-07 22:12:01 +02:00
inputType * inputValue ;
2018-07-12 16:29:32 +02:00
2021-04-07 22:12:01 +02:00
PoolVariableIF * poolVariable ;
2018-07-12 16:29:32 +02:00
2021-04-07 22:12:01 +02:00
lp_var_t < float > outputTemperature ;
2018-07-12 16:29:32 +02:00
2020-12-03 18:32:32 +01:00
LimitMonitor < limitType > sensorMonitor ;
2018-07-12 16:29:32 +02:00
float oldTemperature ;
timeval uptimeOfOldTemperature ;
void doChildOperation ( ) {
2021-04-07 22:12:01 +02:00
if ( ( not poolVariable - > isValid ( ) ) or
( not healthHelper . healthTable - > isHealthy ( getObjectId ( ) ) ) ) {
2018-07-12 16:29:32 +02:00
setInvalid ( ) ;
return ;
}
2020-12-03 18:32:32 +01:00
outputTemperature = calculateOutputTemperature ( * inputValue ) ;
2018-07-12 16:29:32 +02:00
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.
2020-12-03 18:32:32 +01:00
//But this would require storing the maxGradient in DP and quite some overhead.
2018-07-12 16:29:32 +02:00
//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
}
}
2021-04-07 22:12:01 +02:00
//Check is done against raw limits. SHOULDDO: Why? Using C would be more easy to handle.
2020-12-03 18:32:32 +01:00
sensorMonitor . doCheck ( outputTemperature . value ) ;
2018-07-12 16:29:32 +02:00
if ( sensorMonitor . isOutOfLimits ( ) ) {
uptimeOfOldTemperature . tv_sec = INVALID_UPTIME ;
outputTemperature . setValid ( PoolVariableIF : : INVALID ) ;
2021-04-07 22:12:01 +02:00
outputTemperature = thermal : : INVALID_TEMPERATURE ;
2018-07-12 16:29:32 +02:00
} else {
oldTemperature = outputTemperature ;
uptimeOfOldTemperature = uptime ;
}
}
public :
float getTemperature ( ) {
return outputTemperature ;
}
bool isValid ( ) {
return outputTemperature . isValid ( ) ;
}
2020-12-03 18:32:32 +01:00
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 ;
2021-01-29 22:45:53 +01:00
virtual ReturnValue_t getParameter ( uint8_t domainId , uint8_t uniqueId ,
2018-07-12 16:29:32 +02:00
ParameterWrapper * parameterWrapper ,
const ParameterWrapper * newValues , uint16_t startAtIndex ) {
2021-01-29 22:45:53 +01:00
ReturnValue_t result = sensorMonitor . getParameter ( domainId , uniqueId ,
2018-07-12 16:29:32 +02:00
parameterWrapper , newValues , startAtIndex ) ;
if ( result ! = INVALID_DOMAIN_ID ) {
return result ;
}
if ( domainId ! = this - > DOMAIN_ID_BASE ) {
return INVALID_DOMAIN_ID ;
}
2021-01-29 22:45:53 +01:00
switch ( uniqueId ) {
2018-07-12 16:29:32 +02:00
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 :
2020-12-03 18:32:32 +01:00
return INVALID_IDENTIFIER_ID ;
2018-07-12 16:29:32 +02:00
}
return HasReturnvaluesIF : : RETURN_OK ;
}
virtual void resetOldState ( ) {
sensorMonitor . setToUnchecked ( ) ;
}
} ;
# endif /* TEMPERATURESENSOR_H_ */