EPICS Home

Experimental Physics and Industrial Control System


 
1994  1995  1996  1997  1998  1999  <20002001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 1994  1995  1996  1997  1998  1999  <20002001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Monitors for the STAT field
From: Benjamin Franksen <[email protected]>
To: EPICS Techtalk <[email protected]>
Date: Mon, 17 Jan 2000 20:36:42 +0100
Hello,

I have yet another suggestion for the iocCore.

In recGblResetAlarms, a monitor for the STAT field is fired only when
STAT changes. It would be nice if a change of the SEVR also triggered a
STAT event, so monitoring STAT would give me the correct SEVR too.

This could be done by changing recGblResetAlarms in a way similar to the
following. [Ralph: Could you make this change in our local version for
testing? I attached the new recGbl.c.]

recGbl.c, line 266, old:

    if (stat!=nsta) {
	mask = DBE_ALARM;
	db_post_events(pdbc,&pdbc->stat,DBE_VALUE);
    }
    if (sevr!=nsev) {
	mask = DBE_ALARM;
	db_post_events(pdbc,&pdbc->sevr,DBE_VALUE);
    }

new:
    [add local variable: unsigned short stat_mask=0]

    if (sevr!=nsev) {
	stat_mask = mask = DBE_ALARM;
	db_post_events(pdbc,&pdbc->sevr,DBE_VALUE);
    }
    if(stat!=nsta) {
	stat_mask |= DBE_VALUE;
	mask = DBE_ALARM;
    }
    if(stat_mask)
	db_post_events(pdbc,&pdbc->stat,stat_mask);

One of the reasons, why I stumbled over this, is that CA allows only 16
states for a menu field, but menuAlarmStat has some more entries. Since
MEDM uses the native DBR type for monitors, if you display the STAT of a
record with the MEDM, you will find that states above 15 (such as UDF or
DISABLE) are not correctly displayed (empty string).

[Jeff: Is this already on the wish-list for the next CA version?]

In the meantime, I thought the solution could be a soft stringin record
with INP link pointing to the record's STAT and having CPP and MS
property. This works indeed because database access - in contrast to
MEDM - then issues a DBR_STRING request.

But I like to display the STAT field in my MEDM panels with color mode
alarm. This doesn't work because of the above problem, since currently
only a change to STAT's *value* will send an event. I get the correct
severity only if I use a forward link to the stringin (i.e. process more
often than necessary).

Ben
-- 
The Notorious Neb Nesknarf
/* recGbl.c - Global record processing routines */
/* base/src/db $Id: recGbl.c,v 1.44 1998/01/22 14:48:35 mrk Exp $ */

/*
 *      Author:          Marty Kraimer
 *      Date:            11-7-90
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1991, the Regents of the University of California,
 *      and the University of Chicago Board of Governors.
 *
 *      This software was produced under  U.S. Government contracts:
 *      (W-7405-ENG-36) at the Los Alamos National Laboratory,
 *      and (W-31-109-ENG-38) at Argonne National Laboratory.
 *
 *      Initial development by:
 *              The Controls and Automation Group (AT-8)
 *              Ground Test Accelerator
 *              Accelerator Technology Division
 *              Los Alamos National Laboratory
 *
 *      Co-developed with
 *              The Controls and Computing Group
 *              Accelerator Systems Division
 *              Advanced Photon Source
 *              Argonne National Laboratory
 *
 * Modification Log:
 * -----------------
 * .01  11-16-91        jba     Added recGblGetGraphicDouble, recGblGetControlDouble
 * .02  02-28-92        jba     ANSI C changes
 * .03	05-19-92	mrk	Changes for internal database structure changes
 * .04  07-16-92        jba     changes made to remove compile warning msgs
 * .05  07-21-92        jba     Added recGblGetAlarmDouble
 * .06  08-07-92        jba     Added recGblGetLinkValue, recGblPutLinkValue
 * .07  08-07-92        jba     Added RTN_SUCCESS check for status
 * .08  09-15-92        jba     changed error parm in recGblRecordError calls
 * .09  09-17-92        jba     ANSI C changes
 * .10  01-27-93        jba     set pact to true during calls to dbPutLink
 * .11  03-21-94        mcn     Added fast link routines
 */

#include	<vxWorks.h>
#include	<limits.h>
#include	<types.h>
#include	<stdioLib.h>
#include	<strLib.h>

#include	"dbDefs.h"
#include	"epicsPrint.h"
#include	"dbBase.h"
#include	"dbEvent.h"
#include	"dbAccess.h"
#include	"dbConvert.h"
#include	"dbScan.h"
#include	"devSup.h"
#include	"recGbl.h"
#include	"dbCommon.h"
#include	"drvTS.h"


/* local routines */
static void getMaxRangeValues();



void recGblDbaddrError(long status,struct dbAddr *paddr,char *pcaller_name)
{
	char		buffer[200];
	struct dbCommon *precord;
	dbFldDes	*pdbFldDes=(dbFldDes *)(paddr->pfldDes);

	buffer[0]=0;
	if(paddr) { /* print process variable name */
		precord=(struct dbCommon *)(paddr->precord);
		strcat(buffer,"PV: ");
		strcat(buffer,precord->name);
		strcat(buffer,".");
		strcat(buffer,pdbFldDes->name);
		strcat(buffer," ");
	}
	if(pcaller_name) {
		strcat(buffer,"error detected in routine: ");
		strcat(buffer,pcaller_name);
	}
	errMessage(status,buffer);
	return;
}

void recGblRecordError(long status,void *pdbc,char *pcaller_name)
{
	struct dbCommon	*precord = pdbc;
	char		buffer[200];

	buffer[0]=0;
	if(precord) { /* print process variable name */
		strcat(buffer,"PV: ");
		strcat(buffer,precord->name);
		strcat(buffer,"  ");
	}
	if(pcaller_name) {
		strcat(buffer,pcaller_name);
	}
	errMessage(status,buffer);
	return;
}

void recGblRecSupError(long status,struct dbAddr *paddr,char *pcaller_name,
	char *psupport_name)
{
	char 		buffer[200];
	struct dbCommon *precord;
	dbFldDes	*pdbFldDes = 0;
	dbRecordType	*pdbRecordType = 0;

	if(paddr) pdbFldDes=(dbFldDes *)(paddr->pfldDes);
	if(pdbFldDes) pdbRecordType = pdbFldDes->pdbRecordType;
	buffer[0]=0;
	strcat(buffer,"Record Support Routine (");
	if(psupport_name)
		strcat(buffer,psupport_name);
	else
		strcat(buffer,"Unknown");
	strcat(buffer,") not available.\n");
	if(pdbRecordType) {
	    strcat(buffer,"Record Type is ");
	    strcat(buffer,pdbRecordType->name);
	    if(paddr) { /* print process variable name */
		precord=(struct dbCommon *)(paddr->precord);
		strcat(buffer,", PV is ");
		strcat(buffer,precord->name);
		strcat(buffer,".");
		strcat(buffer,pdbFldDes->name);
		strcat(buffer,"\n");
	    }
	}
	if(pcaller_name) {
		strcat(buffer,"error detected in routine: ");
		strcat(buffer,pcaller_name);
	}
	errMessage(status,buffer);
	return;
}

void recGblGetPrec(struct dbAddr *paddr,long *precision)
{
    dbFldDes               *pdbFldDes=(dbFldDes *)(paddr->pfldDes);

    switch(pdbFldDes->field_type){
    case(DBF_SHORT):
         *precision = 0;
         break;
    case(DBF_USHORT):
         *precision = 0;
         break;
    case(DBF_LONG):
         *precision = 0;
         break;
    case(DBF_ULONG):
         *precision = 0;
         break;
    case(DBF_FLOAT):
    case(DBF_DOUBLE):
	 if(*precision<0 || *precision>15) *precision=15;
         break;
    default:
         break;
    }
    return;
}

void recGblGetGraphicDouble(struct dbAddr *paddr,struct dbr_grDouble *pgd)
{
    dbFldDes               *pdbFldDes=(dbFldDes *)(paddr->pfldDes);

    getMaxRangeValues(pdbFldDes->field_type,&pgd->upper_disp_limit,
	&pgd->lower_disp_limit);

    return;
}

void recGblGetAlarmDouble(struct dbAddr *paddr,struct dbr_alDouble *pad)
{
    pad->upper_alarm_limit = 0;
    pad->upper_warning_limit = 0;
    pad->lower_warning_limit = 0;
    pad->lower_alarm_limit = 0;

    return;
}

void recGblGetControlDouble(struct dbAddr *paddr,struct dbr_ctrlDouble *pcd)
{
    dbFldDes               *pdbFldDes=(dbFldDes *)(paddr->pfldDes);

    getMaxRangeValues(pdbFldDes->field_type,&pcd->upper_ctrl_limit,
	&pcd->lower_ctrl_limit);

    return;
}

int  recGblInitConstantLink(struct link *plink,short dbftype,void *pdest)
{
    if(plink->type != CONSTANT) return(FALSE);
    if(!plink->value.constantStr) return(FALSE);
    switch(dbftype) {
    case DBF_STRING:
	strcpy((char *)pdest,plink->value.constantStr);
	break;
    case DBF_CHAR : {
	short	value;
	char	*pvalue = (char *)pdest;

	sscanf(plink->value.constantStr,"%hd",&value);
	*pvalue = value;
	}
	break;
    case DBF_UCHAR : {
	unsigned short	value;
	unsigned char	*pvalue = (unsigned char *)pdest;

	sscanf(plink->value.constantStr,"%hu",&value);
	*pvalue = value;
	}
	break;
    case DBF_SHORT : 
	sscanf(plink->value.constantStr,"%hd",(short *)pdest);
	break;
    case DBF_USHORT : 
    case DBF_ENUM : 
    case DBF_MENU : 
    case DBF_DEVICE : 
	sscanf(plink->value.constantStr,"%hu",(unsigned short *)pdest);
	break;
    case DBF_LONG : 
	sscanf(plink->value.constantStr,"%ld",(long *)pdest);
	break;
    case DBF_ULONG : 
	sscanf(plink->value.constantStr,"%lu",(unsigned long *)pdest);
	break;
    case DBF_FLOAT : 
	sscanf(plink->value.constantStr,"%f",(float *)pdest);
	break;
    case DBF_DOUBLE : 
	sscanf(plink->value.constantStr,"%lf",(double *)pdest);
	break;
    default:
	epicsPrintf("Error in recGblInitConstantLink: Illegal DBF type\n");
	return(FALSE);
    }
    return(TRUE);
}

unsigned short recGblResetAlarms(void *precord)
{
    struct dbCommon *pdbc = precord;
    unsigned short mask,stat,sevr,nsta,nsev,ackt,acks,stat_mask;

    mask = stat_mask = 0;
    stat=pdbc->stat; sevr=pdbc->sevr;
    nsta=pdbc->nsta; nsev=pdbc->nsev;
    pdbc->stat=nsta; pdbc->sevr=nsev;
    pdbc->nsta=0; pdbc->nsev=0;
    /* alarm condition changed this scan?*/
    if (sevr!=nsev) {
	stat_mask = mask = DBE_ALARM;
	db_post_events(pdbc,&pdbc->sevr,DBE_VALUE);
    }
    if(stat!=nsta) {
	stat_mask |= DBE_VALUE;
	mask = DBE_ALARM;
    }
    if(stat_mask)
	db_post_events(pdbc,&pdbc->stat,stat_mask);
    if(sevr!=nsev || stat!=nsta) {
	ackt = pdbc->ackt; acks = pdbc->acks;
	if(!ackt || nsev>=acks){
	    pdbc->acks=nsev;
	    db_post_events(pdbc,&pdbc->acks,DBE_VALUE);
	}
    }
    return(mask);
}

void recGblFwdLink(void *precord)
{
    struct dbCommon *pdbc = precord;
    static short    fwdLinkValue = 1;

    if(pdbc->flnk.type==DB_LINK ) {
	struct dbAddr	*paddr = pdbc->flnk.value.pv_link.pvt;
	dbScanPassive(precord,paddr->precord);
    } else
    if((pdbc->flnk.type==CA_LINK) 
    && (pdbc->flnk.value.pv_link.pvlMask & pvlOptFWD)) {
	dbCaPutLink(&pdbc->flnk,DBR_SHORT,&fwdLinkValue,1);
    }
    /*Handle dbPutFieldNotify record completions*/
    if(pdbc->ppn) dbNotifyCompletion(pdbc);
    if(pdbc->rpro) {
	/*If anyone requested reprocessing do it*/
	pdbc->rpro = FALSE;
	scanOnce(pdbc);
    }
    /*In case putField caused put we are all done */
    pdbc->putf = FALSE;
}


void recGblGetTimeStamp(void* prec)
{
    struct dbCommon* pr = (struct dbCommon*)prec;
 
    if(pr->tsel.type!=CONSTANT)
    {
        dbGetLink(&(pr->tsel), DBR_SHORT,&(pr->tse),0,0);
        TSgetTimeStamp((int)pr->tse,(struct timespec*)&pr->time);
    }
    else
        TSgetTimeStamp((int)pr->tse,(struct timespec*)&pr->time);
}


static void getMaxRangeValues(field_type,pupper_limit,plower_limit)
    short           field_type;
    double          *pupper_limit;
    double          *plower_limit;
{
    switch(field_type){
    case(DBF_CHAR):
         *pupper_limit = -128.0;
         *plower_limit = 127.0;
         break;
    case(DBF_UCHAR):
         *pupper_limit = 255.0;
         *plower_limit = 0.0;
         break;
    case(DBF_SHORT):
         *pupper_limit = (double)SHRT_MAX;
         *plower_limit = (double)SHRT_MIN;
         break;
    case(DBF_ENUM):
    case(DBF_USHORT):
         *pupper_limit = (double)USHRT_MAX;
         *plower_limit = (double)0;
         break;
    case(DBF_LONG):
	/* long did not work using cast to double */
         *pupper_limit = 2147483647.;
         *plower_limit = -2147483648.;
         break;
    case(DBF_ULONG):
         *pupper_limit = (double)ULONG_MAX;
         *plower_limit = (double)0;
         break;
    case(DBF_FLOAT):
         *pupper_limit = (double)1e+30;
         *plower_limit = (double)-1e30;
         break;
    case(DBF_DOUBLE):
         *pupper_limit = (double)1e+30;
         *plower_limit = (double)-1e30;
         break;
    }
    return;
}

Navigate by Date:
Prev: RE: NULL record Name on IOC Jeff Hill
Next: RE: Epics R3.13.1.1 build with gcc2.95 Jeff Hill
Index: 1994  1995  1996  1997  1998  1999  <20002001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: VxWorks global variable support extension proposal Andrew Johnson
Next: RE: Epics R3.13.1.1 build with gcc2.95 Jeff Hill
Index: 1994  1995  1996  1997  1998  1999  <20002001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024