Initial revision
This commit is contained in:
527
src/rec/recAi.c
Normal file
527
src/rec/recAi.c
Normal file
@ -0,0 +1,527 @@
|
||||
/* recAi.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recAi.c - Record Support Routines for Analog Input records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 7-9-87
|
||||
* @(#)iocai.c 1.1 9/22/88
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 8-12-88 lrd Put in breakpoint conversions
|
||||
* Fix conversions for bipolar xy566 cards
|
||||
* .02 12-12-88 lrd Lock record on entry and unlock on exit
|
||||
* .03 12-15-88 lrd Process the forward scan link
|
||||
* .04 12-23-88 lrd Alarm on locked MAX_LOCKED times
|
||||
* .05 01-13-89 lrd deleted db_read_ai
|
||||
* .06 01-18-89 lrd modify adjustment offset to be independent of
|
||||
* adjustment slope
|
||||
* clamp xy566 breakpoint table negative values t o
|
||||
* zero
|
||||
* .07 03-27-89 lrd make hardware errors MAJOR alarms
|
||||
* remove hardware severity from the database
|
||||
* .08 04-03-89 lrd add monitor code
|
||||
* removed signal units conversion stuff
|
||||
* .09 04-05-89 lrd modified so that negative adjustment slope ASLO
|
||||
* would work
|
||||
* .10 05-03-89 lrd removed process mask from arg list
|
||||
* .11 08-01-89 lrd only set value for constant when val != 0
|
||||
* .12 10-11-89 lrd fix smoothing initial condition
|
||||
* .13 01-31-90 lrd add AB plc flag to the ab_aidriver call
|
||||
* .14 03-21-90 lrd add db_post_event for RVAL
|
||||
* .15 04-11-90 lrd make locals static
|
||||
* .16 04-18-90 mrk extensible record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <aiRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
long special();
|
||||
long get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_enum_str NULL
|
||||
long get_units();
|
||||
long get_graphic_double();
|
||||
long get_control_double();
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset aiRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
struct aidset { /* analog input dset */
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN read_ai;/*(-1,0,1)=>(failure,success,don't Continue*/
|
||||
DEVSUPFUN special_linconv;
|
||||
};
|
||||
|
||||
long convert_ai();
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct aiRecord *pai=(struct aiRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %-12.4G\n",pai->val)) return(-1);
|
||||
if(recGblReportLink(fp,"INP ",&(pai->inp))) return(-1);
|
||||
if(fprintf(fp,"PREC %d\n",pai->prec)) return(-1);
|
||||
if(recGblReportCvtChoice(fp,"LINR",pai->linr)) return(-1);
|
||||
if(fprintf(fp,"EGUF %-12.4G EGUL %-12.4G EGU %-8s\n",
|
||||
pai->eguf,pai->egul,pai->egu)) return(-1);
|
||||
if(fprintf(fp,"HOPR %-12.4G LOPR %-12.4G\n",
|
||||
pai->hopr,pai->lopr)) return(-1);
|
||||
if(fprintf(fp,"AOFF %-12.4G ASLO %-12.4G SMOO %-12.4G\n",
|
||||
pai->aoff,pai->aslo,pai->smoo)) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(pai->flnk))) return(-1);
|
||||
if(fprintf(fp,"HIHI %-12.4G HIGH %-12.4G LOW %-12.4G LOLO %-12.4G\n",
|
||||
pai->hihi,pai->high,pai->low,pai->lolo)) return(-1);
|
||||
if(recGblReportGblChoice(fp,pai,"HHSV",pai->hhsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,pai,"HSV ",pai->hsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,pai,"LSV ",pai->lsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,pai,"LLSV",pai->llsv)) return(-1);
|
||||
if(fprintf(fp,"HYST %-12.4G ADEL %-12.4G MDEL %-12.4G ESLO %-12.4G\n",
|
||||
pai->hyst,pai->adel,pai->mdel,pai->eslo)) return(-1);
|
||||
if(fprintf(fp,"RVAL 0x%-8X ACHN %d\n",
|
||||
pai->rval,pai->achn)) return(-1);
|
||||
if(fprintf(fp,"LALM %-12.4G ALST %-12.4G MLST %-12.4G\n",
|
||||
pai->lalm,pai->alst,pai->mlst)) return(-1);
|
||||
if(fprintf(fp,"LBRK %d\n",pai->lbrk)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long init_record(pai)
|
||||
struct aiRecord *pai;
|
||||
{
|
||||
struct aidset *pdset;
|
||||
long status;
|
||||
|
||||
if(!(pdset = (struct aidset *)(pai->dset))) {
|
||||
recGblRecordError(S_dev_noDSET,pai,"ai: init_record");
|
||||
return(S_dev_noDSET);
|
||||
}
|
||||
/* must have read_ai function defined */
|
||||
if( (pdset->number < 5) || (pdset->read_ai == NULL) ) {
|
||||
recGblRecordError(S_dev_missingSup,pai,"ai: init_record");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
pai->init = TRUE;
|
||||
if( pdset->init_record ) {
|
||||
if((status=(*pdset->init_record)(pai))) return(status);
|
||||
}
|
||||
if(pai->linr >= 2) { /*must find breakpoint table*/
|
||||
if( !cvtTable || (cvtTable->number < pai->linr)
|
||||
|| (!(cvtTable->papBrkTable[pai->linr]))) {
|
||||
errMessage(S_db_badField,"Breakpoint Table not Found");
|
||||
return(S_db_badField);
|
||||
}
|
||||
pai->pbrk = (char *)(cvtTable->papBrkTable[pai->linr]);
|
||||
pai->lbrk=0;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct aiRecord *pai=(struct aiRecord *)(paddr->precord);
|
||||
struct aidset *pdset = (struct aidset *)(pai->dset);
|
||||
long status;
|
||||
|
||||
if( (pdset==NULL) || (pdset->read_ai==NULL) ) {
|
||||
pai->pact=TRUE;
|
||||
recGblRecordError(S_dev_missingSup,pai,"read_ai");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
|
||||
status=(*pdset->read_ai)(pai); /* read the new value */
|
||||
pai->pact = TRUE;
|
||||
|
||||
/* status is one if an asynchronous record is being processed*/
|
||||
if(status==1) return(1);
|
||||
else if(status == -1) {
|
||||
if(pai->stat != READ_ALARM) {/* error. set alarm condition */
|
||||
pai->stat = READ_ALARM;
|
||||
pai->sevr = MAJOR_ALARM;
|
||||
pai->achn=1;
|
||||
}
|
||||
}
|
||||
else if(status == -2) {
|
||||
if(pai->stat != HW_LIMIT_ALARM) {/* error. set alarm condition */
|
||||
pai->stat = HW_LIMIT_ALARM;
|
||||
pai->sevr = MAJOR_ALARM;
|
||||
pai->achn=1;
|
||||
}
|
||||
status=0;
|
||||
}
|
||||
else if(status!=0) return(status);
|
||||
else if(pai->stat == READ_ALARM || pai->stat == HW_LIMIT_ALARM) {
|
||||
pai->stat = NO_ALARM;
|
||||
pai->sevr = NO_ALARM;
|
||||
pai->achn=1;
|
||||
}
|
||||
if(status==0) status=convert_ai(pai);
|
||||
|
||||
/* check for alarms */
|
||||
alarm(pai);
|
||||
|
||||
|
||||
/* check event list */
|
||||
if(!pai->disa) status = monitor(pai);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (pai->flnk.type==DB_LINK) dbScanPassive(&pai->flnk.value);
|
||||
|
||||
pai->init=FALSE;
|
||||
pai->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long special(paddr,after)
|
||||
struct dbAddr *paddr;
|
||||
int after;
|
||||
{
|
||||
struct aiRecord *pai = (struct aiRecord *)(paddr->precord);
|
||||
struct aidset *pdset = (struct aidset *) (pai->dset);
|
||||
int special_type = paddr->special;
|
||||
|
||||
switch(special_type) {
|
||||
case(SPC_LINCONV):
|
||||
if(pdset->number<5 || !(pdset->special_linconv)) {
|
||||
recGblDbaddrError(S_db_noMod,paddr,"ai: special");
|
||||
return(S_db_noMod);
|
||||
}
|
||||
pai->init=TRUE;
|
||||
return((*pdset->special_linconv)(pai,after));
|
||||
default:
|
||||
recGblDbaddrError(S_db_badChoice,paddr,"ai: special");
|
||||
return(S_db_badChoice);
|
||||
}
|
||||
}
|
||||
|
||||
static long get_precision(paddr,precision)
|
||||
struct dbAddr *paddr;
|
||||
long *precision;
|
||||
{
|
||||
struct aiRecord *pai=(struct aiRecord *)paddr->precord;
|
||||
|
||||
*precision = pai->prec;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_value(pai,pvdes)
|
||||
struct aiRecord *pai;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_FLOAT;
|
||||
pvdes->no_elements=1;
|
||||
(float *)(pvdes->pvalue) = &pai->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_units(paddr,units)
|
||||
struct dbAddr *paddr;
|
||||
char *units;
|
||||
{
|
||||
struct aiRecord *pai=(struct aiRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,pai->egu,sizeof(pai->egu));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_graphic_double(paddr,pgd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_grDouble *pgd;
|
||||
{
|
||||
struct aiRecord *pai=(struct aiRecord *)paddr->precord;
|
||||
|
||||
pgd->upper_disp_limit = pai->hopr;
|
||||
pgd->lower_disp_limit = pai->lopr;
|
||||
pgd->upper_alarm_limit = pai->hihi;
|
||||
pgd->upper_warning_limit = pai->high;
|
||||
pgd->lower_warning_limit = pai->low;
|
||||
pgd->lower_alarm_limit = pai->lolo;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_control_double(paddr,pcd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_ctrlDouble *pcd;
|
||||
{
|
||||
struct aiRecord *pai=(struct aiRecord *)paddr->precord;
|
||||
|
||||
pcd->upper_ctrl_limit = pai->hopr;
|
||||
pcd->lower_ctrl_limit = pai->lopr;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long alarm(pai)
|
||||
struct aiRecord *pai;
|
||||
{
|
||||
float ftemp;
|
||||
|
||||
/* check for a hardware alarm */
|
||||
if (pai->stat == READ_ALARM) return(0);
|
||||
|
||||
/* if in alarm and difference is not > hysterisis don't bother */
|
||||
if (pai->stat != NO_ALARM){
|
||||
ftemp = pai->lalm - pai->val;
|
||||
if(ftemp<0.0) ftemp = -ftemp;
|
||||
if (ftemp < pai->hyst) return(0);
|
||||
}
|
||||
|
||||
/* alarm condition hihi */
|
||||
if (pai->hhsv != NO_ALARM){
|
||||
if (pai->val > pai->hihi){
|
||||
pai->lalm = pai->val;
|
||||
if (pai->stat != HIHI_ALARM){
|
||||
pai->stat = HIHI_ALARM;
|
||||
pai->sevr = pai->hhsv;
|
||||
pai->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (pai->llsv != NO_ALARM){
|
||||
if (pai->val < pai->lolo){
|
||||
pai->lalm = pai->val;
|
||||
if (pai->stat != LOLO_ALARM){
|
||||
pai->stat = LOLO_ALARM;
|
||||
pai->sevr = pai->llsv;
|
||||
pai->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition high */
|
||||
if (pai->hsv != NO_ALARM){
|
||||
if (pai->val > pai->high){
|
||||
pai->lalm = pai->val;
|
||||
if (pai->stat != HIGH_ALARM){
|
||||
pai->stat = HIGH_ALARM;
|
||||
pai->sevr =pai->hsv;
|
||||
pai->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (pai->lsv != NO_ALARM){
|
||||
if (pai->val < pai->low){
|
||||
pai->lalm = pai->val;
|
||||
if (pai->stat != LOW_ALARM){
|
||||
pai->stat = LOW_ALARM;
|
||||
pai->sevr = pai->lsv;
|
||||
pai->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* no alarm */
|
||||
if (pai->stat != NO_ALARM){
|
||||
pai->stat = NO_ALARM;
|
||||
pai->sevr = NO_ALARM;
|
||||
pai->achn = 1;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long monitor(pai)
|
||||
struct aiRecord *pai;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
float delta;
|
||||
|
||||
/* anyone waiting for an event on this record */
|
||||
if (pai->mlis.count == 0) return(0L);
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (pai->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE | DBE_LOG;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(pai,&pai->stat,DBE_VALUE);
|
||||
db_post_events(pai,&pai->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
pai->mlst = pai->val;
|
||||
|
||||
/* check for value change */
|
||||
}else{
|
||||
delta = pai->mlst - pai->val;
|
||||
if(delta<0.0) delta = -delta;
|
||||
if (delta > pai->mdel) {
|
||||
/* post events for value change */
|
||||
monitor_mask = DBE_VALUE;
|
||||
|
||||
/* update last value monitored */
|
||||
pai->mlst = pai->val;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for archive change */
|
||||
delta = pai->alst - pai->val;
|
||||
if(delta<0.0) delta = 0.0;
|
||||
if (delta > pai->adel) {
|
||||
/* post events on value field for archive change */
|
||||
monitor_mask |= DBE_LOG;
|
||||
|
||||
/* update last archive value monitored */
|
||||
pai->alst = pai->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(pai,&pai->val,monitor_mask);
|
||||
db_post_events(pai,&pai->rval,monitor_mask);
|
||||
}
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long convert_ai(pai)
|
||||
struct aiRecord *pai;
|
||||
{
|
||||
float val;
|
||||
|
||||
|
||||
/* adjust slope and offset */
|
||||
if(pai->aslo != 0.0)
|
||||
val = val * pai->aslo + pai->aoff;
|
||||
else if(pai->aoff != 0.0)
|
||||
val = val + pai->aoff;
|
||||
|
||||
/* convert raw to engineering units and signal units */
|
||||
if(pai->linr == 0) {
|
||||
val = pai->val;
|
||||
}
|
||||
else if(pai->linr == 1) {
|
||||
val = (val * pai->eslo) + pai->egul;
|
||||
}
|
||||
else { /* must use breakpoint table */
|
||||
struct brkTable *pbrkTable;
|
||||
struct brkInt *pInt;
|
||||
struct brkInt *pnxtInt;
|
||||
short lbrk;
|
||||
int number;
|
||||
|
||||
val = pai->val;
|
||||
pbrkTable = (struct brkTable *) pai->pbrk;
|
||||
if((val<pbrkTable->rawLow) || (val>pbrkTable->rawHigh)) {
|
||||
if(pai->stat != READ_ALARM) {
|
||||
pai->stat = READ_ALARM;
|
||||
pai->sevr = MAJOR_ALARM;
|
||||
pai->achn = 1;
|
||||
}
|
||||
return(0L);
|
||||
}
|
||||
number = pbrkTable->number;
|
||||
if(pai->init) lbrk = number/2; /* Just start in the middle */
|
||||
else {
|
||||
lbrk = (pai->lbrk);
|
||||
/*make sure we dont go off end of table*/
|
||||
if( (lbrk+1) >= number ) lbrk--;
|
||||
}
|
||||
pInt = (pbrkTable->papBrkInt[lbrk]);
|
||||
pnxtInt = (pbrkTable->papBrkInt[lbrk+1]);
|
||||
/* find entry for increased value */
|
||||
while( (pnxtInt->raw) <= val ) {
|
||||
if( lbrk >= number-1) {
|
||||
errMessage(S_db_badField,"breakpoint table error");
|
||||
return(S_db_badField);
|
||||
}
|
||||
lbrk++;
|
||||
pInt = pbrkTable->papBrkInt[lbrk];
|
||||
}
|
||||
while( (pInt->raw) > val) {
|
||||
if(lbrk==0) {
|
||||
errMessage(S_db_badField,"breakpoint table error");
|
||||
return(S_db_badField);
|
||||
}
|
||||
lbrk--;
|
||||
pInt = pbrkTable->papBrkInt[lbrk];
|
||||
}
|
||||
pai->lbrk = lbrk;
|
||||
val = pInt->eng + (val - pInt->raw) * pInt->slope;
|
||||
}
|
||||
|
||||
/* apply smoothing algorithm */
|
||||
if (pai->smoo != 0){
|
||||
if (pai->init == 0) pai->val = val; /* initial condition */
|
||||
pai->val = val * (1.00 - pai->smoo) + (pai->val * pai->smoo);
|
||||
}else{
|
||||
pai->val = val;
|
||||
}
|
||||
return(0L);
|
||||
}
|
499
src/rec/recAo.c
Normal file
499
src/rec/recAo.c
Normal file
@ -0,0 +1,499 @@
|
||||
|
||||
/* recAo.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recAo.c - Record Support Routines for Analog Output records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 7-9-87
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 09-26-88 lrd interface the Ziomek085 card
|
||||
* .02 12-12-88 lrd lock record on entry unlock on exit
|
||||
* .03 12-15-88 lrd Process the forward scan link
|
||||
* .04 12-23-88 lrd Alarm on locked MAX_LOCKED times
|
||||
* .05 01-13-89 lrd deleted db_write_ao
|
||||
* .06 01-20-89 lrd fixed vx includes
|
||||
* .07 03-03-89 lrd mods for closed loop/supervisory control
|
||||
* .08 03-17-89 lrd add read_ao routine and call at initialization
|
||||
* .09 03-23-89 lrd convert AB readbacks
|
||||
* .10 03-29-89 lrd make hardware errors MAJOR
|
||||
* remove hw severity spec from database
|
||||
* .11 04-06-89 lrd remove signal conversions
|
||||
* .12 05-03-89 lrd removed process mask from arg list
|
||||
* .13 05-08-89 lrd fixed init to unlock on return condition
|
||||
* .14 05-25-89 lrd added rate of change add incremental/absolute
|
||||
* .15 01-31-90 lrd add plc_flag to ab_aodriver
|
||||
* .16 03-21-90 lrd add db_post_events for RVAL and RBV
|
||||
* .17 04-11-90 lrd make locals static
|
||||
* .18 07-27-90 lrd implement the output to a database record
|
||||
* .19 10-10-90 mrk extensible record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <aoRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
long special();
|
||||
long get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_enum_str NULL
|
||||
long get_units();
|
||||
long get_graphic_double();
|
||||
long get_control_double();
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset aoRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
struct aodset { /* analog input dset */
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN read_ao;
|
||||
DEVSUPFUN write_ao;
|
||||
DEVSUPFUN special_linconv;
|
||||
};
|
||||
|
||||
/* the following definitions must match those in choiceGbl.ascii */
|
||||
#define OUTPUT_FULL 0
|
||||
#define CLOSED_LOOP 1
|
||||
|
||||
/* The following must match the definition in choiceGbl.ascii */
|
||||
#define LINEAR 1
|
||||
|
||||
long convert_ao();
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct aoRecord *pao=(struct aoRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %-12.4G OROC %-12.4G\n",pao->val,pao->oroc)) return(-1);
|
||||
if(recGblReportLink(fp,"OUT ",&(pao->out))) return(-1);
|
||||
if(fprintf(fp,"PREC %d\n",pao->prec)) return(-1);
|
||||
if(recGblReportCvtChoice(fp,"LINR",pao->linr)) return(-1);
|
||||
if(fprintf(fp,"EGUF %-12.4G EGUL %-12.4G EGU %-8s\n",
|
||||
pao->eguf,pao->egul,pao->egu)) return(-1);
|
||||
if(fprintf(fp,"HOPR %-12.4G LOPR %-12.4G\n",
|
||||
pao->hopr,pao->lopr)) return(-1);
|
||||
if(fprintf(fp,"AOFF %-12.4G ASLO %-12.4G\n",
|
||||
pao->aoff,pao->aslo)) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(pao->flnk))) return(-1);
|
||||
if(fprintf(fp,"HIHI %-12.4G HIGH %-12.4G LOW %-12.4G LOLO %-12.4G\n",
|
||||
pao->hihi,pao->high,pao->low,pao->lolo)) return(-1);
|
||||
if(recGblReportGblChoice(fp,pao,"HHSV",pao->hhsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,pao,"HSV ",pao->hsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,pao,"LSV ",pao->lsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,pao,"LLSV",pao->llsv)) return(-1);
|
||||
if(fprintf(fp,"HYST %-12.4G ADEL %-12.4G MDEL %-12.4G ESLO %-12.4G\n",
|
||||
pao->hyst,pao->adel,pao->mdel,pao->eslo)) return(-1);
|
||||
if(fprintf(fp,"RVAL 0x%-8X ACHN %d\n",
|
||||
pao->rval,pao->achn)) return(-1);
|
||||
if(fprintf(fp,"LALM %-12.4G ALST %-12.4G MLST %-12.4G\n",
|
||||
pao->lalm,pao->alst,pao->mlst)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long init_record(pao)
|
||||
struct aoRecord *pao;
|
||||
{
|
||||
struct aodset *pdset;
|
||||
long status;
|
||||
|
||||
if(!(pdset = (struct aodset *)(pao->dset))) {
|
||||
recGblRecordError(S_dev_noDSET,pao,"ao: init_record");
|
||||
return(S_dev_noDSET);
|
||||
}
|
||||
/* must have read_ao and write_ao function defined */
|
||||
if( (pdset->number < 6) || (pdset->read_ao == NULL) ||(pdset->write_ao ==NULL) ) {
|
||||
recGblRecordError(S_dev_missingSup,pao,"ao: init_record");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
pao->init = TRUE;
|
||||
if( pdset->init_record ) {
|
||||
if((status=(*pdset->init_record)(pao))) return(status);
|
||||
}
|
||||
/* get the intial value */
|
||||
if ((pao->dol.type == CONSTANT) && (pao->dol.value.value != 0)){
|
||||
pao->val = pao->dol.value.value;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct aoRecord *pao=(struct aoRecord *)(paddr->precord);
|
||||
struct aodset *pdset = (struct aodset *)(pao->dset);
|
||||
long status;
|
||||
long nRequest;
|
||||
float value;
|
||||
float diff;
|
||||
|
||||
if( (pdset==NULL) || (pdset->write_ao==NULL) ) {
|
||||
pao->pact=TRUE;
|
||||
recGblRecordError(S_dev_missingSup,pao,"write_ao");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
|
||||
/* fetch the desired output if there is a database link */
|
||||
if ((pao->dol.type == DB_LINK) && (pao->omsl == CLOSED_LOOP)){
|
||||
nRequest=1;
|
||||
if (dbGetLink(&pao->dol.value,DBR_FLOAT,&value,&nRequest) < 0){
|
||||
if (pao->stat != READ_ALARM){
|
||||
pao->stat = READ_ALARM;
|
||||
pao->sevr = MAJOR_ALARM;
|
||||
pao->achn = 1;
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
if (pao->oif == OUTPUT_FULL)
|
||||
pao->val = value; /* output full */
|
||||
else
|
||||
pao->val += value; /* output incremental */
|
||||
}
|
||||
|
||||
/* apply the output rate of change */
|
||||
if (pao->oroc){
|
||||
diff = pao->val - pao->oval;
|
||||
if (diff < 0){
|
||||
if (pao->oroc < -diff){
|
||||
pao->oval -= pao->oroc;
|
||||
}else{
|
||||
pao->oval = pao->val;
|
||||
}
|
||||
}else if (pao->oroc < diff){
|
||||
pao->oval += pao->oroc;
|
||||
}else{
|
||||
pao->oval = pao->val;
|
||||
}
|
||||
}else{
|
||||
pao->oval = pao->val;
|
||||
}
|
||||
/* MARTY check for HW_LIMIT*/
|
||||
status=(*pdset->write_ao)(pao); /* write the new value */
|
||||
pao->pact = TRUE;
|
||||
|
||||
/* status is one if an asynchronous record is being processed*/
|
||||
if(status==1) return(1);
|
||||
else if(status == -1) {
|
||||
if(pao->stat != READ_ALARM) {/* error. set alarm condition */
|
||||
pao->stat = READ_ALARM;
|
||||
pao->sevr = MAJOR_ALARM;
|
||||
pao->achn=1;
|
||||
}
|
||||
}
|
||||
else if(status!=0) return(status);
|
||||
else if(pao->stat == READ_ALARM || pao->stat == HW_LIMIT_ALARM) {
|
||||
pao->stat = NO_ALARM;
|
||||
pao->sevr = NO_ALARM;
|
||||
pao->achn=1;
|
||||
}
|
||||
if(status==0) status=convert_ao(pao);
|
||||
/* MARTY convert_ao_rb */
|
||||
|
||||
/* report no harware error if previous hardware error */
|
||||
if ((pao->stat == READ_ALARM) || (pao->stat == WRITE_ALARM)){
|
||||
pao->stat = NO_ALARM;
|
||||
pao->sevr = NO_ALARM;
|
||||
pao->achn = 1;
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
alarm(pao);
|
||||
|
||||
|
||||
/* check event list */
|
||||
if(!pao->disa) status = monitor(pao);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (pao->flnk.type==DB_LINK) dbScanPassive(&pao->flnk.value);
|
||||
|
||||
pao->init=FALSE;
|
||||
pao->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long get_precision(paddr,precision)
|
||||
struct dbAddr *paddr;
|
||||
long *precision;
|
||||
{
|
||||
struct aoRecord *pao=(struct aoRecord *)paddr->precord;
|
||||
|
||||
*precision = pao->prec;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_value(pao,pvdes)
|
||||
struct aoRecord *pao;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_FLOAT;
|
||||
pvdes->no_elements=1;
|
||||
(float *)(pvdes->pvalue) = &pao->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_units(paddr,units)
|
||||
struct dbAddr *paddr;
|
||||
char *units;
|
||||
{
|
||||
struct aoRecord *pao=(struct aoRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,pao->egu,sizeof(pao->egu));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_graphic_double(paddr,pgd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_grDouble *pgd;
|
||||
{
|
||||
struct aoRecord *pao=(struct aoRecord *)paddr->precord;
|
||||
|
||||
pgd->upper_disp_limit = pao->hopr;
|
||||
pgd->lower_disp_limit = pao->lopr;
|
||||
pgd->upper_alarm_limit = pao->hihi;
|
||||
pgd->upper_warning_limit = pao->high;
|
||||
pgd->lower_warning_limit = pao->low;
|
||||
pgd->lower_alarm_limit = pao->lolo;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_control_double(paddr,pcd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_ctrlDouble *pcd;
|
||||
{
|
||||
struct aoRecord *pao=(struct aoRecord *)paddr->precord;
|
||||
|
||||
pcd->upper_ctrl_limit = pao->hopr;
|
||||
pcd->lower_ctrl_limit = pao->lopr;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long alarm(pao)
|
||||
struct aoRecord *pao;
|
||||
{
|
||||
float ftemp;
|
||||
|
||||
/* check for a hardware alarm */
|
||||
if (pao->stat == READ_ALARM) return(0);
|
||||
if (pao->stat == WRITE_ALARM) return(0);
|
||||
if (pao->stat == HW_LIMIT_ALARM) return(0);
|
||||
|
||||
/* if in alarm and difference is not > hysterisis don't bother */
|
||||
if (pao->stat != NO_ALARM){
|
||||
ftemp = pao->lalm - pao->val;
|
||||
if(ftemp<0.0) ftemp = -ftemp;
|
||||
if (ftemp < pao->hyst) return(0);
|
||||
}
|
||||
|
||||
/* alarm condition hihi */
|
||||
if (pao->hhsv != NO_ALARM){
|
||||
if (pao->val > pao->hihi){
|
||||
pao->lalm = pao->val;
|
||||
if (pao->stat != HIHI_ALARM){
|
||||
pao->stat = HIHI_ALARM;
|
||||
pao->sevr = pao->hhsv;
|
||||
pao->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (pao->llsv != NO_ALARM){
|
||||
if (pao->val < pao->lolo){
|
||||
pao->lalm = pao->val;
|
||||
if (pao->stat != LOLO_ALARM){
|
||||
pao->stat = LOLO_ALARM;
|
||||
pao->sevr = pao->llsv;
|
||||
pao->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition high */
|
||||
if (pao->hsv != NO_ALARM){
|
||||
if (pao->val > pao->high){
|
||||
pao->lalm = pao->val;
|
||||
if (pao->stat != HIGH_ALARM){
|
||||
pao->stat = HIGH_ALARM;
|
||||
pao->sevr =pao->hsv;
|
||||
pao->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (pao->lsv != NO_ALARM){
|
||||
if (pao->val < pao->low){
|
||||
pao->lalm = pao->val;
|
||||
if (pao->stat != LOW_ALARM){
|
||||
pao->stat = LOW_ALARM;
|
||||
pao->sevr = pao->lsv;
|
||||
pao->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* no alarm */
|
||||
if (pao->stat != NO_ALARM){
|
||||
pao->stat = NO_ALARM;
|
||||
pao->sevr = NO_ALARM;
|
||||
pao->achn = 1;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long monitor(pao)
|
||||
struct aoRecord *pao;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
float delta;
|
||||
|
||||
/* anyone waiting for an event on this record */
|
||||
if (pao->mlis.count == 0) return(0L);
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (pao->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE | DBE_LOG;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(pao,&pao->stat,DBE_VALUE);
|
||||
db_post_events(pao,&pao->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
pao->mlst = pao->val;
|
||||
|
||||
/* check for value change */
|
||||
}else{
|
||||
delta = pao->mlst - pao->val;
|
||||
if(delta<0.0) delta = -delta;
|
||||
if (delta > pao->mdel) {
|
||||
/* post events for value change */
|
||||
monitor_mask = DBE_VALUE;
|
||||
|
||||
/* update last value monitored */
|
||||
pao->mlst = pao->val;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for archive change */
|
||||
delta = pao->alst - pao->val;
|
||||
if(delta<0.0) delta = 0.0;
|
||||
if (delta > pao->adel) {
|
||||
/* post events on value field for archive change */
|
||||
monitor_mask |= DBE_LOG;
|
||||
|
||||
/* update last archive value monitored */
|
||||
pao->alst = pao->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(pao,&pao->val,monitor_mask);
|
||||
db_post_events(pao,&pao->rval,monitor_mask);
|
||||
db_post_events(pao,&pao->rbv,monitor_mask);
|
||||
}
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static convert_ao_rb(value,pao)
|
||||
unsigned short value; /* readback raw value */
|
||||
struct aoRecord *pao;
|
||||
{
|
||||
|
||||
switch (pao->linr){
|
||||
case (LINEAR):
|
||||
pao->rbv = (value * pao->eslo) + pao->egul;
|
||||
break;
|
||||
default:
|
||||
pao->rbv = value;
|
||||
}
|
||||
}
|
||||
|
||||
static convert_ao(pao)
|
||||
struct aoRecord *pao;
|
||||
{
|
||||
/* check drive limits */
|
||||
if (pao->oval > pao->drvh) pao->oval = pao->drvh;
|
||||
else if (pao->oval < pao->drvl) pao->oval = pao->drvl;
|
||||
|
||||
/* convert */
|
||||
if (pao->linr == LINEAR){
|
||||
if (pao->eslo == 0) pao->rval = 0;
|
||||
else pao->rval = (pao->oval - pao->egul) / pao->eslo;
|
||||
}else{
|
||||
pao->rval = pao->oval;
|
||||
}
|
||||
}
|
||||
|
325
src/rec/recBi.c
Normal file
325
src/rec/recBi.c
Normal file
@ -0,0 +1,325 @@
|
||||
|
||||
/* recBi.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recBi.c - Record Support Routines for Binary Input records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 7-9-87
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 12-12-88 lrd lock the record on entry and unlock on exit
|
||||
* .02 12-15-88 lrd Process the forward scan link
|
||||
* .03 12-23-88 lrd Alarm on locked MAX_LOCKED times
|
||||
* .04 01-13-89 lrd delete db_read_bi
|
||||
* .05 03-17-89 lrd database link inputs
|
||||
* .06 03-29-89 lrd make hardware errors MAJOR
|
||||
* remove hw severity spec from database
|
||||
* .07 04-06-89 lrd add monitor detection
|
||||
* .08 05-03-89 lrd removed process mask from arg list
|
||||
* .09 01-31-90 lrd add the plc_flag arg to the ab_bidriver call
|
||||
* .10 03-21-90 lrd add db_post_events for RVAL
|
||||
* .11 04-11-90 lrd make local variables static
|
||||
* .12 10-10-90 mrk Made changes for new record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
#include <strLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <biRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
long special();
|
||||
long get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
long get_enum_str();
|
||||
#define get_units NULL
|
||||
#define get_graphic_double NULL
|
||||
#define get_control_double NULL
|
||||
long get_enum_strs();
|
||||
|
||||
struct rset biRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
struct bidset { /* binary input dset */
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN read_bi;/*(-1,0,1)=>(failure,success,don't Continue*/
|
||||
};
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct biRecord *pbi=(struct biRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %d\n",pbi->val)) return(-1);
|
||||
if(recGblReportLink(fp,"INP ",&(pbi->inp))) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(pbi->flnk))) return(-1);
|
||||
if(fprintf(fp,"RVAL 0x%-8X\n",
|
||||
pbi->rval)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long init_record(pbi)
|
||||
struct biRecord *pbi;
|
||||
{
|
||||
struct bidset *pdset;
|
||||
long status;
|
||||
|
||||
if(!(pdset = (struct bidset *)(pbi->dset))) {
|
||||
recGblRecordError(S_dev_noDSET,pbi,"bi: init_record");
|
||||
return(S_dev_noDSET);
|
||||
}
|
||||
/* must have read_bi function defined */
|
||||
if( (pdset->number < 5) || (pdset->read_bi == NULL) ) {
|
||||
recGblRecordError(S_dev_missingSup,pbi,"bi: init_record");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
if( pdset->init_record ) {
|
||||
if((status=(*pdset->init_record)(pbi))) return(status);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct biRecord *pbi=(struct biRecord *)(paddr->precord);
|
||||
struct bidset *pdset = (struct bidset *)(pbi->dset);
|
||||
long status;
|
||||
|
||||
if( (pdset==NULL) || (pdset->read_bi==NULL) ) {
|
||||
pbi->pact=TRUE;
|
||||
recGblRecordError(S_dev_missingSup,pbi,"read_bi");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
|
||||
status=(*pdset->read_bi)(pbi); /* read the new value */
|
||||
pbi->pact = TRUE;
|
||||
|
||||
/* status is one if an asynchronous record is being processed*/
|
||||
if(status==1) return(1);
|
||||
else if(status == -1) {
|
||||
if(pbi->stat != READ_ALARM) {/* error. set alarm condition */
|
||||
pbi->stat = READ_ALARM;
|
||||
pbi->sevr = MAJOR_ALARM;
|
||||
pbi->achn=1;
|
||||
}
|
||||
}
|
||||
else if(status!=0) return(status);
|
||||
else if(pbi->stat == READ_ALARM) {
|
||||
pbi->stat = NO_ALARM;
|
||||
pbi->sevr = NO_ALARM;
|
||||
pbi->achn=1;
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
alarm(pbi);
|
||||
|
||||
|
||||
/* check event list */
|
||||
if(!pbi->disa) status = monitor(pbi);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (pbi->flnk.type==DB_LINK) dbScanPassive(&pbi->flnk.value);
|
||||
|
||||
pbi->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long get_value(pbi,pvdes)
|
||||
struct biRecord *pbi;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_ENUM;
|
||||
pvdes->no_elements=1;
|
||||
(unsigned short *)(pvdes->pvalue) = &pbi->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_enum_str(paddr,pstring)
|
||||
struct dbAddr *paddr;
|
||||
char *pstring;
|
||||
{
|
||||
struct biRecord *pbi=(struct biRecord *)paddr->precord;
|
||||
|
||||
if(pbi->val==0) {
|
||||
strncpy(pstring,pbi->znam,sizeof(pbi->znam));
|
||||
pstring[sizeof(pbi->znam)] = 0;
|
||||
} else if(pbi->val==0) {
|
||||
strncpy(pstring,pbi->onam,sizeof(pbi->onam));
|
||||
pstring[sizeof(pbi->onam)] = 0;
|
||||
} else {
|
||||
strcpy(pstring,"Illegal Value");
|
||||
}
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_enum_strs(paddr,pes)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_enumStrs *pes;
|
||||
{
|
||||
struct biRecord *pbi=(struct biRecord *)paddr->precord;
|
||||
|
||||
pes->no_str = 2;
|
||||
bzero(pes->strs,sizeof(pes->strs));
|
||||
strncpy(pes->strs[0],pbi->znam,sizeof(pbi->znam));
|
||||
strncpy(pes->strs[1],pbi->onam,sizeof(pbi->onam));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long alarm(pbi)
|
||||
struct biRecord *pbi;
|
||||
{
|
||||
float ftemp;
|
||||
|
||||
/* check for a hardware alarm */
|
||||
if (pbi->stat == READ_ALARM) return(0);
|
||||
|
||||
if (pbi->val == pbi->lalm){
|
||||
/* no new message for COS alarms */
|
||||
if (pbi->stat == COS_ALARM){
|
||||
pbi->stat = NO_ALARM;
|
||||
pbi->sevr = NO_ALARM;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* set last alarmed value */
|
||||
pbi->lalm = pbi->val;
|
||||
|
||||
/* check for state alarm */
|
||||
if (pbi->val == 0){
|
||||
if (pbi->zsv != NO_ALARM){
|
||||
pbi->stat = STATE_ALARM;
|
||||
pbi->sevr = pbi->zsv;
|
||||
pbi->achn = 1;
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
if (pbi->osv != NO_ALARM){
|
||||
pbi->stat = STATE_ALARM;
|
||||
pbi->sevr = pbi->osv;
|
||||
pbi->achn = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for cos alarm */
|
||||
if (pbi->cosv != NO_ALARM){
|
||||
pbi->sevr = pbi->cosv;
|
||||
pbi->stat = COS_ALARM;
|
||||
pbi->achn = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for change from alarm to no alarm */
|
||||
if (pbi->sevr != NO_ALARM){
|
||||
pbi->sevr = NO_ALARM;
|
||||
pbi->stat = NO_ALARM;
|
||||
pbi->achn = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long monitor(pbi)
|
||||
struct biRecord *pbi;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
|
||||
/* anyone waiting for an event on this record */
|
||||
if (pbi->mlis.count == 0) return(0L);
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (pbi->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE | DBE_LOG;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(pbi,&pbi->stat,DBE_VALUE);
|
||||
db_post_events(pbi,&pbi->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
pbi->mlst = pbi->val;
|
||||
/* check for value change */
|
||||
}else if (pbi->mlst != pbi->val){
|
||||
/* post events for value change and archive change */
|
||||
monitor_mask |= (DBE_VALUE | DBE_LOG);
|
||||
|
||||
/* update last value monitored */
|
||||
pbi->mlst = pbi->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(pbi,&pbi->val,monitor_mask);
|
||||
db_post_events(pbi,&pbi->rval,monitor_mask);
|
||||
}
|
||||
return(0L);
|
||||
}
|
365
src/rec/recBo.c
Normal file
365
src/rec/recBo.c
Normal file
@ -0,0 +1,365 @@
|
||||
|
||||
/* recBo.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recBo.c - Record Support Routines for Binary Output records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 7-17-87
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 12-9-88 lrd lock the record during processing
|
||||
* .02 12-15-88 lrd process the forward scan link
|
||||
* .03 12-23-88 lrd Alarm on locked MAX_LOCKED times
|
||||
* .04 01-13-89 lrd delete db_read_bo and db_write_bo
|
||||
* .05 01-20-89 lrd fixed vx includes
|
||||
* .06 03-29-89 lrd make hardware errors MAJOR
|
||||
* remove hw severity spec from database
|
||||
* add continuous control
|
||||
* .07 04-06-89 lrd add monitor detection
|
||||
* .08 05-03-89 lrd removed process mask from arg list
|
||||
* .09 08-16-89 lrd add ability to do softchannel momentary
|
||||
* .10 08-17-89 lrd add soft channel support
|
||||
* .11 01-31-90 lrd add the plc_flag arg to the ab_bodriver call
|
||||
* .12 03-21-90 lrd add db_post_events for RVAL and RBV
|
||||
* .13 04-02-90 ba/lrd add monitor handling for momentary outputs
|
||||
* remove rbv arg to ab_bodriver
|
||||
* .14 04-05-90 lrd make momentary output handling a task
|
||||
* as the watchdog runs at interrupt level
|
||||
* .15 04-11-90 lrd make locals static
|
||||
* .16 05-02-90 lrd fix initial value set in the DOL field
|
||||
* .17 10-10-90 mrk Changes for record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
#include <strLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <boRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
long special();
|
||||
long get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
long get_enum_str();
|
||||
#define get_units NULL
|
||||
#define get_graphic_double NULL
|
||||
#define get_control_double NULL
|
||||
long get_enum_strs();
|
||||
|
||||
struct rset boRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
struct bodset { /* binary output dset */
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN read_bo;/*(-1,0)=>(failure,success*/
|
||||
DEVSUPFUN write_bo;/*(-1,0,1)=>(failure,success,don't Continue*/
|
||||
};
|
||||
|
||||
/* the following definitions must match those in choiceGbl.ascii */
|
||||
#define OUTPUT_FULL 0
|
||||
#define CLOSED_LOOP 1
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct boRecord *pbo=(struct boRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %d\n",pbo->val)) return(-1);
|
||||
if(recGblReportLink(fp,"OUT ",&(pbo->out))) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(pbo->flnk))) return(-1);
|
||||
if(fprintf(fp,"RVAL 0x%-8X\n",
|
||||
pbo->rval)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long init_record(pbo)
|
||||
struct boRecord *pbo;
|
||||
{
|
||||
struct bodset *pdset;
|
||||
long status;
|
||||
|
||||
if(!(pdset = (struct bodset *)(pbo->dset))) {
|
||||
recGblRecordError(S_dev_noDSET,pbo,"bo: init_record");
|
||||
return(S_dev_noDSET);
|
||||
}
|
||||
/* must have read_bo and write_bo functions defined */
|
||||
if( (pdset->number < 5) || (pdset->read_bo == NULL) || (pdset->write_bo == NULL) ) {
|
||||
recGblRecordError(S_dev_missingSup,pbo,"bo: init_record");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
/* get the intial value */
|
||||
if (pbo->dol.type == CONSTANT){
|
||||
if (pbo->dol.value.value != 0) pbo->val = 1;
|
||||
else pbo->val = 0;
|
||||
}
|
||||
if( pdset->init_record ) {
|
||||
if((status=(*pdset->init_record)(pbo))) return(status);
|
||||
}
|
||||
pbo->time = pbo->high * 60; /* seconds to ticks */
|
||||
pbo->lalm = -1;
|
||||
pbo->mlst = -1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct boRecord *pbo=(struct boRecord *)(paddr->precord);
|
||||
struct bodset *pdset = (struct bodset *)(pbo->dset);
|
||||
long status;
|
||||
long nRequest;
|
||||
float fval;
|
||||
|
||||
if( (pdset==NULL) || (pdset->read_bo==NULL) ) {
|
||||
pbo->pact=TRUE;
|
||||
recGblRecordError(S_dev_missingSup,pbo,"read_bo");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
|
||||
|
||||
/* fetch the desired output if there is a database link */
|
||||
if ( !(pbo->pact) && (pbo->dol.type == DB_LINK) && (pbo->omsl == CLOSED_LOOP)){
|
||||
nRequest = 1;
|
||||
if (dbGetLink(&pbo->dol.value,DBF_SHORT,&fval,&nRequest) < 0){
|
||||
if (pbo->stat != READ_ALARM){
|
||||
pbo->stat = READ_ALARM;
|
||||
pbo->sevr = MAJOR_ALARM;
|
||||
pbo->achn = 1;
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
if (fval != 0) pbo->val = 1;
|
||||
else pbo->val = 0;
|
||||
}
|
||||
|
||||
status=(*pdset->write_bo)(pbo); /* write the new value */
|
||||
pbo->pact = TRUE;
|
||||
|
||||
/* status is one if an asynchronous record is being processed*/
|
||||
if(status==1) return(1);
|
||||
else if(status == -1) {
|
||||
if(pbo->stat != WRITE_ALARM) {/* error. set alarm condition */
|
||||
pbo->stat = WRITE_ALARM;
|
||||
pbo->sevr = MAJOR_ALARM;
|
||||
pbo->achn=1;
|
||||
}
|
||||
}
|
||||
else if(status!=0) return(status);
|
||||
else if(pbo->stat == WRITE_ALARM) {
|
||||
pbo->stat = NO_ALARM;
|
||||
pbo->sevr = NO_ALARM;
|
||||
pbo->achn=1;
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
alarm(pbo);
|
||||
|
||||
|
||||
/* check event list */
|
||||
if(!pbo->disa) status = monitor(pbo);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (pbo->flnk.type==DB_LINK) dbScanPassive(&pbo->flnk.value);
|
||||
|
||||
pbo->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long get_value(pbo,pvdes)
|
||||
struct boRecord *pbo;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_ENUM;
|
||||
pvdes->no_elements=1;
|
||||
(unsigned short *)(pvdes->pvalue) = &pbo->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_enum_str(paddr,pstring)
|
||||
struct dbAddr *paddr;
|
||||
char *pstring;
|
||||
{
|
||||
struct boRecord *pbo=(struct boRecord *)paddr->precord;
|
||||
|
||||
if(pbo->val==0) {
|
||||
strncpy(pstring,pbo->znam,sizeof(pbo->znam));
|
||||
pstring[sizeof(pbo->znam)] = 0;
|
||||
} else if(pbo->val==0) {
|
||||
strncpy(pstring,pbo->onam,sizeof(pbo->onam));
|
||||
pstring[sizeof(pbo->onam)] = 0;
|
||||
} else {
|
||||
strcpy(pstring,"Illegal Value");
|
||||
}
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_enum_strs(paddr,pes)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_enumStrs *pes;
|
||||
{
|
||||
struct boRecord *pbo=(struct boRecord *)paddr->precord;
|
||||
|
||||
pes->no_str = 2;
|
||||
bzero(pes->strs,sizeof(pes->strs));
|
||||
strncpy(pes->strs[0],pbo->znam,sizeof(pbo->znam));
|
||||
strncpy(pes->strs[1],pbo->onam,sizeof(pbo->onam));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long alarm(pbo)
|
||||
struct boRecord *pbo;
|
||||
{
|
||||
float ftemp;
|
||||
|
||||
/* check for a hardware alarm */
|
||||
if (pbo->stat == WRITE_ALARM || pbo->stat == READ_ALARM) return(0);
|
||||
|
||||
if (pbo->val == pbo->lalm){
|
||||
/* no new message for COS alarms */
|
||||
if (pbo->stat == COS_ALARM){
|
||||
pbo->stat = NO_ALARM;
|
||||
pbo->sevr = NO_ALARM;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* set last alarmed value */
|
||||
pbo->lalm = pbo->val;
|
||||
|
||||
/* check for state alarm */
|
||||
if (pbo->val == 0){
|
||||
if (pbo->zsv != NO_ALARM){
|
||||
pbo->stat = STATE_ALARM;
|
||||
pbo->sevr = pbo->zsv;
|
||||
pbo->achn = 1;
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
if (pbo->osv != NO_ALARM){
|
||||
pbo->stat = STATE_ALARM;
|
||||
pbo->sevr = pbo->osv;
|
||||
pbo->achn = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for cos alarm */
|
||||
if (pbo->cosv != NO_ALARM){
|
||||
pbo->sevr = pbo->cosv;
|
||||
pbo->stat = COS_ALARM;
|
||||
pbo->achn = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for change from alarm to no alarm */
|
||||
if (pbo->sevr != NO_ALARM){
|
||||
pbo->sevr = NO_ALARM;
|
||||
pbo->stat = NO_ALARM;
|
||||
pbo->achn = 1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long monitor(pbo)
|
||||
struct boRecord *pbo;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
|
||||
/* anyone waiting for an event on this record */
|
||||
if (pbo->mlis.count == 0) return(0L);
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (pbo->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE | DBE_LOG;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(pbo,&pbo->stat,DBE_VALUE);
|
||||
db_post_events(pbo,&pbo->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
pbo->mlst = pbo->val;
|
||||
/* check for value change */
|
||||
}else if (pbo->mlst != pbo->val){
|
||||
/* post events for value change and archive change */
|
||||
monitor_mask |= (DBE_VALUE | DBE_LOG);
|
||||
|
||||
/* update last value monitored */
|
||||
pbo->mlst = pbo->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(pbo,&pbo->val,monitor_mask);
|
||||
db_post_events(pbo,&pbo->rval,monitor_mask);
|
||||
db_post_events(pbo,&pbo->rbv,monitor_mask);
|
||||
}
|
||||
return(0L);
|
||||
}
|
1273
src/rec/recCalc.c
Normal file
1273
src/rec/recCalc.c
Normal file
File diff suppressed because it is too large
Load Diff
498
src/rec/recCompress.c
Normal file
498
src/rec/recCompress.c
Normal file
@ -0,0 +1,498 @@
|
||||
|
||||
/* recCompress.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recCompress.c - Record Support Routines for Compression records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 7-14-89
|
||||
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 11-27-89 lrd using one more buffer entry than allocated
|
||||
* .02 11-27-89 lrd throttle on monitor requests
|
||||
* .03 02-27-90 lrd handle character value links for Joerger
|
||||
* digitizer (convert to short array for access
|
||||
* .04 03-05-90 lrd add averaging of entire waveforms
|
||||
* .05 04-02-90 ba/lrd fix the joerger processing and
|
||||
* add get_a_byte macro
|
||||
* fix the determination of buff_size
|
||||
* .06 04-11-90 lrd make locals static
|
||||
* .07 05-02-90 lrd fix mdct so that it would remain 0 on the
|
||||
* pass where the monitors are sent
|
||||
* .08 05-08-90 ba mdct is never equal to mcnt during record pro-
|
||||
* cessing, causing some code never to run. Fix
|
||||
* is to check (mdct==mcnt || mdct==0) to indicate
|
||||
* first time through an averaging loop.
|
||||
* .09 07-26-90 lrd fixed the N-to-1 character compression
|
||||
* value was not initialized
|
||||
* .10 10-11-90 mrk Made changes for new record support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <compressRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
#define special NULL
|
||||
long get_precision();
|
||||
long get_value();
|
||||
long cvt_dbaddr();
|
||||
long get_array_info();
|
||||
long put_array_info();
|
||||
#define get_enum_str NULL
|
||||
long get_units();
|
||||
long get_graphic_double();
|
||||
long get_control_double();
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset compressRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long init_record(pcompress)
|
||||
struct compressRecord *pcompress;
|
||||
{
|
||||
long status;
|
||||
|
||||
/* This routine may get called twice. Once by cvt_dbaddr. Once by iocInit*/
|
||||
/* allocate bptr and sptr */
|
||||
if(pcompress->bptr==NULL) {
|
||||
if(pcompress->nsam<=0) pcompress->nsam=1;
|
||||
pcompress->bptr = (float *)malloc(pcompress->nsam * sizeof(float));
|
||||
/* allocate memory for the summing buffer for conversions requiring it */
|
||||
if (pcompress->alg == AVERAGE){
|
||||
pcompress->sptr = (float *)malloc(pcompress->nsam * sizeof(float));
|
||||
}
|
||||
}
|
||||
/*allocate wptr*/
|
||||
if(pcompress->wptr==NULL && pcompress->inp.type==PV_LINK) {
|
||||
struct dbAddr *pdbAddr = (struct dbAddr *)(pcompress->inp.value.db_link.pdbAddr);
|
||||
pcompress->sptr = (float *)malloc(pdbAddr->no_elements * sizeof(float));
|
||||
}
|
||||
/* initialize the monitor count */
|
||||
pcompress->mdct = pcompress->mcnt;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_precision(paddr,precision)
|
||||
struct dbAddr *paddr;
|
||||
long *precision;
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord *)paddr->precord;
|
||||
|
||||
*precision = pcompress->prec;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_value(pcompress,pvdes)
|
||||
struct compressRecord *pcompress;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_FLOAT;
|
||||
pvdes->no_elements=pcompress->nsam;
|
||||
(float *)(pvdes->pvalue) = pcompress->bptr;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long cvt_dbaddr(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord *)paddr->precord;
|
||||
|
||||
/* This may get called before init_record. If so just call it*/
|
||||
if(pcompress->bptr==NULL) init_record(paddr);
|
||||
|
||||
paddr->pfield = (caddr_t)(pcompress->bptr);
|
||||
paddr->no_elements = pcompress->nsam;
|
||||
paddr->field_type = DBF_FLOAT;
|
||||
paddr->field_size = sizeof(float);
|
||||
paddr->dbr_field_type = DBF_FLOAT;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_array_info(paddr,no_elements,offset)
|
||||
struct dbAddr *paddr;
|
||||
long *no_elements;
|
||||
long *offset;
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord *)paddr->precord;
|
||||
|
||||
*no_elements = pcompress->nuse;
|
||||
*offset = inx+1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long put_array_info(paddr,nNew)
|
||||
struct dbAddr *paddr;
|
||||
long nNew;
|
||||
long offset;
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord *)paddr->precord;
|
||||
|
||||
pcompress->inx = (pcompress->inx + nNew) % (pcompress->nsam);
|
||||
pcompress->nuse = (pcompress->nuse + nNew);
|
||||
if(pcompress->nuse > pcompress->nsam) pcompress->nuse = pcompress->nsam;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static long get_units(paddr,units)
|
||||
struct dbAddr *paddr;
|
||||
char *units;
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,pcompress->egu,sizeof(pcompress->egu));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_graphic_double(paddr,pgd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_grDouble *pgd;
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord *)paddr->precord;
|
||||
|
||||
pgd->upper_disp_limit = pcompress->hopr;
|
||||
pgd->lower_disp_limit = pcompress->lopr;
|
||||
pgd->upper_alarm_limit = 0.0;
|
||||
pgd->upper_warning_limit = 0.0;
|
||||
pgd->lower_warning_limit = 0.0;
|
||||
pgd->lower_alarm_limit = 0.0;
|
||||
return(0L);
|
||||
}
|
||||
static long get_control_double(paddr,pcd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_ctrlDouble *pcd;
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord *)paddr->precord;
|
||||
|
||||
pgd->upper_disp_limit = pcompress->hopr;
|
||||
pgd->lower_disp_limit = pcompress->lopr;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord *)(paddr->precord);
|
||||
struct compressdset *pdset = (struct compressdset *)(pcompress->dset);
|
||||
long status;
|
||||
|
||||
pcompress->achn = 0;
|
||||
/* read inputs */
|
||||
if (do_compression(pcompress) < 0){
|
||||
if (pcompress->stat != READ_ALARM){
|
||||
pcompress->stat = READ_ALARM;
|
||||
pcompress->sevr = MAJOR_ALARM;
|
||||
pcompress->achn = 1;
|
||||
monitor_compress(pcompress);
|
||||
}
|
||||
pcompress->pact = 0;
|
||||
return(0);
|
||||
}else{
|
||||
if (pcompress->stat == READ_ALARM){
|
||||
pcompress->stat = NO_ALARM;
|
||||
pcompress->sevr = NO_ALARM;
|
||||
pcompress->achn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* check event list */
|
||||
if(!pcompress->disa) status = monitor(pcompress);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (pcompress->flnk.type==DB_LINK) dbScanPassive(&pcompress->flnk.value);
|
||||
|
||||
pcompress->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long monitor(pcompress)
|
||||
struct compressRecord *pcompress;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
float delta;
|
||||
|
||||
/* anyone wcompressting for an event on this record */
|
||||
if (pcompress->mlis.count == 0) return(0L);
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (pcompress->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(pcompress,&pcompress->stat,DBE_VALUE);
|
||||
db_post_events(pcompress,&pcompress->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
pcompress->mlst = pcompress->val;
|
||||
}
|
||||
monitor_mask |= DBE_LOG|DBE_VALUE;
|
||||
db_post_events(pcompress,&pcompress->val,monitor_mask);
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long do_compression(pcompress)
|
||||
struct compress *pcompress;
|
||||
{
|
||||
struct dbAddr *pdbAddr = (struct dbAddr *)(pcompress->inp.value.db_link.pdbAddr);
|
||||
long options=0;
|
||||
long no_elements=pdbAddr->no_elements;
|
||||
|
||||
if (pcompress->inp.type != DB_LINK) return(0);
|
||||
if (pcompress->wptr == NULL) return(-1);
|
||||
if(status=dbGetLink(&(pcompress->inp),DBR_FLOAT,pcompress->wprt,&options,&no_elements);
|
||||
|
||||
if(pdbAddr->no_elements>1) {
|
||||
compress_array(pcompress,no_elements);
|
||||
}else if(no_elements==1){
|
||||
compress_value(pcompress);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
compress_array(pcompress,no_elements)
|
||||
struct compress *pcompress;
|
||||
long no_elements;
|
||||
{
|
||||
long i,j;
|
||||
int buff_size;
|
||||
float *psource=pcompress->wptr;
|
||||
short *off=&(pcompress->off);
|
||||
short nsam=pconpress->nsam;
|
||||
float *pdest;
|
||||
float value;
|
||||
|
||||
/* for all algorithms but AVERAGE apply the front end filter */
|
||||
if (pcompress->alg != AVERAGE){
|
||||
/* skip out of limit data */
|
||||
if ((pcompress->ilil != 0.0) || (pcompress->ihil != 0.0)){
|
||||
while (((*psource < pcompress->ilil)
|
||||
|| (*psource > pcompress->ihil))
|
||||
&& (no_elements > 0)){
|
||||
no_elements--;
|
||||
psource++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* determine number of samples to take */
|
||||
if ((no_elements - *off) < (pcompress->nsam * pcompress->n)){
|
||||
buff_size = (no_elements / pcompress->n);
|
||||
}else{
|
||||
buff_size = pcompress->nsam;
|
||||
}
|
||||
|
||||
/* destination pointer */
|
||||
pdest = pcompress->bptr + pcompress->off;
|
||||
|
||||
/* compress according to specified algorithm */
|
||||
switch (pcompress->alg){
|
||||
case (NTO1LOW):
|
||||
/* compress N to 1 keeping the lowest value */
|
||||
for (i = 0; i < buff_size; i++){
|
||||
value = *psource++;
|
||||
for (j = 1; j < pcompress->n; j++, psource++){
|
||||
if (value > *psource)
|
||||
value = *psource;
|
||||
}
|
||||
*pdest = value;
|
||||
if( (*off)++ <nsam) {
|
||||
pdest++;
|
||||
} else {
|
||||
pdest = pcompress->bptr;
|
||||
*off=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case (NTO1HIGH):
|
||||
/* compress N to 1 keeping the highest value */
|
||||
for (i = 0; i < buff_size; i++){
|
||||
value = *psource++;
|
||||
for (j = 1; j < pcompress->n; j++, psource++){
|
||||
if (value < *psource)
|
||||
value = *psource;
|
||||
}
|
||||
*pdest = value;
|
||||
if( (*off)++ <nsam) {
|
||||
pdest++;
|
||||
} else {
|
||||
pdest = pcompress->bptr;
|
||||
*off=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case (NTO1AVG):
|
||||
/* compress N to 1 keeping the average value */
|
||||
i = 0;
|
||||
for (i = 0; i < buff_size; i++){
|
||||
value = 0;
|
||||
for (j = 0; j < pcompress->n; j++, psource++){
|
||||
value += *psource;
|
||||
}
|
||||
*pdest = value / j;
|
||||
if( (*off)++ <nsam) {
|
||||
pdest++;
|
||||
} else {
|
||||
pdest = pcompress->bptr;
|
||||
*off=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case (AVERAGE):
|
||||
{
|
||||
register float *psum;
|
||||
register int divider;
|
||||
|
||||
psum = (float *)pcompress->sptr;
|
||||
|
||||
/* add in the new waveform */
|
||||
if (pcompress->mdct == pcompress->mcnt ||
|
||||
pcompress->mdct == 0){
|
||||
for (i = 0; i < buff_size; i++, psource++, psum++)
|
||||
*psum = *psource;
|
||||
}else{
|
||||
for (i = 0; i < buff_size; i++, psource++, psum++)
|
||||
*psum += *psource;
|
||||
}
|
||||
|
||||
/* do we need to calculate the result */
|
||||
if (pcompress->mdct == 1){
|
||||
psum = (float *)pcompress->sptr;
|
||||
divider = pcompress->mcnt;
|
||||
for (i = 0; i < buff_size; i++, psum++) {
|
||||
*pdest = *psum / divider;
|
||||
if( (*off)++ <nsam) {
|
||||
pdest++;
|
||||
} else {
|
||||
pdest = pcompress->bptr;
|
||||
*off=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} /* end case average */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static compress_value(pcompress)
|
||||
register struct compress *pcompress;
|
||||
{
|
||||
float value = *pcompress->wptr;;
|
||||
short inx;
|
||||
|
||||
|
||||
float *pdest;
|
||||
|
||||
/* compress according to specified algorithm */
|
||||
switch (pcompress->alg){
|
||||
case (NTO1LOW):
|
||||
pdest = pcompress->bptr + pcompress->inx;
|
||||
if ((value < *pdest) || (pcompress->ccnt == 0))
|
||||
*pdest = value;
|
||||
pcompress->ccnt++;
|
||||
if (pcompress->ccnt >= pcompress->n){
|
||||
pcompress->ccnt = 0;
|
||||
if (++pcompress->inx >= pcompress->nsam)
|
||||
pcompress->inx = 0;
|
||||
}
|
||||
break;
|
||||
case (NTO1HIGH):
|
||||
pdest = pcompress->bptr + pcompress->inx;
|
||||
if ((value > *pdest) || (pcompress->ccnt == 0))
|
||||
*pdest = value;
|
||||
pcompress->ccnt++;
|
||||
if (pcompress->ccnt >= pcompress->n){
|
||||
pcompress->ccnt = 0;
|
||||
if (++pcompress->inx >= pcompress->nsam)
|
||||
pcompress->inx = 0;
|
||||
}
|
||||
break;
|
||||
case (NTO1AVG):
|
||||
if (pcompress->ccnt == 0)
|
||||
pcompress->sum = value;
|
||||
else
|
||||
pcompress->sum += value;
|
||||
pcompress->ccnt++;
|
||||
if (pcompress->ccnt >= pcompress->n){
|
||||
pdest=pcompress->bptr + pcompress->inx;
|
||||
*pdest = pcompress->sum / pcompress->n;
|
||||
pcompress->ccnt = 0;
|
||||
if (++pcompress->inx >= pcompress->nsam)
|
||||
pcompress->inx = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
115
src/rec/recFanout.c
Normal file
115
src/rec/recFanout.c
Normal file
@ -0,0 +1,115 @@
|
||||
|
||||
/* recFanout.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recFanout.c - Record Support Routines for Fanout records
|
||||
*
|
||||
* Author: Marty Kraimer
|
||||
* Date: 10/10/90
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 10-10-90 mrk extensible record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <fanoutRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
#define init_record NULL
|
||||
long process();
|
||||
#define special NULL
|
||||
#define get_precision NULL
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_enum_str NULL
|
||||
#define get_units NULL
|
||||
#define get_graphic_double NULL
|
||||
#define get_control_double NULL
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset fanoutRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct fanoutRecord *pfanout=(struct fanoutRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(recGblReportLink(fp,"LNK1",&(pfanout->lnk1))) return(-1);
|
||||
if(recGblReportLink(fp,"LNK2",&(pfanout->lnk2))) return(-1);
|
||||
if(recGblReportLink(fp,"LNK3",&(pfanout->lnk3))) return(-1);
|
||||
if(recGblReportLink(fp,"LNK4",&(pfanout->lnk4))) return(-1);
|
||||
if(recGblReportLink(fp,"LNK5",&(pfanout->lnk5))) return(-1);
|
||||
if(recGblReportLink(fp,"LNK6",&(pfanout->lnk6))) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct fanoutRecord *pfanout=(struct fanoutRecord *)(paddr->precord);
|
||||
|
||||
if (pfanout->lnk1.type==DB_LINK) dbScanPassive(&pfanout->lnk1.value);
|
||||
if (pfanout->lnk2.type==DB_LINK) dbScanPassive(&pfanout->lnk2.value);
|
||||
if (pfanout->lnk3.type==DB_LINK) dbScanPassive(&pfanout->lnk3.value);
|
||||
if (pfanout->lnk4.type==DB_LINK) dbScanPassive(&pfanout->lnk4.value);
|
||||
if (pfanout->lnk5.type==DB_LINK) dbScanPassive(&pfanout->lnk5.value);
|
||||
if (pfanout->lnk6.type==DB_LINK) dbScanPassive(&pfanout->lnk6.value);
|
||||
pfanout->pact=FALSE;
|
||||
return(0);
|
||||
}
|
356
src/rec/recMbbi.c
Normal file
356
src/rec/recMbbi.c
Normal file
@ -0,0 +1,356 @@
|
||||
|
||||
/* recMbbi.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recMbbi.c - Record Support Routines for multi bit binary Input records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 5-9-88
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 12-12-88 lrd lock the record while processing
|
||||
* .02 12-15-88 lrd Process the forward scan link
|
||||
* .03 12-23-88 lrd Alarm on locked MAX_LOCKED times
|
||||
* .04 01-13-89 lrd delete db_read_mbbi
|
||||
* .05 03-29-89 lrd make hardware errors MAJOR
|
||||
* remove hw severity spec from database
|
||||
* .06 04-07-89 lrd add monitor detection
|
||||
* .07 05-03-89 lrd removed process mask from arg list
|
||||
* .08 05-29-89 lrd support 16 states
|
||||
* .09 05-30-89 lrd fixed masks for allen-bradley IO
|
||||
* .10 06-06-89 lrd fixed AB mbbi conversion - signal wrong
|
||||
* added ability to enter raw numbers if no
|
||||
* states are defined - like the mbbo
|
||||
* .11 12-06-89 lrd add database fetch support
|
||||
* .12 02-08-90 lrd add Allen-Bradley PLC support
|
||||
* .13 10-11-90 mrk changes for new record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
#include <strLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <mbbiRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
long special();
|
||||
long get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
long get_enum_str();
|
||||
#define get_units NULL
|
||||
#define get_graphic_double NULL
|
||||
#define get_control_double NULL
|
||||
long get_enum_strs();
|
||||
|
||||
struct rset mbbiRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
struct mbbidset { /* multi bit binary input dset */
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN read_mbbi;/*(-1,0,1)=>(failure,success,don't Continue*/
|
||||
};
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct mbbiRecord *pmbbi=(struct mbbiRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %d\n",pmbbi->val)) return(-1);
|
||||
if(recGblReportLink(fp,"INP ",&(pmbbi->inp))) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(pmbbi->flnk))) return(-1);
|
||||
if(fprintf(fp,"RVAL 0x%-8X\n",
|
||||
pmbbi->rval)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long init_record(pmbbi)
|
||||
struct mbbiRecord *pmbbi;
|
||||
{
|
||||
struct mbbidset *pdset;
|
||||
long status;
|
||||
|
||||
if(!(pdset = (struct mbbidset *)(pmbbi->dset))) {
|
||||
recGblRecordError(S_dev_noDSET,pmbbi,"mbbi: init_record");
|
||||
return(S_dev_noDSET);
|
||||
}
|
||||
/* must have read_mbbi function defined */
|
||||
if( (pdset->number < 5) || (pdset->read_mbbi == NULL) ) {
|
||||
recGblRecordError(S_dev_missingSup,pmbbi,"mbbi: init_record");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
if( pdset->init_record ) {
|
||||
if((status=(*pdset->init_record)(pmbbi))) return(status);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct mbbiRecord *pmbbi=(struct mbbiRecord *)(paddr->precord);
|
||||
struct mbbidset *pdset = (struct mbbidset *)(pmbbi->dset);
|
||||
long status;
|
||||
unsigned long *pstate_values;
|
||||
short i,states_defined;
|
||||
|
||||
if( (pdset==NULL) || (pdset->read_mbbi==NULL) ) {
|
||||
pmbbi->pact=TRUE;
|
||||
recGblRecordError(S_dev_missingSup,pmbbi,"read_mbbi");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
|
||||
status=(*pdset->read_mbbi)(pmbbi); /* read the new value */
|
||||
pmbbi->pact = TRUE;
|
||||
|
||||
/* status is one if an asynchronous record is being processed*/
|
||||
if(status==1) return(1);
|
||||
else if(status == -1) {
|
||||
if(pmbbi->stat != READ_ALARM) {/* error. set alarm condition */
|
||||
pmbbi->stat = READ_ALARM;
|
||||
pmbbi->sevr = MAJOR_ALARM;
|
||||
pmbbi->achn=1;
|
||||
}
|
||||
}
|
||||
else if(status!=0) return(status);
|
||||
else if(pmbbi->stat == READ_ALARM) {
|
||||
pmbbi->stat = NO_ALARM;
|
||||
pmbbi->sevr = NO_ALARM;
|
||||
pmbbi->achn=1;
|
||||
}
|
||||
|
||||
/* determine if any states are defined */
|
||||
pstate_values = &(pmbbi->zrvl);
|
||||
states_defined = 0;
|
||||
for (i=0; (i<16) && (!states_defined); i++)
|
||||
if (*(pstate_values+i)) states_defined = 1;
|
||||
|
||||
/* convert the value */
|
||||
if (states_defined){
|
||||
pstate_values = &(pmbbi->zrvl);
|
||||
for (i = 0; i < 16; i++){
|
||||
if (*pstate_values == pmbbi->rval){
|
||||
pmbbi->val = i;
|
||||
return(0);
|
||||
}
|
||||
pstate_values++;
|
||||
}
|
||||
pmbbi->val = -2; /* unknown state-other than init LALM */
|
||||
}else{
|
||||
/* the raw value is the desired value */
|
||||
pmbbi->val = pmbbi->rval;
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
alarm(pmbbi);
|
||||
|
||||
|
||||
/* check event list */
|
||||
if(!pmbbi->disa) status = monitor(pmbbi);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (pmbbi->flnk.type==DB_LINK) dbScanPassive(&pmbbi->flnk.value);
|
||||
|
||||
pmbbi->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long get_value(pmbbi,pvdes)
|
||||
struct mbbiRecord *pmbbi;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_ENUM;
|
||||
pvdes->no_elements=1;
|
||||
(unsigned short *)(pvdes->pvalue) = &pmbbi->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_enum_str(paddr,pstring)
|
||||
struct dbAddr *paddr;
|
||||
char *pstring;
|
||||
{
|
||||
struct mbbiRecord *pmbbi=(struct mbbiRecord *)paddr->precord;
|
||||
char *psource;
|
||||
unsigned short val=pmbbi->val;
|
||||
|
||||
if( val>0 && val<= 15) {
|
||||
psource = (pmbbi->zrst);
|
||||
psource += (val * sizeof(pmbbi->zrst));
|
||||
strncpy(pstring,psource,sizeof(pmbbi->zrst));
|
||||
} else {
|
||||
strcpy(pstring,"Illegal Value");
|
||||
}
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_enum_strs(paddr,pes)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_enumStrs *pes;
|
||||
{
|
||||
struct mbbiRecord *pmbbi=(struct mbbiRecord *)paddr->precord;
|
||||
char *psource;
|
||||
int i;
|
||||
|
||||
pes->no_str = 16;
|
||||
bzero(pes->strs,sizeof(pes->strs));
|
||||
for(i=0,psource=(pmbbi->zrst); i<15; i++, psource += sizeof(pmbbi->zrst) )
|
||||
strncpy(pes->strs[i],pmbbi->zrst,sizeof(pmbbi->zrst));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long alarm(pmbbi)
|
||||
struct mbbiRecord *pmbbi;
|
||||
{
|
||||
float ftemp;
|
||||
unsigned short *severities;
|
||||
|
||||
/* check for a hardware alarm */
|
||||
if (pmbbi->stat == READ_ALARM) return(0);
|
||||
|
||||
if (pmbbi->val == pmbbi->lalm){
|
||||
/* no new message for COS alarms */
|
||||
if (pmbbi->stat == COS_ALARM){
|
||||
pmbbi->stat = NO_ALARM;
|
||||
pmbbi->sevr = NO_ALARM;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* set last alarmed value */
|
||||
pmbbi->lalm = pmbbi->val;
|
||||
|
||||
/* check for state alarm */
|
||||
/* unknown state */
|
||||
if ((pmbbi->val < 0) || (pmbbi->val > 15)){
|
||||
if (pmbbi->unsv != NO_ALARM){
|
||||
pmbbi->stat = STATE_ALARM;
|
||||
pmbbi->sevr = pmbbi->unsv;
|
||||
pmbbi->achn = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* in a state which is an error */
|
||||
severities = (unsigned short *)&(pmbbi->zrsv);
|
||||
if (severities[pmbbi->val] != NO_ALARM){
|
||||
pmbbi->stat = STATE_ALARM;
|
||||
pmbbi->sevr = severities[pmbbi->val];
|
||||
pmbbi->achn = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for cos alarm */
|
||||
if (pmbbi->cosv != NO_ALARM){
|
||||
pmbbi->sevr = pmbbi->cosv;
|
||||
pmbbi->stat = COS_ALARM;
|
||||
pmbbi->achn = 1;
|
||||
return;
|
||||
}
|
||||
/* check for change from alarm to no alarm */
|
||||
if (pmbbi->sevr != NO_ALARM){
|
||||
pmbbi->sevr = NO_ALARM;
|
||||
pmbbi->stat = NO_ALARM;
|
||||
pmbbi->achn = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long monitor(pmbbi)
|
||||
struct mbbiRecord *pmbbi;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
|
||||
/* anyone waiting for an event on this record */
|
||||
if (pmbbi->mlis.count == 0) return(0L);
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (pmbbi->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE | DBE_LOG;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(pmbbi,&pmbbi->stat,DBE_VALUE);
|
||||
db_post_events(pmbbi,&pmbbi->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
pmbbi->mlst = pmbbi->val;
|
||||
/* check for value change */
|
||||
}else if (pmbbi->mlst != pmbbi->val){
|
||||
/* post events for value change and archive change */
|
||||
monitor_mask |= (DBE_VALUE | DBE_LOG);
|
||||
|
||||
/* update last value monitored */
|
||||
pmbbi->mlst = pmbbi->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(pmbbi,&pmbbi->val,monitor_mask);
|
||||
db_post_events(pmbbi,&pmbbi->rval,monitor_mask);
|
||||
}
|
||||
return(0L);
|
||||
}
|
362
src/rec/recMbbo.c
Normal file
362
src/rec/recMbbo.c
Normal file
@ -0,0 +1,362 @@
|
||||
|
||||
/* recMbbo.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recMbbo.c - Record Support Routines for multi bit binary Output records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 7-17-87
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 11-28-88 lrd add desired value fetched
|
||||
* .02 12-12-88 lrd lock the record while processing
|
||||
* .03 12-15-88 lrd Process the forward scan link
|
||||
* .04 12-23-88 lrd Alarm on locked MAX_LOCKED times
|
||||
* .05 01-09-89 lrd Fix direct value outputs so that they shift the
|
||||
* value into the correct bit position
|
||||
* .06 01-13-89 lrd delete db_write_mbbo and db_write_mbbo
|
||||
* .07 01-20-89 lrd fixed vx inlcudes
|
||||
* .08 03-03-89 lrd add supervisory/closed loop control
|
||||
* .09 03-29-89 lrd make hardware errors MAJOR
|
||||
* remove hw severity spec from database
|
||||
* .10 04-07-89 lrd add monitor service
|
||||
* .11 05-03-89 lrd removed process mask from arg list
|
||||
* .12 05-30-89 lrd fixed mask for allen-bradley IO
|
||||
* .13 01-05-90 joh,lrd fixed write_mbbo() to set rval
|
||||
* .14 02-08-90 lrd/cr fixed the mbbo to read at initialization for
|
||||
* Allen-Bradley and added PLC support
|
||||
* .15 04-11-90 lrd make locals static
|
||||
* .16 10-11-90 mrk make changes for new record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
#include <strLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <mbboRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
long special();
|
||||
long get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
long get_enum_str();
|
||||
#define get_units NULL
|
||||
#define get_graphic_double NULL
|
||||
#define get_control_double NULL
|
||||
long get_enum_strs();
|
||||
|
||||
struct rset mbboRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
struct mbbodset { /* multi bit binary input dset */
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN write_mbbo;/*(-1,0,1)=>(failure,success,don't Continue*/
|
||||
};
|
||||
|
||||
/* the following definitions must match those in choiceGbl.ascii */
|
||||
#define OUTPUT_FULL 0
|
||||
#define CLOSED_LOOP 1
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct mbboRecord *pmbbo=(struct mbboRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %d\n",pmbbo->val)) return(-1);
|
||||
if(recGblReportLink(fp,"OUT ",&(pmbbo->out))) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(pmbbo->flnk))) return(-1);
|
||||
if(fprintf(fp,"RVAL 0x%-8X\n",
|
||||
pmbbo->rval)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long init_record(pmbbo)
|
||||
struct mbboRecord *pmbbo;
|
||||
{
|
||||
struct mbbodset *pdset;
|
||||
long status;
|
||||
|
||||
if(!(pdset = (struct mbbodset *)(pmbbo->dset))) {
|
||||
recGblRecordError(S_dev_noDSET,pmbbo,"mbbo: init_record");
|
||||
return(S_dev_noDSET);
|
||||
}
|
||||
/* must have write_mbbo function defined */
|
||||
if( (pdset->number < 5) || (pdset->write_mbbo == NULL) ) {
|
||||
recGblRecordError(S_dev_missingSup,pmbbo,"mbbo: init_record");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
if( pdset->init_record ) {
|
||||
if((status=(*pdset->init_record)(pmbbo))) return(status);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct mbboRecord *pmbbo=(struct mbboRecord *)(paddr->precord);
|
||||
struct mbbodset *pdset = (struct mbbodset *)(pmbbo->dset);
|
||||
long status;
|
||||
unsigned long *pvalues;
|
||||
short states_defined,i;
|
||||
|
||||
if( (pdset==NULL) || (pdset->write_mbbo==NULL) ) {
|
||||
pmbbo->pact=TRUE;
|
||||
recGblRecordError(S_dev_missingSup,pmbbo,"write_mbbo");
|
||||
return(S_dev_missingSup);
|
||||
}
|
||||
|
||||
status=(*pdset->write_mbbo)(pmbbo); /* read the new value */
|
||||
pmbbo->pact = TRUE;
|
||||
|
||||
/* status is one if an asynchronous record is being processed*/
|
||||
if(status==1) return(1);
|
||||
else if(status == -1) {
|
||||
if(pmbbo->stat != READ_ALARM) {/* error. set alarm condition */
|
||||
pmbbo->stat = READ_ALARM;
|
||||
pmbbo->sevr = MAJOR_ALARM;
|
||||
pmbbo->achn=1;
|
||||
}
|
||||
}
|
||||
else if(status!=0) return(status);
|
||||
else if(pmbbo->stat == READ_ALARM) {
|
||||
pmbbo->stat = NO_ALARM;
|
||||
pmbbo->sevr = NO_ALARM;
|
||||
pmbbo->achn=1;
|
||||
}
|
||||
|
||||
/* determine if any states are defined */
|
||||
pvalues = &(pmbbo->zrvl);
|
||||
states_defined = FALSE;
|
||||
for (i=0; (i<16) && (!states_defined); i++)
|
||||
if (*(pvalues+i)) states_defined = TRUE;
|
||||
|
||||
/* convert the value */
|
||||
if (states_defined){
|
||||
pvalues = (unsigned long *)&(pmbbo->zrvl);
|
||||
pmbbo->rbv = -1; /* initialize to unknown state */
|
||||
for (i = 0; i < 16; i++,pvalues++){
|
||||
if (*pvalues == pmbbo->rval){
|
||||
pmbbo->rbv = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pmbbo->rbv = pmbbo->rval;
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
alarm(pmbbo);
|
||||
|
||||
|
||||
/* check event list */
|
||||
if(!pmbbo->disa) status = monitor(pmbbo);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (pmbbo->flnk.type==DB_LINK) dbScanPassive(&pmbbo->flnk.value);
|
||||
|
||||
pmbbo->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long get_value(pmbbo,pvdes)
|
||||
struct mbboRecord *pmbbo;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_ENUM;
|
||||
pvdes->no_elements=1;
|
||||
(unsigned short *)(pvdes->pvalue) = &pmbbo->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_enum_str(paddr,pstring)
|
||||
struct dbAddr *paddr;
|
||||
char *pstring;
|
||||
{
|
||||
struct mbboRecord *pmbbo=(struct mbboRecord *)paddr->precord;
|
||||
char *psource;
|
||||
unsigned short val=pmbbo->val;
|
||||
|
||||
if( val>0 && val<= 15) {
|
||||
psource = (pmbbo->zrst);
|
||||
psource += (val * sizeof(pmbbo->zrst));
|
||||
strncpy(pstring,psource,sizeof(pmbbo->zrst));
|
||||
} else {
|
||||
strcpy(pstring,"Illegal Value");
|
||||
}
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_enum_strs(paddr,pes)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_enumStrs *pes;
|
||||
{
|
||||
struct mbboRecord *pmbbo=(struct mbboRecord *)paddr->precord;
|
||||
char *psource;
|
||||
int i;
|
||||
|
||||
pes->no_str = 16;
|
||||
bzero(pes->strs,sizeof(pes->strs));
|
||||
for(i=0,psource=(pmbbo->zrst); i<15; i++, psource += sizeof(pmbbo->zrst) )
|
||||
strncpy(pes->strs[i],pmbbo->zrst,sizeof(pmbbo->zrst));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long alarm(pmbbo)
|
||||
struct mbboRecord *pmbbo;
|
||||
{
|
||||
float ftemp;
|
||||
unsigned short *severities;
|
||||
|
||||
/* check for a hardware alarm */
|
||||
if (pmbbo->stat == READ_ALARM) return(0);
|
||||
if (pmbbo->stat == WRITE_ALARM) return(0);
|
||||
|
||||
if (pmbbo->val == pmbbo->lalm){
|
||||
/* no new message for COS alarms */
|
||||
if (pmbbo->stat == COS_ALARM){
|
||||
pmbbo->stat = NO_ALARM;
|
||||
pmbbo->sevr = NO_ALARM;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* set last alarmed value */
|
||||
pmbbo->lalm = pmbbo->val;
|
||||
|
||||
/* check for state alarm */
|
||||
/* unknown state */
|
||||
if ((pmbbo->val < 0) || (pmbbo->val > 15)){
|
||||
if (pmbbo->unsv != NO_ALARM){
|
||||
pmbbo->stat = STATE_ALARM;
|
||||
pmbbo->sevr = pmbbo->unsv;
|
||||
pmbbo->achn = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* in a state which is an error */
|
||||
severities = (unsigned short *)&(pmbbo->zrsv);
|
||||
if (severities[pmbbo->val] != NO_ALARM){
|
||||
pmbbo->stat = STATE_ALARM;
|
||||
pmbbo->sevr = severities[pmbbo->val];
|
||||
pmbbo->achn = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for cos alarm */
|
||||
if (pmbbo->cosv != NO_ALARM){
|
||||
pmbbo->sevr = pmbbo->cosv;
|
||||
pmbbo->stat = COS_ALARM;
|
||||
pmbbo->achn = 1;
|
||||
return;
|
||||
}
|
||||
/* check for change from alarm to no alarm */
|
||||
if (pmbbo->sevr != NO_ALARM){
|
||||
pmbbo->sevr = NO_ALARM;
|
||||
pmbbo->stat = NO_ALARM;
|
||||
pmbbo->achn = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long monitor(pmbbo)
|
||||
struct mbboRecord *pmbbo;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
|
||||
/* anyone waiting for an event on this record */
|
||||
if (pmbbo->mlis.count == 0) return(0L);
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (pmbbo->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE | DBE_LOG;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(pmbbo,&pmbbo->stat,DBE_VALUE);
|
||||
db_post_events(pmbbo,&pmbbo->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
pmbbo->mlst = pmbbo->val;
|
||||
/* check for value change */
|
||||
}else if (pmbbo->mlst != pmbbo->val){
|
||||
/* post events for value change and archive change */
|
||||
monitor_mask |= (DBE_VALUE | DBE_LOG);
|
||||
|
||||
/* update last value monitored */
|
||||
pmbbo->mlst = pmbbo->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(pmbbo,&pmbbo->val,monitor_mask);
|
||||
db_post_events(pmbbo,&pmbbo->rval,monitor_mask);
|
||||
}
|
||||
return(0L);
|
||||
}
|
107
src/rec/recPermissive.c
Normal file
107
src/rec/recPermissive.c
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
/* recPermissive.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recPermissive.c - Record Support Routines for Permissive records
|
||||
*
|
||||
* Author: Marty Kraimer
|
||||
* Date: 10/10/90
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 10-10-90 mrk extensible record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <permissiveRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
#define init_record NULL
|
||||
long process();
|
||||
#define special NULL
|
||||
#define get_precision NULL
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_enum_str NULL
|
||||
#define get_units NULL
|
||||
#define get_graphic_double NULL
|
||||
#define get_control_double NULL
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset permissiveRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct permissiveRecord *ppermissive=(struct permissiveRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"LABL %s\n",ppermissive->labl)) return(-1);
|
||||
if(fprintf(fp,"VAL %d\n",ppermissive->val)) return(-1);
|
||||
if(fprintf(fp,"WFLG %d\n",ppermissive->wflg)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct permissiveRecord *ppermissive=(struct permissiveRecord *)(paddr->precord);
|
||||
/* anyone waiting for an event on this record */
|
||||
ppermissive->pact=FALSE;
|
||||
return(0);
|
||||
}
|
409
src/rec/recPid.c
Normal file
409
src/rec/recPid.c
Normal file
@ -0,0 +1,409 @@
|
||||
|
||||
/* recPid.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recPid.c - Record Support Routines for Pid records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 05-19-89
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 10-15-90 mrk changes for new record support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <pidRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
#define special NULL
|
||||
long get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_enum_str NULL
|
||||
long get_units();
|
||||
long get_graphic_double();
|
||||
long get_control_double();
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset pidRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct pidRecord *ppid=(struct pidRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %-12.4G\n",ppid->val)) return(-1);
|
||||
if(recGblReportLink(fp,"INP ",&(ppid->inp))) return(-1);
|
||||
if(fprintf(fp,"PREC %d\n",ppid->prec)) return(-1);
|
||||
if(recGblReportCvtChoice(fp,"LINR",ppid->linr)) return(-1);
|
||||
if(fprintf(fp,"EGUF %-12.4G EGUL %-12.4G EGU %-8s\n",
|
||||
ppid->eguf,ppid->egul,ppid->egu)) return(-1);
|
||||
if(fprintf(fp,"HOPR %-12.4G LOPR %-12.4G\n",
|
||||
ppid->hopr,ppid->lopr)) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(ppid->flnk))) return(-1);
|
||||
if(fprintf(fp,"HIHI %-12.4G HIGH %-12.4G LOW %-12.4G LOLO %-12.4G\n",
|
||||
ppid->hihi,ppid->high,ppid->low,ppid->lolo)) return(-1);
|
||||
if(recGblReportGblChoice(fp,ppid,"HHSV",ppid->hhsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,ppid,"HSV ",ppid->hsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,ppid,"LSV ",ppid->lsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,ppid,"LLSV",ppid->llsv)) return(-1);
|
||||
if(fprintf(fp,"HYST %-12.4G ADEL %-12.4G MDEL %-12.4G ESLO %-12.4G\n",
|
||||
ppid->hyst,ppid->adel,ppid->mdel,ppid->eslo)) return(-1);
|
||||
if(fprintf(fp,"ACHN %d\n", ppid->achn)) return(-1);
|
||||
if(fprintf(fp,"LALM %-12.4G ALST %-12.4G MLST %-12.4G\n",
|
||||
ppid->lalm,ppid->alst,ppid->mlst)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
^L
|
||||
static pid_intervals[] = {1,5,4,3,2,1,1,1};
|
||||
|
||||
static long init_record(ppid)
|
||||
struct pidRecord *ppid;
|
||||
{
|
||||
/* get the interval based on the scan type */
|
||||
ppid->intv = pid_intervals[ppid->scan];
|
||||
|
||||
/* initialize the setpoint for constant setpoint */
|
||||
if (ppid->stpl.type == CONSTANT)
|
||||
ppid->val = ppid->stpl.value.value;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct pidRecord *ppid=(struct pidRecord *)(paddr->precord);
|
||||
long status;
|
||||
|
||||
ppid->pact = TRUE;
|
||||
status=do_pid(ppid);
|
||||
if(status == -1) {
|
||||
if(ppid->stat != READ_ALARM) {/* error. set alarm condition */
|
||||
ppid->stat = READ_ALARM;
|
||||
ppid->sevr = MAJOR_ALARM;
|
||||
ppid->achn=1;
|
||||
}
|
||||
}else if(status!=0) return(status);
|
||||
else if(ppid->stat == READ_ALARM || ppid->stat == HW_LIMIT_ALARM) {
|
||||
ppid->stat = NO_ALARM;
|
||||
ppid->sevr = NO_ALARM;
|
||||
ppid->achn=1;
|
||||
}
|
||||
if(status==0) do_pidect(ppid);
|
||||
|
||||
/* check for alarms */
|
||||
alarm(ppid);
|
||||
|
||||
|
||||
/* check event list */
|
||||
monitor(ppid);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (ppid->flnk.type==DB_LINK) dbScanPassive(&ppid->flnk.value);
|
||||
|
||||
ppid->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long get_precision(paddr,precision)
|
||||
struct dbAddr *paddr;
|
||||
long *precision;
|
||||
{
|
||||
struct pidRecord *ppid=(struct pidRecord *)paddr->precord;
|
||||
|
||||
*precision = ppid->prec;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_value(ppid,pvdes)
|
||||
struct pidRecord *ppid;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_FLOAT;
|
||||
pvdes->no_elements=1;
|
||||
(float *)(pvdes->pvalue) = &ppid->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_units(paddr,units)
|
||||
struct dbAddr *paddr;
|
||||
char *units;
|
||||
{
|
||||
struct pidRecord *ppid=(struct pidRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,ppid->egu,sizeof(ppid->egu));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_graphic_double(paddr,pgd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_grDouble *pgd;
|
||||
{
|
||||
struct pidRecord *ppid=(struct pidRecord *)paddr->precord;
|
||||
|
||||
pgd->upper_disp_limit = ppid->hopr;
|
||||
pgd->lower_disp_limit = ppid->lopr;
|
||||
pgd->upper_alarm_limit = ppid->hihi;
|
||||
pgd->upper_warning_limit = ppid->high;
|
||||
pgd->lower_warning_limit = ppid->low;
|
||||
pgd->lower_alarm_limit = ppid->lolo;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_control_double(paddr,pcd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_ctrlDouble *pcd;
|
||||
{
|
||||
struct pidRecord *ppid=(struct pidRecord *)paddr->precord;
|
||||
|
||||
pcd->upper_ctrl_limit = ppid->hopr;
|
||||
pcd->lower_ctrl_limit = ppid->lopr;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static void alarm(ppid)
|
||||
struct pidRecord *ppid;
|
||||
{
|
||||
float ftemp;
|
||||
|
||||
/* check for a hardware alarm */
|
||||
if (ppid->stat == READ_ALARM) return(0);
|
||||
|
||||
/* if in alarm and difference is not > hysterisis don't bother */
|
||||
if (ppid->stat != NO_ALARM){
|
||||
ftemp = ppid->lalm - ppid->val;
|
||||
if(ftemp<0.0) ftemp = -ftemp;
|
||||
if (ftemp < ppid->hyst) return;
|
||||
}
|
||||
|
||||
/* alarm condition hihi */
|
||||
if (ppid->hhsv != NO_ALARM){
|
||||
if (ppid->val > ppid->hihi){
|
||||
ppid->lalm = ppid->val;
|
||||
if (ppid->stat != HIHI_ALARM){
|
||||
ppid->stat = HIHI_ALARM;
|
||||
ppid->sevr = ppid->hhsv;
|
||||
ppid->achn = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (ppid->llsv != NO_ALARM){
|
||||
if (ppid->val < ppid->lolo){
|
||||
ppid->lalm = ppid->val;
|
||||
if (ppid->stat != LOLO_ALARM){
|
||||
ppid->stat = LOLO_ALARM;
|
||||
ppid->sevr = ppid->llsv;
|
||||
ppid->achn = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition high */
|
||||
if (ppid->hsv != NO_ALARM){
|
||||
if (ppid->val > ppid->high){
|
||||
ppid->lalm = ppid->val;
|
||||
if (ppid->stat != HIGH_ALARM){
|
||||
ppid->stat = HIGH_ALARM;
|
||||
ppid->sevr =ppid->hsv;
|
||||
ppid->achn = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (ppid->lsv != NO_ALARM){
|
||||
if (ppid->val < ppid->low){
|
||||
ppid->lalm = ppid->val;
|
||||
if (ppid->stat != LOW_ALARM){
|
||||
ppid->stat = LOW_ALARM;
|
||||
ppid->sevr = ppid->lsv;
|
||||
ppid->achn = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* no alarm */
|
||||
if (ppid->stat != NO_ALARM){
|
||||
ppid->stat = NO_ALARM;
|
||||
ppid->sevr = NO_ALARM;
|
||||
ppid->achn = 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void monitor(ppid)
|
||||
struct pidRecord *ppid;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
float delta;
|
||||
|
||||
/* anyone waiting for an event on this record */
|
||||
if (ppid->mlis.count == 0) return;
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (ppid->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE | DBE_LOG;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(ppid,&ppid->stat,DBE_VALUE);
|
||||
db_post_events(ppid,&ppid->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
ppid->mlst = ppid->val;
|
||||
|
||||
/* check for value change */
|
||||
}else{
|
||||
delta = ppid->mlst - ppid->val;
|
||||
if(delta<0.0) delta = -delta;
|
||||
if (delta > ppid->mdel) {
|
||||
/* post events for value change */
|
||||
monitor_mask = DBE_VALUE;
|
||||
|
||||
/* update last value monitored */
|
||||
ppid->mlst = ppid->val;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for archive change */
|
||||
delta = ppid->alst - ppid->val;
|
||||
if(delta<0.0) delta = 0.0;
|
||||
if (delta > ppid->adel) {
|
||||
/* post events on value field for archive change */
|
||||
monitor_mask |= DBE_LOG;
|
||||
|
||||
/* update last archive value monitored */
|
||||
ppid->alst = ppid->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(ppid,&ppid->val,monitor_mask);
|
||||
db_post_events(ppid,&ppid->rval,monitor_mask);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static long do_pid(ppid)
|
||||
register struct pid *ppid;
|
||||
{
|
||||
/* fetch the controlled value */
|
||||
if (ppid->cvl.type != DB_LINK) return(-1); /* nothing to control */
|
||||
if (db_fetch(&ppid->cvl.value,&ppid->cval) < 0){
|
||||
if (ppid->stat != READ_ALARM){
|
||||
ppid->stat = READ_ALARM;
|
||||
ppid->sevr = MAJOR;
|
||||
ppid->achn = 1;
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* rate of change on the setpoint? */
|
||||
/* fetch the setpoint */
|
||||
if ((ppid->stpl.type == DB_LINK) && (ppid->smsl == CLOSED_LOOP)){
|
||||
if (db_fetch(&ppid->stpl.value,&ppid->val) < 0){
|
||||
if (ppid->stat != READ_ALARM){
|
||||
ppid->stat = READ_ALARM;
|
||||
ppid->sevr = MAJOR;
|
||||
ppid->achn = 1;
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* reset the integral term when the setpoint changes */
|
||||
if (ppid->val != ppid->lval){
|
||||
ppid->lval = ppid->val;
|
||||
ppid->inte = 0;
|
||||
}
|
||||
|
||||
/* determine the error */
|
||||
ppid->lerr = ppid->err;
|
||||
ppid->err = ppid->val - ppid->cval;
|
||||
ppid->derr = ppid->err - ppid->lerr;
|
||||
|
||||
/* determine the proportional contribution */
|
||||
ppid->prop = ppid->err * ppid->kp;
|
||||
|
||||
/* determine the integral contribution */
|
||||
ppid->inte += ppid->err;
|
||||
ppid->intg = ppid->inte * ppid->ki * ppid->intv;
|
||||
|
||||
/* determine the derivative contribution */
|
||||
/* we are implementing the derivativa term on error - do we want value also? */
|
||||
ppid->der = (ppid->derr * ppid->kd) / ppid->intv;
|
||||
|
||||
/* delta output contributions weighted by the proportional constant */
|
||||
ppid->out = ppid->intg + ppid->der + ppid->prop;
|
||||
|
||||
return(0);
|
||||
}
|
434
src/rec/recSel.c
Normal file
434
src/rec/recSel.c
Normal file
@ -0,0 +1,434 @@
|
||||
|
||||
/* recSel.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recSel.c - Record Support Routines for Select records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 06-02-89
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 11-16-89 lrd fixed select algorithms not to compare against
|
||||
* the previous value
|
||||
*
|
||||
* .02 10-12-90 mrk changes for new record support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <selRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
#define special NULL
|
||||
long get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_enum_str NULL
|
||||
long get_units();
|
||||
long get_graphic_double();
|
||||
long get_control_double();
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset selRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
#define SEL_MAX 6
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct selRecord *psel=(struct selRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %-12.4G\n",psel->val)) return(-1);
|
||||
if(recGblReportLink(fp,"INP ",&(psel->inp))) return(-1);
|
||||
if(fprintf(fp,"PREC %d\n",psel->prec)) return(-1);
|
||||
if(recGblReportCvtChoice(fp,"LINR",psel->linr)) return(-1);
|
||||
if(fprintf(fp,"EGUF %-12.4G EGUL %-12.4G EGU %-8s\n",
|
||||
psel->eguf,psel->egul,psel->egu)) return(-1);
|
||||
if(fprintf(fp,"HOPR %-12.4G LOPR %-12.4G\n",
|
||||
psel->hopr,psel->lopr)) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(psel->flnk))) return(-1);
|
||||
if(fprintf(fp,"HIHI %-12.4G HIGH %-12.4G LOW %-12.4G LOLO %-12.4G\n",
|
||||
psel->hihi,psel->high,psel->low,psel->lolo)) return(-1);
|
||||
if(recGblReportGblChoice(fp,psel,"HHSV",psel->hhsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,psel,"HSV ",psel->hsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,psel,"LSV ",psel->lsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,psel,"LLSV",psel->llsv)) return(-1);
|
||||
if(fprintf(fp,"HYST %-12.4G ADEL %-12.4G MDEL %-12.4G ESLO %-12.4G\n",
|
||||
psel->hyst,psel->adel,psel->mdel,psel->eslo)) return(-1);
|
||||
if(fprintf(fp,"ACHN %d\n", psel->achn)) return(-1);
|
||||
if(fprintf(fp,"LALM %-12.4G ALST %-12.4G MLST %-12.4G\n",
|
||||
psel->lalm,psel->alst,psel->mlst)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
^L
|
||||
static long init_record(psel)
|
||||
struct selRecord *psel;
|
||||
{
|
||||
|
||||
if(psel->inpa.type==CONSTANT) psel->a = psel->inpa.value.value;
|
||||
if(psel->inpb.type==CONSTANT) psel->b = psel->inpb.value.value;
|
||||
if(psel->inpc.type==CONSTANT) psel->c = psel->inpc.value.value;
|
||||
if(psel->inpd.type==CONSTANT) psel->d = psel->inpd.value.value;
|
||||
if(psel->inpe.type==CONSTANT) psel->e = psel->inpe.value.value;
|
||||
if(psel->inpf.type==CONSTANT) psel->f = psel->inpf.value.value;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct selRecord *psel=(struct selRecord *)(paddr->precord);
|
||||
long status;
|
||||
|
||||
psel->pact = TRUE;
|
||||
status=fetch_values(psel);
|
||||
if(status == -1) {
|
||||
if(psel->stat != READ_ALARM) {/* error. set alarm condition */
|
||||
psel->stat = READ_ALARM;
|
||||
psel->sevr = MAJOR_ALARM;
|
||||
psel->achn=1;
|
||||
}
|
||||
}else if(status!=0) return(status);
|
||||
else if(psel->stat == READ_ALARM || psel->stat == HW_LIMIT_ALARM) {
|
||||
psel->stat = NO_ALARM;
|
||||
psel->sevr = NO_ALARM;
|
||||
psel->achn=1;
|
||||
}
|
||||
if(status==0) do_select(psel);
|
||||
|
||||
/* check for alarms */
|
||||
alarm(psel);
|
||||
|
||||
|
||||
/* check event list */
|
||||
if(!psel->disa) status = monitor(psel);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (psel->flnk.type==DB_LINK) dbScanPassive(&psel->flnk.value);
|
||||
|
||||
psel->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
static long get_precision(paddr,precision)
|
||||
struct dbAddr *paddr;
|
||||
long *precision;
|
||||
{
|
||||
struct selRecord *psel=(struct selRecord *)paddr->precord;
|
||||
|
||||
*precision = psel->prec;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_value(psel,pvdes)
|
||||
struct selRecord *psel;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_FLOAT;
|
||||
pvdes->no_elements=1;
|
||||
(float *)(pvdes->pvalue) = &psel->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_units(paddr,units)
|
||||
struct dbAddr *paddr;
|
||||
char *units;
|
||||
{
|
||||
struct selRecord *psel=(struct selRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,psel->egu,sizeof(psel->egu));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_graphic_double(paddr,pgd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_grDouble *pgd;
|
||||
{
|
||||
struct selRecord *psel=(struct selRecord *)paddr->precord;
|
||||
|
||||
pgd->upper_disp_limit = psel->hopr;
|
||||
pgd->lower_disp_limit = psel->lopr;
|
||||
pgd->upper_alarm_limit = psel->hihi;
|
||||
pgd->upper_warning_limit = psel->high;
|
||||
pgd->lower_warning_limit = psel->low;
|
||||
pgd->lower_alarm_limit = psel->lolo;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_control_double(paddr,pcd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_ctrlDouble *pcd;
|
||||
{
|
||||
struct selRecord *psel=(struct selRecord *)paddr->precord;
|
||||
|
||||
pcd->upper_ctrl_limit = psel->hopr;
|
||||
pcd->lower_ctrl_limit = psel->lopr;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long alarm(psel)
|
||||
struct selRecord *psel;
|
||||
{
|
||||
float ftemp;
|
||||
|
||||
/* check for a hardware alarm */
|
||||
if (psel->stat == READ_ALARM) return(0);
|
||||
|
||||
/* if in alarm and difference is not > hysterisis don't bother */
|
||||
if (psel->stat != NO_ALARM){
|
||||
ftemp = psel->lalm - psel->val;
|
||||
if(ftemp<0.0) ftemp = -ftemp;
|
||||
if (ftemp < psel->hyst) return(0);
|
||||
}
|
||||
|
||||
/* alarm condition hihi */
|
||||
if (psel->hhsv != NO_ALARM){
|
||||
if (psel->val > psel->hihi){
|
||||
psel->lalm = psel->val;
|
||||
if (psel->stat != HIHI_ALARM){
|
||||
psel->stat = HIHI_ALARM;
|
||||
psel->sevr = psel->hhsv;
|
||||
psel->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (psel->llsv != NO_ALARM){
|
||||
if (psel->val < psel->lolo){
|
||||
psel->lalm = psel->val;
|
||||
if (psel->stat != LOLO_ALARM){
|
||||
psel->stat = LOLO_ALARM;
|
||||
psel->sevr = psel->llsv;
|
||||
psel->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition high */
|
||||
if (psel->hsv != NO_ALARM){
|
||||
if (psel->val > psel->high){
|
||||
psel->lalm = psel->val;
|
||||
if (psel->stat != HIGH_ALARM){
|
||||
psel->stat = HIGH_ALARM;
|
||||
psel->sevr =psel->hsv;
|
||||
psel->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (psel->lsv != NO_ALARM){
|
||||
if (psel->val < psel->low){
|
||||
psel->lalm = psel->val;
|
||||
if (psel->stat != LOW_ALARM){
|
||||
psel->stat = LOW_ALARM;
|
||||
psel->sevr = psel->lsv;
|
||||
psel->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* no alarm */
|
||||
if (psel->stat != NO_ALARM){
|
||||
psel->stat = NO_ALARM;
|
||||
psel->sevr = NO_ALARM;
|
||||
psel->achn = 1;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long monitor(psel)
|
||||
struct selRecord *psel;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
float delta;
|
||||
|
||||
/* anyone waiting for an event on this record */
|
||||
if (psel->mlis.count == 0) return(0L);
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (psel->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE | DBE_LOG;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(psel,&psel->stat,DBE_VALUE);
|
||||
db_post_events(psel,&psel->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
psel->mlst = psel->val;
|
||||
|
||||
/* check for value change */
|
||||
}else{
|
||||
delta = psel->mlst - psel->val;
|
||||
if(delta<0.0) delta = -delta;
|
||||
if (delta > psel->mdel) {
|
||||
/* post events for value change */
|
||||
monitor_mask = DBE_VALUE;
|
||||
|
||||
/* update last value monitored */
|
||||
psel->mlst = psel->val;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for archive change */
|
||||
delta = psel->alst - psel->val;
|
||||
if(delta<0.0) delta = 0.0;
|
||||
if (delta > psel->adel) {
|
||||
/* post events on value field for archive change */
|
||||
monitor_mask |= DBE_LOG;
|
||||
|
||||
/* update last archive value monitored */
|
||||
psel->alst = psel->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(psel,&psel->val,monitor_mask);
|
||||
db_post_events(psel,&psel->rval,monitor_mask);
|
||||
}
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long do_sel(psel)
|
||||
struct sel *psel; /* pointer to selection record */
|
||||
{
|
||||
float *pvalue;
|
||||
struct link *plink;
|
||||
float order[SEL_MAX];
|
||||
unsigned short order_inx;
|
||||
unsigned short i,j;
|
||||
|
||||
/* selection mechanism */
|
||||
pvalue = &psel->a;
|
||||
switch (psel->selm){
|
||||
case (SELECTED):
|
||||
psel->val = *(pvalue+psel->seln);
|
||||
break;
|
||||
case (SELECT_HIGH):
|
||||
psel->val = *pvalue;
|
||||
for (i = 0; i < SEL_MAX; i++,pvalue++){
|
||||
if (psel->val < *pvalue)
|
||||
psel->val = *pvalue;
|
||||
}
|
||||
break;
|
||||
case (SELECT_LOW):
|
||||
psel->val = *pvalue;
|
||||
for (i = 0; i < SEL_MAX; i++,pvalue++){
|
||||
if (psel->val > *pvalue)
|
||||
psel->val = *pvalue;
|
||||
}
|
||||
break;
|
||||
case (SELECT_MEDIAN):
|
||||
/* order only those fetched from another record */
|
||||
plink = &psel->inpa;
|
||||
order_inx = 0;
|
||||
for (i = 0; i < SEL_MAX; i++,pvalue++,plink++){
|
||||
if (plink->type == DB_LINK){
|
||||
j = order_inx;
|
||||
while ((order[j-1] > *pvalue) && (j > 0)){
|
||||
order[j] = order[j-1];
|
||||
j--;
|
||||
}
|
||||
order[j] = *pvalue;
|
||||
order_inx++;
|
||||
}
|
||||
}
|
||||
psel->val = order[order_inx/2];
|
||||
break;
|
||||
}
|
||||
|
||||
/* initialize flag */
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* FETCH_VALUES
|
||||
*
|
||||
* fetch the values for the variables from which to select
|
||||
*/
|
||||
static fetch_values(psel)
|
||||
register struct sel *psel;
|
||||
{
|
||||
long nRequest;
|
||||
long options=0;
|
||||
struct link *plink;
|
||||
float *pvalue;
|
||||
|
||||
plink = &psel->inpa;
|
||||
pvalue = &psel->a;
|
||||
for(i=0; i<SEL_MAX; i++, plink++, pvalue++) {
|
||||
if(plink->type==DB_LINK) {
|
||||
nRequest=1;
|
||||
status=dbGetLink(plink,DBR_FLOAT,pvalue,&options,&nRequest);
|
||||
if(status!=0) return(status);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
105
src/rec/recState.c
Normal file
105
src/rec/recState.c
Normal file
@ -0,0 +1,105 @@
|
||||
|
||||
/* recState.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recState.c - Record Support Routines for State records
|
||||
*
|
||||
* Author: Marty Kraimer
|
||||
* Date: 10/10/90
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 10-10-90 mrk extensible record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <stateRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
#define init_record NULL
|
||||
long process();
|
||||
#define special NULL
|
||||
#define get_precision NULL
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_enum_str NULL
|
||||
#define get_units NULL
|
||||
#define get_graphic_double NULL
|
||||
#define get_control_double NULL
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset stateRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct stateRecord *pstate=(struct stateRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %d\n",pstate->val)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct stateRecord *pstate=(struct stateRecord *)(paddr->precord);
|
||||
/* anyone waiting for an event on this record */
|
||||
pstate->pact=FALSE;
|
||||
return(0);
|
||||
}
|
781
src/rec/recSub.c
Normal file
781
src/rec/recSub.c
Normal file
@ -0,0 +1,781 @@
|
||||
|
||||
/* recSub.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recSub.c - Record Support Routines for Subroutine records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 01-25-90
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 10-10-90 mrk Made changes for new record support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <subRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
#define special NULL
|
||||
long get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_enum_str NULL
|
||||
long get_units();
|
||||
long get_graphic_double();
|
||||
long get_control_double();
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset subRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct subRecord *psub=(struct subRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %-12.4G\n",psub->val)) return(-1);
|
||||
if(recGblReportLink(fp,"INPA ",&(psub->inpa))) return(-1);
|
||||
if(recGblReportLink(fp,"INPB ",&(psub->inpb))) return(-1);
|
||||
if(recGblReportLink(fp,"INPC ",&(psub->inpc))) return(-1);
|
||||
if(recGblReportLink(fp,"INPD ",&(psub->inpd))) return(-1);
|
||||
if(recGblReportLink(fp,"INPE ",&(psub->inpe))) return(-1);
|
||||
if(recGblReportLink(fp,"INPF ",&(psub->inpf))) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(psub->flnk))) return(-1);
|
||||
if(fprintf(fp,"A %-12.4G\n",psub->a)) return(-1);
|
||||
if(fprintf(fp,"B %-12.4G\n",psub->b)) return(-1);
|
||||
if(fprintf(fp,"C %-12.4G\n",psub->c)) return(-1);
|
||||
if(fprintf(fp,"D %-12.4G\n",psub->d)) return(-1);
|
||||
if(fprintf(fp,"E %-12.4G\n",psub->e)) return(-1);
|
||||
if(fprintf(fp,"F %-12.4G\n",psub->f)) return(-1);
|
||||
if(fprintf(fp,"PREC %d EGU %-8s\n",psub->prec,psub->egu)) return(-1);
|
||||
if(fprintf(fp,"HOPR %-12.4G LOPR %-12.4G\n",
|
||||
psub->hopr,psub->lopr)) return(-1);
|
||||
if(fprintf(fp,"HIHI %-12.4G HIGH %-12.4G LOW %-12.4G LOLO %-12.4G\n",
|
||||
psub->hihi,psub->high,psub->low,psub->lolo)) return(-1);
|
||||
if(recGblReportGblChoice(fp,psub,"HHSV",psub->hhsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,psub,"HSV ",psub->hsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,psub,"LSV ",psub->lsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,psub,"LLSV",psub->llsv)) return(-1);
|
||||
if(fprintf(fp,"HYST %-12.4G ADEL %-12.4G MDEL %-12.4G\n",
|
||||
psub->hyst,psub->adel,psub->mdel)) return(-1);
|
||||
if(fprintf(fp,"ACHN %d\n",psub->achn)) return(-1);
|
||||
if(fprintf(fp,"LALM %-12.4G ALST %-12.4G MLST %-12.4G\n",
|
||||
psub->lalm,psub->alst,psub->mlst)) return(-1);
|
||||
if(fprintf(fp,"CALC %s\n",psub->sub)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long init_record(psub)
|
||||
struct subRecord *psub;
|
||||
{
|
||||
long status;
|
||||
FUNCPTR psubroutine;
|
||||
char sub_type;
|
||||
char temp[40];
|
||||
short ret;
|
||||
|
||||
if(psub->inpa.type==CONSTANT) psub->a = psub->inpa.value.value;
|
||||
if(psub->inpb.type==CONSTANT) psub->b = psub->inpb.value.value;
|
||||
if(psub->inpc.type==CONSTANT) psub->c = psub->inpc.value.value;
|
||||
if(psub->inpd.type==CONSTANT) psub->d = psub->inpd.value.value;
|
||||
if(psub->inpe.type==CONSTANT) psub->e = psub->inpe.value.value;
|
||||
if(psub->inpf.type==CONSTANT) psub->f = psub->inpf.value.value;
|
||||
|
||||
|
||||
/* convert the initialization subroutine name */
|
||||
temp[0] = 0; /* all global variables start with _ */
|
||||
if (psub->inam[0] != '_'){
|
||||
strcpy(temp,"_");
|
||||
}
|
||||
strcat(temp,psub->inam);
|
||||
ret = symFindByName(sysSymTbl,temp,&psub->sadr,&sub_type);
|
||||
if ((ret < 0) || ((sub_type & N_TEXT) == 0)){
|
||||
psub->stat = BAD_SUB_ALARM;
|
||||
psub->sevr = MAJOR;
|
||||
psub->achn = 1;
|
||||
monitor_sub(psub);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* invoke the initialization subroutine */
|
||||
(long)psubroutine = psub->sadr;
|
||||
if (psubroutine(psub,sub_callback,
|
||||
&psub->a,&psub->b,&psub->c,&psub->d,&psub->e,&psub->f,
|
||||
&psub->val) < 0){
|
||||
if (psub->brsv != NO_ALARM){
|
||||
psub->stat = RETURN_ALARM;
|
||||
psub->sevr = psub->brsv;
|
||||
psub->achn = 1;
|
||||
monitor_sub(psub);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* convert the subroutine name to an address and type */
|
||||
/* convert the initialization subroutine name */
|
||||
temp[0] = 0; /* all global variables start with _ */
|
||||
if (psub->snam[0] != '_'){
|
||||
strcpy(temp,"_");
|
||||
}
|
||||
strcat(temp,psub->snam);
|
||||
ret = symFindByName(sysSymTbl,temp,&psub->sadr,&sub_type);
|
||||
if ((ret < 0) || ((sub_type & N_TEXT) == 0)){
|
||||
psub->styp = sub_type;
|
||||
psub->stat = BAD_SUB_ALARM;
|
||||
psub->sevr = MAJOR;
|
||||
psub->achn = 1;
|
||||
monitor_sub(psub);
|
||||
return(-1);
|
||||
}else if (psub->stat != NO_ALARM){
|
||||
psub->sevr = psub->stat = NO_ALARM;
|
||||
psub->achn = 1;
|
||||
}
|
||||
psub->styp = sub_type;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_precision(paddr,precision)
|
||||
struct dbAddr *paddr;
|
||||
long *precision;
|
||||
{
|
||||
struct subRecord *psub=(struct subRecord *)paddr->precord;
|
||||
|
||||
*precision = psub->prec;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_value(psub,pvdes)
|
||||
struct subRecord *psub;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_FLOAT;
|
||||
pvdes->no_elements=1;
|
||||
(float *)(pvdes->pvalue) = &psub->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_units(paddr,units)
|
||||
struct dbAddr *paddr;
|
||||
char *units;
|
||||
{
|
||||
struct subRecord *psub=(struct subRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,psub->egu,sizeof(psub->egu));
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_graphic_double(paddr,pgd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_grDouble *pgd;
|
||||
{
|
||||
struct subRecord *psub=(struct subRecord *)paddr->precord;
|
||||
|
||||
pgd->upper_disp_limit = psub->hopr;
|
||||
pgd->lower_disp_limit = psub->lopr;
|
||||
pgd->upper_alarm_limit = psub->hihi;
|
||||
pgd->upper_warning_limit = psub->high;
|
||||
pgd->lower_warning_limit = psub->low;
|
||||
pgd->lower_alarm_limit = psub->lolo;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long get_control_double(paddr,pcd)
|
||||
struct dbAddr *paddr;
|
||||
struct dbr_ctrlDouble *pcd;
|
||||
{
|
||||
struct subRecord *psub=(struct subRecord *)paddr->precord;
|
||||
|
||||
pcd->upper_ctrl_limit = psub->hopr;
|
||||
pcd->lower_ctrl_limit = psub->lopr;
|
||||
return(0L);
|
||||
}
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct subRecord *psub=(struct subRecord *)(paddr->precord);
|
||||
struct subdset *pdset = (struct subdset *)(psub->dset);
|
||||
long status;
|
||||
|
||||
psub->achn = 0;
|
||||
/* read inputs */
|
||||
if (fetch_values(psub) < 0){
|
||||
if (psub->stat != READ_ALARM){
|
||||
psub->stat = READ_ALARM;
|
||||
psub->sevr = MAJOR_ALARM;
|
||||
psub->achn = 1;
|
||||
monitor_sub(psub);
|
||||
}
|
||||
psub->pact = 0;
|
||||
return(0);
|
||||
}else{
|
||||
if (psub->stat == READ_ALARM){
|
||||
psub->stat = NO_ALARM;
|
||||
psub->sevr = NO_ALARM;
|
||||
psub->achn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* perform subulation */
|
||||
if (do_sub(psub) < 0){
|
||||
if (psub->stat != CALC_ALARM){
|
||||
psub->stat = CALC_ALARM;
|
||||
psub->sevr = MAJOR_ALARM;
|
||||
psub->achn = 1;
|
||||
monitor_sub(psub);
|
||||
}
|
||||
psub->pact = 0;
|
||||
return;
|
||||
}else{
|
||||
if (psub->stat == CALC_ALARM){
|
||||
psub->stat = NO_ALARM;
|
||||
psub->sevr = NO_ALARM;
|
||||
psub->achn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for alarms */
|
||||
alarm(psub);
|
||||
|
||||
|
||||
/* check event list */
|
||||
if(!psub->disa) status = monitor(psub);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (psub->flnk.type==DB_LINK) dbScanPassive(&psub->flnk.value);
|
||||
|
||||
psub->pact=FALSE;
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* FETCH_VALUES
|
||||
*
|
||||
* fetch the values for the variables in the subulation
|
||||
*/
|
||||
static fetch_values(psub)
|
||||
struct subRecord *psub;
|
||||
{
|
||||
short status;
|
||||
|
||||
/* note - currently not using alarm status */
|
||||
status = 0;
|
||||
status |= get_sub_inp(&psub->inpa,&psub->a);
|
||||
status |= get_sub_inp(&psub->inpb,&psub->b);
|
||||
status |= get_sub_inp(&psub->inpc,&psub->c);
|
||||
status |= get_sub_inp(&psub->inpd,&psub->d);
|
||||
status |= get_sub_inp(&psub->inpe,&psub->e);
|
||||
status |= get_sub_inp(&psub->inpf,&psub->f);
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* GET_CALC_INPUT
|
||||
*
|
||||
* return an input value
|
||||
*/
|
||||
static get_sub_inp(plink,pvalue)
|
||||
struct link *plink; /* structure of the link field */
|
||||
float *pvalue;
|
||||
{
|
||||
float float_value;
|
||||
|
||||
/* database link */
|
||||
if (plink->type == DB_LINK){
|
||||
if (dbGetLink(&plink->value.db_link,DBR_FLOAT,&float_value,1) < 0)
|
||||
return(-1);
|
||||
*pvalue = float_value;
|
||||
|
||||
/* constant */
|
||||
}else if (plink->type == CONSTANT){
|
||||
;
|
||||
/* illegal link type */
|
||||
}else{
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
static long alarm(psub)
|
||||
struct subRecord *psub;
|
||||
{
|
||||
float ftemp;
|
||||
|
||||
/* if in alarm and difference is not > hysterisis don't bother */
|
||||
if (psub->stat != NO_ALARM){
|
||||
ftemp = psub->lalm - psub->val;
|
||||
if(ftemp<0.0) ftemp = -ftemp;
|
||||
if (ftemp < psub->hyst) return(0);
|
||||
}
|
||||
|
||||
/* alarm condition hihi */
|
||||
if (psub->hhsv != NO_ALARM){
|
||||
if (psub->val > psub->hihi){
|
||||
psub->lalm = psub->val;
|
||||
if (psub->stat != HIHI_ALARM){
|
||||
psub->stat = HIHI_ALARM;
|
||||
psub->sevr = psub->hhsv;
|
||||
psub->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (psub->llsv != NO_ALARM){
|
||||
if (psub->val < psub->lolo){
|
||||
psub->lalm = psub->val;
|
||||
if (psub->stat != LOLO_ALARM){
|
||||
psub->stat = LOLO_ALARM;
|
||||
psub->sevr = psub->llsv;
|
||||
psub->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition high */
|
||||
if (psub->hsv != NO_ALARM){
|
||||
if (psub->val > psub->high){
|
||||
psub->lalm = psub->val;
|
||||
if (psub->stat != HIGH_ALARM){
|
||||
psub->stat = HIGH_ALARM;
|
||||
psub->sevr =psub->hsv;
|
||||
psub->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (psub->lsv != NO_ALARM){
|
||||
if (psub->val < psub->low){
|
||||
psub->lalm = psub->val;
|
||||
if (psub->stat != LOW_ALARM){
|
||||
psub->stat = LOW_ALARM;
|
||||
psub->sevr = psub->lsv;
|
||||
psub->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* no alarm */
|
||||
if (psub->stat != NO_ALARM){
|
||||
psub->stat = NO_ALARM;
|
||||
psub->sevr = NO_ALARM;
|
||||
psub->achn = 1;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long monitor(psub)
|
||||
struct subRecord *psub;
|
||||
{
|
||||
unsigned short monitor_mask;
|
||||
float delta;
|
||||
|
||||
/* anyone wsubting for an event on this record */
|
||||
if (psub->mlis.count == 0) return(0L);
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (psub->achn){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE | DBE_LOG;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(psub,&psub->stat,DBE_VALUE);
|
||||
db_post_events(psub,&psub->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
psub->mlst = psub->val;
|
||||
|
||||
/* check for value change */
|
||||
}else{
|
||||
delta = psub->mlst - psub->val;
|
||||
if(delta<0.0) delta = -delta;
|
||||
if (delta > psub->mdel) {
|
||||
/* post events for value change */
|
||||
monitor_mask = DBE_VALUE;
|
||||
|
||||
/* update last value monitored */
|
||||
psub->mlst = psub->val;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for archive change */
|
||||
delta = psub->alst - psub->val;
|
||||
if(delta<0.0) delta = 0.0;
|
||||
if (delta > psub->adel) {
|
||||
/* post events on value field for archive change */
|
||||
monitor_mask |= DBE_LOG;
|
||||
|
||||
/* update last archive value monitored */
|
||||
psub->alst = psub->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask){
|
||||
db_post_events(psub,&psub->val,monitor_mask);
|
||||
}
|
||||
return(0L);
|
||||
}
|
||||
|
||||
process_sub(psub)
|
||||
register struct sub *psub; /* pointer to subroutine record */
|
||||
{
|
||||
psub->achn = 0;
|
||||
|
||||
/* lock the record */
|
||||
if (psub->lock){
|
||||
if (psub->lcnt >= MAX_LOCK){
|
||||
psub->stat = SCAN_ALARM;
|
||||
psub->sevr = MAJOR;
|
||||
psub->achn = 1;
|
||||
monitor_sub(psub);
|
||||
}else{
|
||||
psub->lcnt++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
psub->lcnt = 0;
|
||||
psub->lock = 1;
|
||||
|
||||
if (psub->init == 0){
|
||||
if (sub_init(psub) < 0){
|
||||
psub->lock = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for valid subroutine connection */
|
||||
if (psub->stat == BAD_SUB_ALARM){
|
||||
psub->lock = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* perform the subroutine call */
|
||||
do_sub(psub);
|
||||
|
||||
/* do post processing for synchronous routines */
|
||||
if (psub->rtcb == FALSE){
|
||||
sub_callback(psub);
|
||||
}
|
||||
/* unlock of record is done in sub_callback either directly (above) */
|
||||
/* or asynchronously through the callback mechanism */
|
||||
}
|
||||
|
||||
/*
|
||||
* SUB_CALLBACK
|
||||
*
|
||||
* subroutine values returned handling -
|
||||
* either called immediately for fast routines or asynchronously for slow
|
||||
* routines (i.e. GPIB interfaces that require a wait)
|
||||
*/
|
||||
sub_callback(psub)
|
||||
register struct sub *psub; /* pointer to subroutine record */
|
||||
{
|
||||
/* check for alarms */
|
||||
if ((psub->stat != READ_ALARM) && (psub->stat != RETURN_ALARM)
|
||||
&& (psub->stat != BAD_SUB_ALARM))
|
||||
alarm_sub(psub);
|
||||
|
||||
/* check for monitors */
|
||||
monitor_sub(psub);
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (psub->flnk.type == DB_LINK)
|
||||
db_scan(&psub->flnk.value);
|
||||
|
||||
/* unlock the record */
|
||||
psub->lock = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DO_SUB
|
||||
*
|
||||
* invoke the subroutine
|
||||
*/
|
||||
static do_sub(psub)
|
||||
register struct sub *psub; /* pointer to subroutine record */
|
||||
{
|
||||
register short status;
|
||||
register FUNCPTR psubroutine;
|
||||
|
||||
/* get the subroutine arguments */
|
||||
status = 0;
|
||||
if (psub->inpa.type == DB_LINK){
|
||||
if (db_fetch(&psub->inpa.value.db_link,&psub->a) < 0)
|
||||
status |= -1;
|
||||
}
|
||||
if (psub->inpb.type == DB_LINK){
|
||||
if (db_fetch(&psub->inpb.value.db_link,&psub->b) < 0)
|
||||
status |= -1;
|
||||
}
|
||||
if (psub->inpc.type == DB_LINK){
|
||||
if (db_fetch(&psub->inpc.value.db_link,&psub->c) < 0)
|
||||
status |= -1;
|
||||
}
|
||||
if (psub->inpd.type == DB_LINK){
|
||||
if (db_fetch(&psub->inpd.value.db_link,&psub->d) < 0)
|
||||
status |= -1;
|
||||
}
|
||||
if (psub->inpe.type == DB_LINK){
|
||||
if (db_fetch(&psub->inpe.value.db_link,&psub->e) < 0)
|
||||
status |= -1;
|
||||
}
|
||||
if (psub->inpf.type == DB_LINK){
|
||||
if (db_fetch(&psub->inpf.value.db_link,&psub->f) < 0)
|
||||
status |= -1;
|
||||
}
|
||||
if (status != 0){
|
||||
psub->stat = READ_ALARM;
|
||||
psub->sevr = MAJOR;
|
||||
psub->achn = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* call the subroutine */
|
||||
(long)psubroutine = psub->sadr;
|
||||
if (psubroutine(psub,sub_callback,
|
||||
&psub->a,&psub->b,&psub->c,&psub->d,&psub->e,&psub->f,
|
||||
&psub->val) < 0){
|
||||
if (psub->brsv != NO_ALARM){
|
||||
psub->stat = RETURN_ALARM;
|
||||
psub->sevr = psub->brsv;
|
||||
psub->achn = 1;
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
if (psub->brsv != NO_ALARM){
|
||||
psub->stat = NO_ALARM;
|
||||
psub->sevr = NO_ALARM;
|
||||
psub->achn = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* ALARM_SUB
|
||||
*
|
||||
* check the alarm condition
|
||||
*/
|
||||
static alarm_sub(psub)
|
||||
register struct sub *psub;
|
||||
{
|
||||
register float ftemp;
|
||||
|
||||
/* if in alarm and difference is not > hysterisis don't bother */
|
||||
if (psub->stat != NO_ALARM){
|
||||
ftemp = psub->lalm - psub->val;
|
||||
if ( (ftemp < psub->hyst) && (ftemp > -psub->hyst))
|
||||
return;
|
||||
}
|
||||
|
||||
/* alarm condition hihi */
|
||||
if (psub->hhsv != NO_ALARM){
|
||||
if (psub->val > psub->hihi){
|
||||
if (psub->stat != HIHI_ALARM){
|
||||
psub->stat = HIHI_ALARM;
|
||||
psub->sevr = psub->hhsv;
|
||||
psub->lalm = psub->val;
|
||||
psub->achn = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition lolo */
|
||||
if (psub->llsv != NO_ALARM){
|
||||
if (psub->val < psub->lolo){
|
||||
if (psub->stat != LOLO_ALARM){
|
||||
psub->stat = LOLO_ALARM;
|
||||
psub->sevr = psub->llsv;
|
||||
psub->lalm = psub->val;
|
||||
psub->achn = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition high */
|
||||
if (psub->hsv != NO_ALARM){
|
||||
if (psub->val > psub->high){
|
||||
if (psub->stat != HIGH_ALARM){
|
||||
psub->stat = HIGH_ALARM;
|
||||
psub->sevr = psub->hsv;
|
||||
psub->lalm = psub->val;
|
||||
psub->achn = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* alarm condition low */
|
||||
if (psub->lsv != NO_ALARM){
|
||||
if (psub->val < psub->low){
|
||||
if (psub->stat != LOW_ALARM){
|
||||
psub->stat = LOW_ALARM;
|
||||
psub->sevr = psub->lsv;
|
||||
psub->lalm = psub->val;
|
||||
psub->achn = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* no alarm */
|
||||
if (psub->stat != NO_ALARM){
|
||||
psub->stat = NO_ALARM;
|
||||
psub->sevr = NO_ALARM;
|
||||
psub->achn = 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* MONITOR_SUB
|
||||
*
|
||||
* process subroutine record monitors
|
||||
*/
|
||||
static monitor_sub(psub)
|
||||
register struct sub *psub; /* pointer to the subroutine record */
|
||||
{
|
||||
register unsigned short monitor_mask;
|
||||
register float delta;
|
||||
|
||||
/* anyone waiting for an event on this record */
|
||||
if (psub->mqct == 0) return;
|
||||
|
||||
/* check monitors for each of the argument fields */
|
||||
if (psub->la != psub->a){
|
||||
db_post_events(psub,&psub->a,DBE_VALUE);
|
||||
psub->la = psub->a;
|
||||
}
|
||||
if (psub->lb != psub->b){
|
||||
db_post_events(psub,&psub->b,DBE_VALUE);
|
||||
psub->la = psub->b;
|
||||
}
|
||||
if (psub->lc != psub->c){
|
||||
db_post_events(psub,&psub->c,DBE_VALUE);
|
||||
psub->lc = psub->c;
|
||||
}
|
||||
if (psub->ld != psub->d){
|
||||
db_post_events(psub,&psub->d,DBE_VALUE);
|
||||
psub->ld = psub->d;
|
||||
}
|
||||
if (psub->le != psub->e){
|
||||
db_post_events(psub,&psub->e,DBE_VALUE);
|
||||
psub->le = psub->e;
|
||||
}
|
||||
if (psub->lf != psub->f){
|
||||
db_post_events(psub,&psub->f,DBE_VALUE);
|
||||
psub->lf = psub->f;
|
||||
}
|
||||
|
||||
/* Flags which events to fire on the value field */
|
||||
monitor_mask = 0;
|
||||
|
||||
/* alarm condition changed this scan */
|
||||
if (psub->achn != 0){
|
||||
/* post events for alarm condition change and value change */
|
||||
monitor_mask = DBE_ALARM | DBE_VALUE;
|
||||
|
||||
/* post stat and sevr fields */
|
||||
db_post_events(psub,&psub->stat,DBE_VALUE);
|
||||
db_post_events(psub,&psub->sevr,DBE_VALUE);
|
||||
|
||||
/* update last value monitored */
|
||||
psub->mlst = psub->val;
|
||||
|
||||
/* check for value change */
|
||||
}else{
|
||||
delta = psub->mlst - psub->val;
|
||||
if ((delta > psub->mdel) || (delta < -psub->mdel)){
|
||||
/* post events for value change */
|
||||
monitor_mask = DBE_VALUE;
|
||||
|
||||
/* update last value monitored */
|
||||
psub->mlst = psub->val;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for archive change */
|
||||
delta = psub->alst - psub->val;
|
||||
if ((delta > psub->adel) || (delta < -psub->adel)){
|
||||
/* post events on value field for archive change */
|
||||
monitor_mask |= DBE_LOG;
|
||||
|
||||
/* update last archive value monitored */
|
||||
psub->alst = psub->val;
|
||||
}
|
||||
|
||||
/* send out monitors connected to the value field */
|
||||
if (monitor_mask)
|
||||
db_post_events(psub,&psub->val,monitor_mask);
|
||||
}
|
351
src/rec/recTimer.c
Normal file
351
src/rec/recTimer.c
Normal file
@ -0,0 +1,351 @@
|
||||
|
||||
/* recTimer.c */
|
||||
/* share/src/rec $Id$ */
|
||||
|
||||
/* recTimer.c - Record Support Routines for Timer records
|
||||
*
|
||||
* Author: Bob Dalesio
|
||||
* Date: 1-9-89
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Bob Dalesio, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 667-3414
|
||||
* E-mail: dalesio@luke.lanl.gov
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 01-20-89 lrd fix vx includes
|
||||
* .02 02-06-89 lrd add event post capability
|
||||
* .03 03-29-89 lrd make hardware errors MAJOR
|
||||
* remove hw severity spec from database
|
||||
* .04 04-07-89 lrd service monitors
|
||||
* .05 05-03-89 lrd removed process mask from arg list
|
||||
* .06 05-03-89 lrd modified to read the timing on startup
|
||||
* .07 05-03-89 lrd read trigger delay from trigger origin record
|
||||
* .08 07-03-89 lrd add processing a forward link
|
||||
* .09 08-15-89 lrd add post events for timing pulse 1 fields
|
||||
* .10 10-15-90 mrk extensible record and device support
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <lstLib.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <cvtTable.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <devSup.h>
|
||||
#include <errMdef.h>
|
||||
#include <link.h>
|
||||
#include <recSup.h>
|
||||
#include <special.h>
|
||||
#include <timerRecord.h>
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
long report();
|
||||
#define initialize NULL
|
||||
long init_record();
|
||||
long process();
|
||||
#define special();
|
||||
#define get_precision();
|
||||
long get_value();
|
||||
#define cvt_dbaddr NULL
|
||||
#define get_array_info NULL
|
||||
#define put_array_info NULL
|
||||
#define get_enum_str NULL
|
||||
#define get_units();
|
||||
#define get_graphic_double();
|
||||
#define get_control_double();
|
||||
#define get_enum_strs NULL
|
||||
|
||||
struct rset timerRSET={
|
||||
RSETNUMBER,
|
||||
report,
|
||||
initialize,
|
||||
init_record,
|
||||
process,
|
||||
special,
|
||||
get_precision,
|
||||
get_value,
|
||||
cvt_dbaddr,
|
||||
get_array_info,
|
||||
put_array_info,
|
||||
get_enum_str,
|
||||
get_units,
|
||||
get_graphic_double,
|
||||
get_control_double,
|
||||
get_enum_strs };
|
||||
|
||||
/* because the driver does all the work just declare device support here*/
|
||||
struct dset devMizar8310={4,NULL,NULL,NULL,NULL};
|
||||
struct dset devDg535={4,NULL,NULL,NULL,NULL};
|
||||
struct dset devVxiAt5Time={4,NULL,NULL,NULL,NULL};
|
||||
|
||||
static long report(fp,paddr)
|
||||
FILE *fp;
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct timerRecord *ptimer=(struct timerRecord*)(paddr->precord);
|
||||
|
||||
if(recGblReportDbCommon(fp,paddr)) return(-1);
|
||||
if(fprintf(fp,"VAL %-12.4G\n",ptimer->val)) return(-1);
|
||||
if(recGblReportLink(fp,"INP ",&(ptimer->inp))) return(-1);
|
||||
if(fprintf(fp,"PREC %d\n",ptimer->prec)) return(-1);
|
||||
if(recGblReportCvtChoice(fp,"LINR",ptimer->linr)) return(-1);
|
||||
if(fprintf(fp,"HOPR %-12.4G LOPR %-12.4G\n",
|
||||
ptimer->hopr,ptimer->lopr)) return(-1);
|
||||
if(recGblReportLink(fp,"FLNK",&(ptimer->flnk))) return(-1);
|
||||
if(fprintf(fp,"HIHI %-12.4G HIGH %-12.4G LOW %-12.4G LOLO %-12.4G\n",
|
||||
ptimer->hihi,ptimer->high,ptimer->low,ptimer->lolo)) return(-1);
|
||||
if(recGblReportGblChoice(fp,ptimer,"HHSV",ptimer->hhsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,ptimer,"HSV ",ptimer->hsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,ptimer,"LSV ",ptimer->lsv)) return(-1);
|
||||
if(recGblReportGblChoice(fp,ptimer,"LLSV",ptimer->llsv)) return(-1);
|
||||
if(fprintf(fp,"HYST %-12.4G ADEL %-12.4G MDEL %-12.4G ESLO %-12.4G\n",
|
||||
ptimer->hyst,ptimer->adel,ptimer->mdel,ptimer->eslo)) return(-1);
|
||||
if(fprintf(fp,"RVAL 0x%-8X ACHN %d\n",
|
||||
ptimer->rval,ptimer->achn)) return(-1);
|
||||
if(fprintf(fp,"LALM %-12.4G ALST %-12.4G MLST %-12.4G\n",
|
||||
ptimer->lalm,ptimer->alst,ptimer->mlst)) return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long init_record(ptimer)
|
||||
struct timerRecord *ptimer;
|
||||
{
|
||||
long status;
|
||||
|
||||
/* read to maintain time pulses over a restart */
|
||||
read_timer(ptimer);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long get_value(ptimer,pvdes)
|
||||
struct timerRecord *ptimer;
|
||||
struct valueDes *pvdes;
|
||||
{
|
||||
pvdes->field_type = DBF_SHORT;
|
||||
pvdes->no_elements=1;
|
||||
(short *)(pvdes->pvalue) = &ptimer->val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
extern int post_event();
|
||||
|
||||
static long process(paddr)
|
||||
struct dbAddr *paddr;
|
||||
{
|
||||
struct timerRecord *ptimer=(struct timerRecord *)(paddr->precord);
|
||||
long status;
|
||||
|
||||
ptimer->pact=TRUE;
|
||||
ptimer->achn = 0; /* init the alarm change flag */
|
||||
|
||||
/* write the new value */
|
||||
write_timer(ptimer);
|
||||
|
||||
/* need to post events for an alarm condition change */
|
||||
if ((ptimer->achn) && (ptimer->mlis.count!=0))
|
||||
db_post_events(ptimer,&ptimer->val,DBE_ALARM);
|
||||
|
||||
if (ptimer->mlis.count!=0){
|
||||
db_post_events(ptimer,&ptimer->val,DBE_VALUE);
|
||||
db_post_events(ptimer,&ptimer->t1wd,DBE_VALUE);
|
||||
db_post_events(ptimer,&ptimer->t1ld,DBE_VALUE);
|
||||
db_post_events(ptimer,&ptimer->t1td,DBE_VALUE);
|
||||
}
|
||||
|
||||
/* process the forward scan link record */
|
||||
if (ptimer->flnk.type == DB_LINK)
|
||||
dbScanPassive(&ptimer->flnk.value);
|
||||
|
||||
/* unlock the record */
|
||||
ptimer->lock = 0;
|
||||
ptimer->pact=FALSE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* These constants are indexed by the time units field in the timer record.
|
||||
* Values are converted to seconds.
|
||||
*/
|
||||
static double constants[] = {1000,1000000,1000000000,1000000000000};
|
||||
/*
|
||||
* CONVERT_TIMER
|
||||
*
|
||||
*/
|
||||
static convert_timer(ptimer)
|
||||
register struct timer *ptimer;
|
||||
{
|
||||
double constant;
|
||||
|
||||
/* check the tdisble bit */
|
||||
if (ptimer->tdis == 1){
|
||||
ptimer->t1dl = ptimer->t1wd = 0;
|
||||
ptimer->t2dl = ptimer->t2wd = 0;
|
||||
ptimer->t3dl = ptimer->t3wd = 0;
|
||||
ptimer->t4dl = ptimer->t4wd = 0;
|
||||
ptimer->t5dl = ptimer->t5wd = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* convert according to time units */
|
||||
constant = constants[ptimer->timu];
|
||||
|
||||
/* timing pulse 1 */
|
||||
ptimer->t1dl = (ptimer->dut1 + ptimer->trdl) / constant; /* delay */
|
||||
ptimer->t1wd = ptimer->opw1 / constant; /* width */
|
||||
ptimer->t1ld = ptimer->dut1 + ptimer->trdl; /* leading edge delay */
|
||||
ptimer->t1td = ptimer->t1ld + ptimer->opw1; /* trailing edge delay */
|
||||
|
||||
/* timing pulse 2 */
|
||||
ptimer->t2dl = (ptimer->dut2 + ptimer->trdl) / constant; /* delay */
|
||||
ptimer->t2wd = ptimer->opw2 / constant; /* width */
|
||||
ptimer->t2ld = ptimer->dut2 + ptimer->trdl; /* leading edge delay */
|
||||
ptimer->t2td = ptimer->t2ld + ptimer->opw2; /* trailing edge delay */
|
||||
|
||||
/* timing pulse 3 */
|
||||
ptimer->t3dl = (ptimer->dut3 + ptimer->trdl) / constant; /* delay */
|
||||
ptimer->t3wd = ptimer->opw3 / constant; /* width */
|
||||
ptimer->t3ld = ptimer->dut3 + ptimer->trdl; /* leading edge delay */
|
||||
ptimer->t3td = ptimer->t3ld + ptimer->opw3; /* trailing edge delay */
|
||||
|
||||
/* timing pulse 4 */
|
||||
ptimer->t4dl = (ptimer->dut4 + ptimer->trdl) / constant; /* delay */
|
||||
ptimer->t4wd = ptimer->opw4 / constant; /* width */
|
||||
ptimer->t4ld = ptimer->dut4 + ptimer->trdl; /* leading edge delay */
|
||||
ptimer->t4td = ptimer->t4ld + ptimer->opw4; /* trailing edge delay */
|
||||
|
||||
/* timing pulse 5 */
|
||||
ptimer->t5dl = (ptimer->dut5 + ptimer->trdl) / constant; /* delay */
|
||||
ptimer->t5wd = ptimer->opw5 / constant; /* width */
|
||||
ptimer->t5ld = ptimer->dut5 + ptimer->trdl; /* leading edge delay */
|
||||
ptimer->t5td = ptimer->t5ld + ptimer->opw5; /* trailing edge delay */
|
||||
}
|
||||
|
||||
/*
|
||||
* WRITE_TIMER
|
||||
*
|
||||
* convert the value and write it
|
||||
*/
|
||||
static write_timer(ptimer)
|
||||
register struct timer *ptimer;
|
||||
{
|
||||
register struct vmeio *pvmeio;
|
||||
register double *pdelay;
|
||||
register short count;
|
||||
register short i;
|
||||
|
||||
/* get the delay from trigger source */
|
||||
if (ptimer->torg.type == DB_LINK){
|
||||
if (db_fetch(&ptimer->torg.value,&ptimer->trdl) < 0){
|
||||
if (ptimer->stat != READ_ALARM){
|
||||
ptimer->stat = READ_ALARM;
|
||||
ptimer->sevr = MAJOR;
|
||||
ptimer->achn = 1;
|
||||
}
|
||||
return(-1);
|
||||
}else if (ptimer->stat == READ_ALARM){
|
||||
ptimer->stat = NO_ALARM;
|
||||
ptimer->sevr = NO_ALARM;
|
||||
ptimer->achn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptimer->out.type != VME_IO) return(-1);
|
||||
|
||||
pvmeio = (struct vmeio *)(&ptimer->out.value);
|
||||
|
||||
/* convert the value */
|
||||
convert_timer(ptimer);
|
||||
|
||||
/* put the value to the ao driver */
|
||||
if (time_driver((int)pvmeio->card, /* card number */
|
||||
(int)pvmeio->signal, /* signal number */
|
||||
(int)ptimer->type, /* card type */
|
||||
(int)ptimer->tsrc, /* trigger source */
|
||||
(int)ptimer->ptst, /* pre-trigger state */
|
||||
&ptimer->t1dl, /* delay/width array */
|
||||
1, /* number of pulses */
|
||||
((ptimer->tevt == 0)?0:post_event), /* addr of event post routine */
|
||||
(int)ptimer->tevt) /* event to post on trigger */
|
||||
!= NO_ALARM){
|
||||
if (ptimer->stat != WRITE_ALARM){
|
||||
ptimer->stat = WRITE_ALARM;
|
||||
ptimer->sevr = MAJOR;
|
||||
ptimer->achn = 1;
|
||||
}
|
||||
return(-1);
|
||||
}else if (ptimer->stat == WRITE_ALARM){
|
||||
ptimer->stat = NO_ALARM;
|
||||
ptimer->sevr = NO_ALARM;
|
||||
ptimer->achn = 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* READ_TIMER
|
||||
*
|
||||
* read the current timer pulses and convert them to engineering units
|
||||
*/
|
||||
static read_timer(ptimer)
|
||||
register struct timer *ptimer;
|
||||
{
|
||||
register struct vmeio *pvmeio;
|
||||
int source;
|
||||
int ptst;
|
||||
int no_pulses;
|
||||
double time_pulse[2]; /* delay and width */
|
||||
double constant;
|
||||
|
||||
/* initiate the write */
|
||||
if (ptimer->out.type != VME_IO) return(-1);
|
||||
|
||||
/* only supports a one channel VME timer module !!!! */
|
||||
|
||||
|
||||
pvmeio = (struct vmeio *)(&ptimer->out.value);
|
||||
|
||||
/* put the value to the ao driver */
|
||||
if (time_driver_read((int)pvmeio->card, /* card number */
|
||||
(int)pvmeio->signal, /* signal number */
|
||||
(int)ptimer->type, /* card type */
|
||||
&source, /* trigger source */
|
||||
&ptst, /* pre-trigger state */
|
||||
&time_pulse[0], /* delay/width */
|
||||
&no_pulses, /* number pulses found */
|
||||
1) < 0) return;
|
||||
|
||||
if (no_pulses == 0) return;
|
||||
|
||||
/* convert according to time units */
|
||||
constant = constants[ptimer->timu];
|
||||
|
||||
/* timing pulse 1 is currently active */
|
||||
/* put its parameters into the database so that it will not change */
|
||||
/* when the timer record is written */
|
||||
ptimer->dut1 = time_pulse[0] * constant; /* delay to trigger */
|
||||
ptimer->opw1 = time_pulse[1] * constant; /* pulse width */
|
||||
ptimer->ptst = ptst; /* pre-trigger state */
|
||||
ptimer->tsrc = source; /* clock source */
|
||||
return(0);
|
||||
}
|
Reference in New Issue
Block a user