Files
ISTTOK/epics/css/sys-mng-opi/CSS/MARTe/Interfaces/EPICSLib/exScalarPV.cpp
2019-10-21 16:02:55 +01:00

270 lines
7.7 KiB
C++

/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE-EPICS that is included with this distribution.
\*************************************************************************/
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#include "alarm.h"
#include "exServer.h"
#include "gddApps.h"
#define myPI 3.14159265358979323846
//
// SUN C++ does not have RAND_MAX yet
//
#if !defined(RAND_MAX)
//
// Apparently SUN C++ is using the SYSV version of rand
//
#if 0
#define RAND_MAX INT_MAX
#else
#define RAND_MAX SHRT_MAX
#endif
#endif
//
// exScalarPV::scan
//
void exScalarPV::scan()
{
caStatus status;
double radians;
smartGDDPointer pDD;
float newValue;
float limit;
int gddStatus;
//
// update current time (so we are not required to do
// this every time that we write the PV which impacts
// throughput under sunos4 because gettimeofday() is
// slow)
//
// this->currentTime = epicsTime::getCurrent ();
pDD = new gddScalar ( gddAppType_value, aitEnumFloat64 );
if ( ! pDD.valid () ) {
return;
}
//
// smart pointer class manages reference count after this point
//
gddStatus = pDD->unreference ();
assert ( ! gddStatus );
// consider every data type
/* if ( this->info.buffer ) { // code by Anto
switch ( (this->info.btd).Type() ) {
case BTDTInteger:
pDD->put( (int)*( (int32 *)this->info.buffer ) );
break;
case BTDTFloat:
default:
pDD->put( (float)*( (float *)this->info.buffer ) );
break;
}
// switch in base a data type :-)
}
else { // original code */
radians = ( rand () * 2.0 * myPI ) / RAND_MAX;
if ( this->pValue.valid () ) {
this->pValue->getConvert(newValue);
}
else {
newValue = 0.0f;
}
newValue += (float) ( sin (radians) / 10.0 );
limit = (float) this->info.getHopr ();
newValue = tsMin ( newValue, limit );
limit = (float) this->info.getLopr ();
newValue = tsMax ( newValue, limit );
*pDD = newValue;
//}
aitTimeStamp gddts ( this->currentTime ); // TODO change it!!!!
pDD->setTimeStamp ( & gddts );
// antonio code
if ( (this->info.getScanPeriod() > 0.0) ) {
status = this->update ( *pDD, true, false );
if (status!=S_casApp_success) {
errMessage ( status, "scalar scan update failed\n" );
}
}
// delete &((gddScalar ) *pDD);
// delete &((gdd) *pDD);
}
#define DBE_VALUE (1<<0)
#define DBE_ARCHIVE (1<<1)
#define DBE_LOG DBE_ARCHIVE
#define DBE_ALARM (1<<2)
#define DBE_PROPERTY (1<<3)
//
// exScalarPV::updateValue ()
//
// NOTES:
// 1) This should have a test which verifies that the
// incoming value in all of its various data types can
// be translated into a real number?
// 2) We prefer to unreference the old PV value here and
// reference the incomming value because this will
// result in each value change events retaining an
// independent value on the event queue.
//
caStatus exScalarPV::updateValue ( const gdd & valueIn )
{
// muoviamo il check per il data type???
// mi sa di si... ?!? pero ce da fare lo stesso anche per gli scalars..
//
// Really no need to perform this check since the
// server lib verifies that all requests are in range
//
if ( ! valueIn.isScalar() ) {
return S_casApp_outOfBounds;
}
if ( ! pValue.valid () ) {
this->pValue = new gddScalar ( gddAppType_value, this->info.getType () );
if ( ! pValue.valid () ) {
return S_casApp_noMemory;
}
}
this->pValue->put ( & valueIn );
// TODO for a full implementation see aiRecord.c checkAlarms
double value;
this->pValue->get(value);
/* Antonio code
if ( value < this->info.getLolo() ) {
this->pValue->setStatSevr(LOLO_ALARM, MAJOR_ALARM);
}
else if ( value < this->info.getLow() ) {
this->pValue->setStatSevr(LOW_ALARM, MINOR_ALARM);
}
if ( value > this->info.getHihi() ) {
this->pValue->setStatSevr(HIHI_ALARM, MAJOR_ALARM);
}
else if ( value > this->info.getHigh() ) {
this->pValue->setStatSevr(HIGH_ALARM, MINOR_ALARM);
}
*/
// original code from the aiRecord checkAlarms -----------------------------------------------------------
/* non considered for now the following lines
if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
return;
}
*/
#define recGblSetSevr(NSTA, NSEV) ((nsev<(NSEV)) ? (nsta=(NSTA),nsev=(NSEV),true) : false)
aitInt16 nsev, nsta;
aiRecord_checkAlarms:
double hyst, lalm;
double alev;
epicsEnum16 asev;
this->pValue->getStatSevr(nsta, nsev); // fetch previous values
hyst = this->info.hyst; //hyst = prec->hyst;
lalm = this->info.lalm; //lalm = prec->lalm;
/* alarm condition hihi */
asev = this->info.hhsv; //asev = prec->hhsv;
alev = this->info.getHihi(); //alev = this->info.hihi; //prec->hihi;
if (asev && (value >= alev || ((lalm == alev) && (value >= alev - hyst)))) {
if ( recGblSetSevr(HIHI_ALARM, asev) )
this->info.lalm = alev;
goto recGbl_recGblResetAlarms;
}
/* alarm condition lolo */
asev = this->info.llsv; //asev = prec->llsv;
alev = this->info.getLolo(); //alev = this->info.lolo; //alev = prec->lolo;
if (asev && (value <= alev || ((lalm == alev) && (value <= alev + hyst)))) {
if ( recGblSetSevr(LOLO_ALARM, asev) )
this->info.lalm = alev;
goto recGbl_recGblResetAlarms;
}
/* alarm condition high */
asev = this->info.hsv; //asev = prec->hsv;
alev = this->info.getHigh(); // alev = this->info.high; // alev = prec->high;
if (asev && (value >= alev || ((lalm == alev) && (value >= alev - hyst)))) {
if ( recGblSetSevr(HIGH_ALARM, asev) )
this->info.lalm = alev;
goto recGbl_recGblResetAlarms;
}
/* alarm condition low */
asev = this->info.lsv; //asev = prec->lsv;
alev = this->info.getLow();//alev = this->info.low; // alev = prec->low;
if (asev && (value <= alev || ((lalm == alev) && (value <= alev + hyst)))) {
if ( recGblSetSevr(LOW_ALARM, asev) )
this->info.lalm = alev;
goto recGbl_recGblResetAlarms;
}
/* we get here only if val is out of alarm by at least hyst */
this->info.lalm = value;
//recGblResetAlarms from recGbl.c
recGbl_recGblResetAlarms:
epicsEnum16 stat_mask = 0;
//epicsEnum16 val_mask = 0;
if (this->pValue->getSevr() != nsev ) //if (prev_sevr != new_sev)
{
this->pValue->setSevr(nsev);
stat_mask = DBE_ALARM;
//db_post_events(pdbc, &pdbc->sevr, DBE_VALUE); // monitor the change of the PV .SEVR
}
if (this->pValue->getStat() != nsta )
{
this->pValue->setStat(nsta);
stat_mask |= DBE_VALUE;
}
if (stat_mask)
{
//db_post_events(pdbc, &pdbc->stat, stat_mask); // monitor the change of the PV .STAT
//val_mask = DBE_ALARM;
// questo significa che se ackt è a zero oppure nsev >= acks allora aggiorna acks
//previous code if (!pdbc->ackt || new_sevr >= pdbc->acks) {
if (!this->info.ackt || nsev >= this->info.acks) {
this->info.acks = (aitEnum) nsev;
//db_post_events(pdbc, &pdbc->acks, DBE_VALUE); //monitor the change of the PV .ACKS
}
}
// e fino a qui mi cambia stat e sevr e acks -----------------------------------------------------------
return S_casApp_success;
}