Experimental Physics and Industrial Control System
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
<2000>
2001
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
<2000>
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024