From 1dbd526476d651c3956a648db6b109830d2453ad Mon Sep 17 00:00:00 2001 From: Bob Zieman Date: Wed, 17 Oct 1990 06:28:14 +0000 Subject: [PATCH] Initial revision --- src/rec/recAi.c | 527 ++++++++++++++++ src/rec/recAo.c | 499 +++++++++++++++ src/rec/recBi.c | 325 ++++++++++ src/rec/recBo.c | 365 +++++++++++ src/rec/recCalc.c | 1273 +++++++++++++++++++++++++++++++++++++++ src/rec/recCompress.c | 498 +++++++++++++++ src/rec/recFanout.c | 115 ++++ src/rec/recMbbi.c | 356 +++++++++++ src/rec/recMbbo.c | 362 +++++++++++ src/rec/recPermissive.c | 107 ++++ src/rec/recPid.c | 409 +++++++++++++ src/rec/recSel.c | 434 +++++++++++++ src/rec/recState.c | 105 ++++ src/rec/recSub.c | 781 ++++++++++++++++++++++++ src/rec/recTimer.c | 351 +++++++++++ 15 files changed, 6507 insertions(+) create mode 100644 src/rec/recAi.c create mode 100644 src/rec/recAo.c create mode 100644 src/rec/recBi.c create mode 100644 src/rec/recBo.c create mode 100644 src/rec/recCalc.c create mode 100644 src/rec/recCompress.c create mode 100644 src/rec/recFanout.c create mode 100644 src/rec/recMbbi.c create mode 100644 src/rec/recMbbo.c create mode 100644 src/rec/recPermissive.c create mode 100644 src/rec/recPid.c create mode 100644 src/rec/recSel.c create mode 100644 src/rec/recState.c create mode 100644 src/rec/recSub.c create mode 100644 src/rec/recTimer.c diff --git a/src/rec/recAi.c b/src/rec/recAi.c new file mode 100644 index 000000000..18e1fa434 --- /dev/null +++ b/src/rec/recAi.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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((valrawLow) || (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); +} diff --git a/src/rec/recAo.c b/src/rec/recAo.c new file mode 100644 index 000000000..88e733c9a --- /dev/null +++ b/src/rec/recAo.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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; + } +} + diff --git a/src/rec/recBi.c b/src/rec/recBi.c new file mode 100644 index 000000000..a72fe8cd7 --- /dev/null +++ b/src/rec/recBi.c @@ -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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/src/rec/recBo.c b/src/rec/recBo.c new file mode 100644 index 000000000..e20397cf8 --- /dev/null +++ b/src/rec/recBo.c @@ -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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/src/rec/recCalc.c b/src/rec/recCalc.c new file mode 100644 index 000000000..0d6c72552 --- /dev/null +++ b/src/rec/recCalc.c @@ -0,0 +1,1273 @@ + +/* recCalc.c */ +/* share/src/rec $Id$ */ + +/* recCalc.c - Record Support Routines for Calculation records + * + * Author: Julie Sander and Bob Dalesio + * Date: 7-27-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 5-18-88 lrd modified modulo and power to avoid math library + * .02 5-19-88 lrd modified absolute value to avoid math library + * defined unary math lib routines as doubles + * removed include math.h + * stopped loading dinglers math routines (ml) + * wrote a random number generator to return a + * double between 0 and 1 + * .03 12-09-88 lrd fixed modulo not to perform zero division + * .04 12-12-88 lrd lock the record while processing + * .05 12-13-88 lrd made an alarm for math error + * .06 12-15-88 lrd Process the forward scan link + * .07 12-23-88 lrd Alarm on locked MAX_LOCKED times + * .08 01-11-89 lrd Add Right and Left Shift + * .09 02-01-89 lrd Add Trig functions + * .10 03-14-89 lrd fix true on C question mark operator + * .11 03-29-89 lrd make hardware errors MAJOR + * remove hw severity spec from database + * .12 04-06-89 lrd add monitor detection + * .13 05-03-89 lrd removed process mask from arg list + * .14 06-05-89 lrd check for negative square root + * .15 08-01-89 lrd full range of exponentiation using pow(x,y) + * .16 04-04-90 lrd fix post events for read and calc alarms + * fix neg base raised to integer exponent + * .17 04-06-90 lrd change conditional to check for 0 and non-zero + * instead of 0 and 1 (more 'C' like) + * .18 10-10-90 mrk Made changes for new record support + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 calcRSET={ + 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 }; + +/* the floating point math routines need to be declared as doubles */ +static double random(); /* random number generator */ +double sqrt(),log(),log10(); +double acos(),asin(),atan(); +double cos(),sin(),tan(); +double cosh(),sinh(),tanh(); + +/* defines for element table */ +#define FETCH_A 0 +#define FETCH_B 1 +#define FETCH_C 2 +#define FETCH_D 3 +#define FETCH_E 4 +#define FETCH_F 5 +#define ACOS 6 +#define ASIN 7 +#define ATAN 8 +#define COS 9 +#define COSH 10 +#define SIN 11 +#define STORE_A 12 +#define STORE_B 13 +#define STORE_C 14 +#define STORE_D 15 +#define STORE_E 16 +#define STORE_F 17 +#define RIGHT_SHIFT 18 +#define LEFT_SHIFT 19 +#define SINH 20 +#define TAN 21 +#define TANH 22 +#define LOG_2 23 +#define COND_ELSE 24 +#define ABS_VAL 25 +#define UNARY_NEG 26 +#define SQU_RT 27 +#define LOG_10 28 +#define LOG_E 29 +#define RANDOM 30 +/* +#define 31 +*/ +#define ADD 32 +#define SUB 33 +#define MULT 34 +#define DIV 35 +#define EXPON 36 +#define MODULO 37 +#define BIT_OR 38 +#define BIT_AND 39 +#define BIT_EXCL_OR 40 +#define GR_OR_EQ 41 +#define GR_THAN 42 +#define LESS_OR_EQ 43 +#define LESS_THAN 44 +#define NOT_EQ 45 +#define EQUAL 46 +#define REL_OR 47 +#define REL_AND 48 +#define PAREN -1 +#define END_STACK -1 + +static long report(fp,paddr) + FILE *fp; + struct dbAddr *paddr; +{ + struct calcRecord *pcalc=(struct calcRecord*)(paddr->precord); + + if(recGblReportDbCommon(fp,paddr)) return(-1); + if(fprintf(fp,"VAL %-12.4G\n",pcalc->val)) return(-1); + if(recGblReportLink(fp,"INPA ",&(pcalc->inpa))) return(-1); + if(recGblReportLink(fp,"INPB ",&(pcalc->inpb))) return(-1); + if(recGblReportLink(fp,"INPC ",&(pcalc->inpc))) return(-1); + if(recGblReportLink(fp,"INPD ",&(pcalc->inpd))) return(-1); + if(recGblReportLink(fp,"INPE ",&(pcalc->inpe))) return(-1); + if(recGblReportLink(fp,"INPF ",&(pcalc->inpf))) return(-1); + if(recGblReportLink(fp,"FLNK",&(pcalc->flnk))) return(-1); + if(fprintf(fp,"A %-12.4G\n",pcalc->a)) return(-1); + if(fprintf(fp,"B %-12.4G\n",pcalc->b)) return(-1); + if(fprintf(fp,"C %-12.4G\n",pcalc->c)) return(-1); + if(fprintf(fp,"D %-12.4G\n",pcalc->d)) return(-1); + if(fprintf(fp,"E %-12.4G\n",pcalc->e)) return(-1); + if(fprintf(fp,"F %-12.4G\n",pcalc->f)) return(-1); + if(fprintf(fp,"PREC %d EGU %-8s\n",pcalc->prec,pcalc->egu)) return(-1); + if(fprintf(fp,"HOPR %-12.4G LOPR %-12.4G\n", + pcalc->hopr,pcalc->lopr)) return(-1); + if(fprintf(fp,"HIHI %-12.4G HIGH %-12.4G LOW %-12.4G LOLO %-12.4G\n", + pcalc->hihi,pcalc->high,pcalc->low,pcalc->lolo)) return(-1); + if(recGblReportGblChoice(fp,pcalc,"HHSV",pcalc->hhsv)) return(-1); + if(recGblReportGblChoice(fp,pcalc,"HSV ",pcalc->hsv)) return(-1); + if(recGblReportGblChoice(fp,pcalc,"LSV ",pcalc->lsv)) return(-1); + if(recGblReportGblChoice(fp,pcalc,"LLSV",pcalc->llsv)) return(-1); + if(fprintf(fp,"HYST %-12.4G ADEL %-12.4G MDEL %-12.4G\n", + pcalc->hyst,pcalc->adel,pcalc->mdel)) return(-1); + if(fprintf(fp,"ACHN %d\n",pcalc->achn)) return(-1); + if(fprintf(fp,"LALM %-12.4G ALST %-12.4G MLST %-12.4G\n", + pcalc->lalm,pcalc->alst,pcalc->mlst)) return(-1); + if(fprintf(fp,"CALC %s\n",pcalc->calc)) return(-1); + return(0); +} + +static long init_record(pcalc) + struct calcRecord *pcalc; +{ + long status; + short error_number; + char rpbuf[80]; + + if(pcalc->inpa.type==CONSTANT) pcalc->a = pcalc->inpa.value.value; + if(pcalc->inpb.type==CONSTANT) pcalc->b = pcalc->inpb.value.value; + if(pcalc->inpc.type==CONSTANT) pcalc->c = pcalc->inpc.value.value; + if(pcalc->inpd.type==CONSTANT) pcalc->d = pcalc->inpd.value.value; + if(pcalc->inpe.type==CONSTANT) pcalc->e = pcalc->inpe.value.value; + if(pcalc->inpf.type==CONSTANT) pcalc->f = pcalc->inpf.value.value; + status=postfix(pcalc->calc,rpbuf,&error_number); + if(status) return(status); + bcopy(rpbuf,pcalc->rpcl,sizeof(pcalc->rpcl)); + return(0); +} + +static long special(paddr,after) + struct dbAddr *paddr; + int after; +{ + long status; + struct calcRecord *pcalc = (struct calcRecord *)(paddr->precord); + int special_type = paddr->special; + short error_number; + char rpbuf[80]; + + if(!after) return(0); + switch(special_type) { + case(SPC_CALC): + status=postfix(pcalc->calc,rpbuf,&error_number); + if(status) return(status); + bcopy(rpbuf,pcalc->rpcl,sizeof(pcalc->rpcl)); + return(0); + default: + recGblDbaddrError(S_db_badChoice,paddr,"calc: special"); + return(S_db_badChoice); + } +} + +static long get_precision(paddr,precision) + struct dbAddr *paddr; + long *precision; +{ + struct calcRecord *pcalc=(struct calcRecord *)paddr->precord; + + *precision = pcalc->prec; + return(0L); +} + +static long get_value(pcalc,pvdes) + struct calcRecord *pcalc; + struct valueDes *pvdes; +{ + pvdes->field_type = DBF_FLOAT; + pvdes->no_elements=1; + (float *)(pvdes->pvalue) = &pcalc->val; + return(0); +} + +static long get_units(paddr,units) + struct dbAddr *paddr; + char *units; +{ + struct calcRecord *pcalc=(struct calcRecord *)paddr->precord; + + strncpy(units,pcalc->egu,sizeof(pcalc->egu)); + return(0L); +} + +static long get_graphic_double(paddr,pgd) + struct dbAddr *paddr; + struct dbr_grDouble *pgd; +{ + struct calcRecord *pcalc=(struct calcRecord *)paddr->precord; + + pgd->upper_disp_limit = pcalc->hopr; + pgd->lower_disp_limit = pcalc->lopr; + pgd->upper_alarm_limit = pcalc->hihi; + pgd->upper_warning_limit = pcalc->high; + pgd->lower_warning_limit = pcalc->low; + pgd->lower_alarm_limit = pcalc->lolo; + return(0L); +} + +static long get_control_double(paddr,pcd) + struct dbAddr *paddr; + struct dbr_ctrlDouble *pcd; +{ + struct calcRecord *pcalc=(struct calcRecord *)paddr->precord; + + pcd->upper_ctrl_limit = pcalc->hopr; + pcd->lower_ctrl_limit = pcalc->lopr; + return(0L); +} + +static long process(paddr) + struct dbAddr *paddr; +{ + struct calcRecord *pcalc=(struct calcRecord *)(paddr->precord); + struct calcdset *pdset = (struct calcdset *)(pcalc->dset); + long status; + + pcalc->achn = 0; + /* read inputs */ + if (fetch_values(pcalc) < 0){ + if (pcalc->stat != READ_ALARM){ + pcalc->stat = READ_ALARM; + pcalc->sevr = MAJOR_ALARM; + pcalc->achn = 1; + monitor_calc(pcalc); + } + pcalc->pact = 0; + return(0); + }else{ + if (pcalc->stat == READ_ALARM){ + pcalc->stat = NO_ALARM; + pcalc->sevr = NO_ALARM; + pcalc->achn = 1; + } + } + + /* perform calculation */ + if (do_calc(pcalc) < 0){ + if (pcalc->stat != CALC_ALARM){ + pcalc->stat = CALC_ALARM; + pcalc->sevr = MAJOR_ALARM; + pcalc->achn = 1; + monitor_calc(pcalc); + } + pcalc->pact = 0; + return; + }else{ + if (pcalc->stat == CALC_ALARM){ + pcalc->stat = NO_ALARM; + pcalc->sevr = NO_ALARM; + pcalc->achn = 1; + } + } + + /* check for alarms */ + alarm(pcalc); + + + /* check event list */ + if(!pcalc->disa) status = monitor(pcalc); + + /* process the forward scan link record */ + if (pcalc->flnk.type==DB_LINK) dbScanPassive(&pcalc->flnk.value); + + pcalc->pact=FALSE; + return(status); +} + +/* + * DO_CALC + * + * execute the calculation + */ +#define NOT_SET 0 +#define TRUE_COND 1 +#define FALSE_COND 2 + +static do_calc(pcalc) +struct calcRecord *pcalc; /* pointer to calculation record */ +{ + char *post; /* postfix expression */ + double *pstacktop; /* stack of values */ + double stack[80]; + double temp; + short temp1; + short i; + double *top; + int itop; /* integer top value */ + int inexttop; /* ineteger next to top value */ + short cond_flag; /* conditional else flag */ + + /* initialize flag */ + cond_flag = NOT_SET; + pstacktop = &stack[0]; + + /* set post to postfix expression in calc structure */ + post = &pcalc->rpcl[0]; + top = pstacktop; + + /* polish calculator loop */ + while (*post != END_STACK){ + switch (*post){ + case FETCH_A: + ++pstacktop; + *pstacktop = pcalc->a; + break; + + case FETCH_B: + ++pstacktop; + *pstacktop = pcalc->b; + break; + + case FETCH_C: + ++pstacktop; + *pstacktop = pcalc->c; + break; + + case FETCH_D: + ++pstacktop; + *pstacktop = pcalc->d; + break; + + case FETCH_E: + ++pstacktop; + *pstacktop = pcalc->e; + break; + + case FETCH_F: + ++pstacktop; + *pstacktop = pcalc->f; + break; + + case ADD: + --pstacktop; + *pstacktop = *pstacktop + *(pstacktop+1); + break; + + case SUB: + --pstacktop; + *pstacktop = *pstacktop - *(pstacktop+1); + break; + + case MULT: + --pstacktop; + *pstacktop = *pstacktop * *(pstacktop+1); + break; + + case DIV: + --pstacktop; + if (*(pstacktop+1) == 0) /* can't divide by zero */ + return(-1); + *pstacktop = *pstacktop / *(pstacktop+1); + break; + + case COND_ELSE: + /* first conditional set cond_flag */ + /* true */ + if ((*pstacktop != 0.0) && (cond_flag == NOT_SET)){ + cond_flag = TRUE_COND; + --pstacktop; /* remove condition */ + /* false */ + }else if ((*pstacktop==0.0) && (cond_flag==NOT_SET)){ + cond_flag = FALSE_COND; + --pstacktop; /* remove condition */ + /* check for else condition */ + i = 1; + while (*(post+i) != COND_ELSE){ + /* no else value */ + if (*(post+i) == END_STACK){ + /* skip to end of expression */ + while (*(post+1) != END_STACK) + ++post; + /* use last value as result */ + ++pstacktop; + *pstacktop = pcalc->val; + } + i++; + } + }else if (cond_flag == TRUE_COND){ + /* skip expression - result is on stack */ + while ((*(post+1) != COND_ELSE) + && (*(post+1) != END_STACK)) + ++post; + }else if (cond_flag == FALSE_COND){ + /* remove true answer from stack top */ + --pstacktop; + } + break; + + case ABS_VAL: + if (*pstacktop < 0) *pstacktop = -*pstacktop; + break; + + case UNARY_NEG: + *pstacktop = -1* (*pstacktop); + break; + + case SQU_RT: + if (*pstacktop < 0) return(-1); /* undefined */ + *pstacktop = sqrt(*pstacktop); + break; + + case LOG_10: + *pstacktop = log10(*pstacktop); + break; + + case LOG_E: + *pstacktop = log(*pstacktop); + break; + + case RANDOM: + ++pstacktop; + *pstacktop = random(); + break; + + case EXPON: + --pstacktop; + if (*pstacktop < 0){ + temp1 = (int) *(pstacktop+1); + /* is exponent an integer */ + if ((*(pstacktop+1) - (double)temp1) != 0) return (-1); + *pstacktop = exp(*(pstacktop+1) * log(-*pstacktop)); + /* is value negative */ + if ((temp1 % 2) > 0) *pstacktop = -*pstacktop; + }else{ + *pstacktop = exp(*(pstacktop+1) * log(*pstacktop)); + } + break; + + case MODULO: + --pstacktop; + itop = (int)*pstacktop; + inexttop = (int)*(pstacktop+1); + if (inexttop == 0) + return(-1); + i = itop % inexttop; + *pstacktop = i; + break; + + case REL_OR: + --pstacktop; + *pstacktop = (*pstacktop || *(pstacktop+1)); + break; + + case REL_AND: + --pstacktop; + *pstacktop = (*pstacktop && *(pstacktop+1)); + break; + + case BIT_OR: + /* force double values into integers and or them */ + itop = (int)*pstacktop; + inexttop = (int)*(pstacktop-1); + --pstacktop; + *pstacktop = (inexttop | itop); + break; + + case BIT_AND: + /* force double values into integers and and them */ + itop = (int)*pstacktop; + inexttop = (int)*(pstacktop-1); + --pstacktop; + *pstacktop = (inexttop & itop); + break; + + case BIT_EXCL_OR: + /*force double values to integers to exclusive or them*/ + itop = (int)*pstacktop; + inexttop = (int)*(pstacktop-1); + --pstacktop; + *pstacktop = (inexttop ^ itop); + break; + + case GR_OR_EQ: + --pstacktop; + *pstacktop = *pstacktop >= *(pstacktop+1); + break; + + case GR_THAN: + --pstacktop; + *pstacktop = *pstacktop > *(pstacktop+1); + break; + + case LESS_OR_EQ: + --pstacktop; + *pstacktop = *pstacktop <= *(pstacktop+1); + break; + + case LESS_THAN: + --pstacktop; + *pstacktop = *pstacktop < *(pstacktop+1); + break; + + case NOT_EQ: + --pstacktop; + *pstacktop = *pstacktop != *(pstacktop+1); + break; + + case EQUAL: + --pstacktop; + *pstacktop = (*pstacktop == *(pstacktop+1)); + break; + + case RIGHT_SHIFT: + itop = (int)*pstacktop; + inexttop = (int)*(pstacktop-1); + --pstacktop; + *pstacktop = (inexttop >> itop); + break; + + case LEFT_SHIFT: + itop = (int)*pstacktop; + inexttop = (int)*(pstacktop-1); + --pstacktop; + *pstacktop = (inexttop << itop); + break; + + case ACOS: + *pstacktop = acos(*pstacktop); + break; + + case ASIN: + *pstacktop = asin(*pstacktop); + break; + + case ATAN: + *pstacktop = atan(*pstacktop); + break; + + case COS: + *pstacktop = cos(*pstacktop); + break; + + case SIN: + *pstacktop = sin(*pstacktop); + break; + + case TAN: + *pstacktop = tan(*pstacktop); + break; + + case COSH: + *pstacktop = cosh(*pstacktop); + break; + + case SINH: + *pstacktop = sinh(*pstacktop); + break; + + case TANH: + *pstacktop = tanh(*pstacktop); + break; + + default: + printf("%d bad expression element\n",*post); + break; + } + + /* move ahead in postfix expression */ + ++post; + } + + /* if everything is peachy,the stack should end at its first position */ + if (++top == pstacktop) + pcalc->val = *pstacktop; + else + return(-1); + return(0); +} + +/* + * FETCH_VALUES + * + * fetch the values for the variables in the calculation + */ +static fetch_values(pcalc) +struct calcRecord *pcalc; +{ + short status; + + /* note - currently not using alarm status */ + status = 0; + status |= get_calc_inp(&pcalc->inpa,&pcalc->a); + status |= get_calc_inp(&pcalc->inpb,&pcalc->b); + status |= get_calc_inp(&pcalc->inpc,&pcalc->c); + status |= get_calc_inp(&pcalc->inpd,&pcalc->d); + status |= get_calc_inp(&pcalc->inpe,&pcalc->e); + status |= get_calc_inp(&pcalc->inpf,&pcalc->f); + return(status); +} + +/* + * GET_CALC_INPUT + * + * return an input value + */ +static get_calc_inp(plink,pvalue) +struct link *plink; /* structure of the link field */ +float *pvalue; +{ + float float_value; + + /* hardware io into a calc not currently supported */ + if (plink->type == VME_IO){ + return(-1); + + /* database link */ + }else 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); + +} + +/* + * RANDOM + * + * generates a random number between 0 and 1 using the + * seed = (multy * seed) + addy Random Number Generator by Knuth + * SemiNumerical Algorithms + * Chapter 1 + * randy = 1.0 / (seed & 0xff) To normalize the number between 0 - 1 + */ +static unsigned short seed = 0xa3bf; +static unsigned short multy = 191 * 8 + 5; /* 191 % 8 == 5 */ +static unsigned short addy = 0x3141; +static double random() +{ + double randy; + + /* random number */ + seed = (seed * multy) + addy; + randy = 1.0 / (seed & 0xff); + + /* between 0 - 1 */ + return(randy); +} + +static long alarm(pcalc) + struct calcRecord *pcalc; +{ + float ftemp; + + /* if in alarm and difference is not > hysterisis don't bother */ + if (pcalc->stat != NO_ALARM){ + ftemp = pcalc->lalm - pcalc->val; + if(ftemp<0.0) ftemp = -ftemp; + if (ftemp < pcalc->hyst) return(0); + } + + /* alarm condition hihi */ + if (pcalc->hhsv != NO_ALARM){ + if (pcalc->val > pcalc->hihi){ + pcalc->lalm = pcalc->val; + if (pcalc->stat != HIHI_ALARM){ + pcalc->stat = HIHI_ALARM; + pcalc->sevr = pcalc->hhsv; + pcalc->achn = 1; + } + return(0); + } + } + + /* alarm condition lolo */ + if (pcalc->llsv != NO_ALARM){ + if (pcalc->val < pcalc->lolo){ + pcalc->lalm = pcalc->val; + if (pcalc->stat != LOLO_ALARM){ + pcalc->stat = LOLO_ALARM; + pcalc->sevr = pcalc->llsv; + pcalc->achn = 1; + } + return(0); + } + } + + /* alarm condition high */ + if (pcalc->hsv != NO_ALARM){ + if (pcalc->val > pcalc->high){ + pcalc->lalm = pcalc->val; + if (pcalc->stat != HIGH_ALARM){ + pcalc->stat = HIGH_ALARM; + pcalc->sevr =pcalc->hsv; + pcalc->achn = 1; + } + return(0); + } + } + + /* alarm condition lolo */ + if (pcalc->lsv != NO_ALARM){ + if (pcalc->val < pcalc->low){ + pcalc->lalm = pcalc->val; + if (pcalc->stat != LOW_ALARM){ + pcalc->stat = LOW_ALARM; + pcalc->sevr = pcalc->lsv; + pcalc->achn = 1; + } + return(0); + } + } + + /* no alarm */ + if (pcalc->stat != NO_ALARM){ + pcalc->stat = NO_ALARM; + pcalc->sevr = NO_ALARM; + pcalc->achn = 1; + } + + return(0); +} + +static long monitor(pcalc) + struct calcRecord *pcalc; +{ + unsigned short monitor_mask; + float delta; + + /* anyone wcalcting for an event on this record */ + if (pcalc->mlis.count == 0) return(0L); + + /* Flags which events to fire on the value field */ + monitor_mask = 0; + + /* alarm condition changed this scan */ + if (pcalc->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(pcalc,&pcalc->stat,DBE_VALUE); + db_post_events(pcalc,&pcalc->sevr,DBE_VALUE); + + /* update last value monitored */ + pcalc->mlst = pcalc->val; + + /* check for value change */ + }else{ + delta = pcalc->mlst - pcalc->val; + if(delta<0.0) delta = -delta; + if (delta > pcalc->mdel) { + /* post events for value change */ + monitor_mask = DBE_VALUE; + + /* update last value monitored */ + pcalc->mlst = pcalc->val; + } + } + + /* check for archive change */ + delta = pcalc->alst - pcalc->val; + if(delta<0.0) delta = 0.0; + if (delta > pcalc->adel) { + /* post events on value field for archive change */ + monitor_mask |= DBE_LOG; + + /* update last archive value monitored */ + pcalc->alst = pcalc->val; + } + + /* send out monitors connected to the value field */ + if (monitor_mask){ + db_post_events(pcalc,&pcalc->val,monitor_mask); + } + return(0L); +} + +/* + * POSTFIX.C + * + * Subroutines used to convert an infix expression to a postfix expression + * + * Author: Bob Dalesio + * Date: 12-12-86 + * @(#)postfix.c 1.1 9/21/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: + * Andy Kozubal, AT-8, Mail Stop H820 + * Los Alamos National Laboratory + * Los Alamos, New Mexico 87545 + * Phone: (505) 667-6508 + * E-mail: kozubal@k2.lanl.gov + * + * Modification Log: + * ----------------- + * .01 01-11-89 lrd added right shift and left shift operations + * .02 01-13-89 lrd modified to load into IOCs + * .03 02-01-89 lrd added trigonometric functions + * .04 04-05-89 lrd fixed the order of some operations in the + * element table and added a warning label +*/ + +/* + * Subroutines + * + * find_element finds a symbolic element in the expression element tbl + * args + * pbuffer pointer to the infox expression element + * pelement pointer to the expression element table entry + * pno_bytes pointer to the size of this element + * returns + * TRUE element found + * FALSE element not found + * get_element finds the next expression element in the infix expr + * args + * pinfix pointer into the infix expression + * pelement pointer to the expression element table + * pno_bytes size of the element in the infix expression + * returns + * FINE found an expression element + * VARIABLE found a database reference + * UNKNOWN_ELEMENT unknown element found in the infix expression + * match_element finds an alpha element in the expression table + * args + * pbuffer pointer to an alpha expression element + * pelement pointer to the expression element table + * returns + * TRUE found the element in the element table + * FLASE expression element not found + * postfix convert an algebraic expression to symbolic postfix + * args + * pinfix the algebraic expression + * ppostfix the symbolic postfix expression + * returns + * 0 successful + * -1 not successful + */ + +/* element types */ +#define OPERAND 0 +#define UNARY_OPERATOR 1 +#define BINARY_OPERATOR 2 +#define EXPR_TERM 3 +#define COND 4 +#define CLOSE_PAREN 5 +#define CONDITIONAL 6 +#define ELSE 7 +#define TRASH 8 + +/* flags end of element table */ +#define END_ELEMENTS -1 + +/* parsing return values */ +#define FINE 0 +#define UNKNOWN_ELEMENT -1 +#define END -2 + +/* + * element table + * + * structure of an element + */ +struct expression_element{ + char element[10]; /* character representation of an element */ + char in_stack_pri; /* priority in translation stack */ + char in_coming_pri; /* priority when first checking */ + char type; /* element type */ + char code; /* postfix representation */ +}; + +/* + * NOTE: DO NOT CHANGE WITHOUT READING THIS NOTICE !!!!!!!!!!!!!!!!!!!! + * Because the routine that looks for a match in this table takes the first + * match it finds, elements whose designations are contained in other elements + * MUST come first in this list. (e.g. ABS will match A if A preceeds ABS and + * then try to find BS therefore ABS must be first in this list + */ +static struct expression_element elements[] = { +/* element i_s_p i_c_p type_element internal_rep */ +"ABS", 7, 8, UNARY_OPERATOR, ABS_VAL, /* absolute value */ +"NOT", 7, 8, UNARY_OPERATOR, UNARY_NEG, /* unary negate */ +"SQR", 7, 8, UNARY_OPERATOR, SQU_RT, /* square root */ +"LOG", 7, 8, UNARY_OPERATOR, LOG_10, /* log 10 */ +"LOGE", 7, 8, UNARY_OPERATOR, LOG_E, /* log E */ +"ACOS", 7, 8, UNARY_OPERATOR, ACOS, /* arc cosine */ +"ASIN", 7, 8, UNARY_OPERATOR, ASIN, /* arc sine */ +"ATAN", 7, 8, UNARY_OPERATOR, ATAN, /* arc tangent */ +"COS", 7, 8, UNARY_OPERATOR, COS, /* cosine */ +"COSH", 7, 8, UNARY_OPERATOR, COSH, /* hyperbolic cosine */ +"SIN", 7, 8, UNARY_OPERATOR, SIN, /* sine */ +"SINH", 7, 8, UNARY_OPERATOR, SINH, /* hyperbolic sine */ +"TAN", 7, 8, UNARY_OPERATOR, TAN, /* tangent */ +"TANH", 7, 8, UNARY_OPERATOR, TANH, /* hyperbolic tangent*/ +"RNDM", 0, 0, OPERAND, RANDOM, /* Random Number */ +"OR", 1, 1, BINARY_OPERATOR,BIT_OR, /* or */ +"AND", 2, 2, BINARY_OPERATOR,BIT_AND, /* and */ +"XOR", 1, 1, BINARY_OPERATOR,BIT_EXCL_OR, /* exclusive or */ +"A", 0, 0, OPERAND, FETCH_A, /* fetch var A */ +"B", 0, 0, OPERAND, FETCH_B, /* fetch var B */ +"C", 0, 0, OPERAND, FETCH_C, /* fetch var C */ +"D", 0, 0, OPERAND, FETCH_D, /* fetch var D */ +"E", 0, 0, OPERAND, FETCH_E, /* fetch var E */ +"F", 0, 0, OPERAND, FETCH_F, /* fetch var F */ +"a", 0, 0, OPERAND, FETCH_A, /* fetch var A */ +"b", 0, 0, OPERAND, FETCH_B, /* fetch var B */ +"c", 0, 0, OPERAND, FETCH_C, /* fetch var C */ +"d", 0, 0, OPERAND, FETCH_D, /* fetch var D */ +"e", 0, 0, OPERAND, FETCH_E, /* fetch var E */ +"f", 0, 0, OPERAND, FETCH_F, /* fetch var F */ +"?", 0, 0, CONDITIONAL, COND_ELSE, /* conditional */ +":", 0, 0, ELSE, COND_ELSE, /* else */ +"(", 0, 8, UNARY_OPERATOR, PAREN, /* open paren */ +"^", 6, 6, BINARY_OPERATOR,EXPON, /* exponentiation */ +"**", 6, 6, BINARY_OPERATOR,EXPON, /* exponentiation */ +"+", 4, 4, BINARY_OPERATOR,ADD, /* addition */ +"-", 4, 4, BINARY_OPERATOR,SUB, /* subtraction */ +"*", 5, 5, BINARY_OPERATOR,MULT, /* multiplication */ +"/", 5, 5, BINARY_OPERATOR,DIV, /* division */ +"%", 5, 5, BINARY_OPERATOR,MODULO, /* modulo */ +")", 0, 0, CLOSE_PAREN, PAREN, /* close paren */ +"||", 1, 1, BINARY_OPERATOR,REL_OR, /* or */ +"|", 1, 1, BINARY_OPERATOR,BIT_OR, /* or */ +"&&", 2, 2, BINARY_OPERATOR,REL_AND, /* and */ +"&", 2, 2, BINARY_OPERATOR,BIT_AND, /* and */ +">>", 2, 2, BINARY_OPERATOR,RIGHT_SHIFT, /* right shift */ +">=", 3, 3, BINARY_OPERATOR,GR_OR_EQ, /* greater or equal*/ +">", 3, 3, BINARY_OPERATOR,GR_THAN, /* greater than */ +"<<", 2, 2, BINARY_OPERATOR,LEFT_SHIFT, /* left shift */ +"<=", 3, 3, BINARY_OPERATOR,LESS_OR_EQ,/* less or equal to*/ +"<", 3, 3, BINARY_OPERATOR,LESS_THAN, /* less than */ +"#", 3, 3, BINARY_OPERATOR,NOT_EQ, /* not equal */ +"=", 3, 3, BINARY_OPERATOR,EQUAL, /* equal */ +"" +}; + +/* + * FIND_ELEMENT + * + * find the pointer to an entry in the element table + */ + find_element(pbuffer,pelement,pno_bytes) +#define SAME 0 + char *pbuffer; + struct expression_element **pelement; + short *pno_bytes; + { + + /* compare the string to each element in the element table */ + *pelement = &elements[0]; + while ((*pelement)->element[0] != NULL){ + if (strncmp(pbuffer,(*pelement)->element, + strlen((*pelement)->element)) == SAME){ + *pno_bytes += strlen((*pelement)->element); + return(TRUE); + } + *pelement += 1; + } + return(FALSE); + } + +/* + * GET_ELEMENT + * + * get an expression element + */ +get_element(pinfix,pelement,pno_bytes) +char *pinfix; +struct expression_element **pelement; +short *pno_bytes; +{ + char buffer[40]; + short i; + + /* get the next expression element from the infix expression */ + if (*pinfix == NULL) return(END); + *pno_bytes = 0; + while (*pinfix == 0x20){ + *pno_bytes += 1; + pinfix++; + } + if (!find_element(pinfix,pelement,pno_bytes)) + return(UNKNOWN_ELEMENT); + return(FINE); + + +} + +/* + * POSTFIX + * + * convert an infix expression to a postfix expression + */ +long postfix(pinfix,ppostfix,perror) +char *pinfix; +char *ppostfix; +short *perror; +{ + short got_if; + short got_else; + short no_bytes; + short operand_needed; + short new_expression; + short link_inx; /* index into variable table */ + struct expression_element stack[80]; + struct expression_element *pelement; + struct expression_element *pstacktop; + + /* place the expression elements into postfix */ + got_if = FALSE; + got_else = FALSE; + operand_needed = TRUE; + new_expression = TRUE; + pstacktop = &stack[0]; + while (get_element(pinfix,&pelement,&no_bytes) != END){ + + pinfix += no_bytes; + switch (pelement->type){ + + case OPERAND: + if (!operand_needed){ + *perror = 5; + return(-1); + } + + /* add operand to the expression */ + *ppostfix++ = pelement->code; + + operand_needed = FALSE; + new_expression = FALSE; + break; + + case BINARY_OPERATOR: + if (operand_needed){ + *perror = 4; + return(-1); + } + + /* add operators of higher or equal priority to */ + /* postfix notation */ + while ((pstacktop->in_stack_pri >= pelement->in_coming_pri) + && (pstacktop >= &stack[1])){ + *ppostfix++ = pstacktop->code; + pstacktop--; + } + + /* add new operator to stack */ + pstacktop++; + *pstacktop = *pelement; + + operand_needed = TRUE; + break; + + case UNARY_OPERATOR: + if (!operand_needed){ + *perror = 5; + return(-1); + } + + /* add operators of higher or equal priority to */ + /* postfix notation */ + while ((pstacktop->in_stack_pri >= pelement->in_coming_pri) + && (pstacktop >= &stack[1])){ + *ppostfix++ = pstacktop->code; + pstacktop--; + } + + /* add new operator to stack */ + pstacktop++; + *pstacktop = *pelement; + + new_expression = FALSE; + break; + + case CLOSE_PAREN: + if (operand_needed){ + *perror = 4; + return(-1); + } + + /* add operators to postfix until matching paren */ + while (pstacktop->element[0] != '('){ + if (pstacktop == &stack[1]){ + *perror = 6; + return(-1); + } + *ppostfix++ = pstacktop->code; + pstacktop--; + } + pstacktop--; /* remove ( from stack */ + break; + + /* conditional includes expression termination */ + case CONDITIONAL: + if (got_if){ + *perror = 9; + return(-1); + } + got_if = TRUE; + + /* else includes expression termination */ + case ELSE: + if (pelement->type == ELSE){ + if (!got_if){ + *perror = 11; + return(-1); + } + if (got_else){ + *perror = 10; + return(-1); + } + got_else = TRUE; + } + + case EXPR_TERM: + if (operand_needed && !new_expression){ + *perror = 4; + return(-1); + } + + /* add all operators on stack to postfix */ + while (pstacktop >= &stack[1]){ + if (pstacktop->element[0] == '('){ + *perror = 6; + return(-1); + } + *ppostfix++ = pstacktop->code; + pstacktop--; + } + + /* add new element to the postfix expression */ + *ppostfix++ = pelement->code; + + operand_needed = TRUE; + new_expression = TRUE; + break; + + + default: + *perror = 8; + return(-1); + } + } + if (operand_needed){ + *perror = 4; + return(-1); + } + + /* add all operators on stack to postfix */ + while (pstacktop >= &stack[1]){ + if (pstacktop->element[0] == '('){ + *perror = 6; + return(-1); + } + *ppostfix++ = pstacktop->code; + pstacktop--; + } + *ppostfix = END_STACK; + + return(0); +} diff --git a/src/rec/recCompress.c b/src/rec/recCompress.c new file mode 100644 index 000000000..23232673a --- /dev/null +++ b/src/rec/recCompress.c @@ -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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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)++ 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)++ 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)++ 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)++ 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; + } + } +} + diff --git a/src/rec/recFanout.c b/src/rec/recFanout.c new file mode 100644 index 000000000..928e7285e --- /dev/null +++ b/src/rec/recFanout.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/src/rec/recMbbi.c b/src/rec/recMbbi.c new file mode 100644 index 000000000..288e87709 --- /dev/null +++ b/src/rec/recMbbi.c @@ -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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/src/rec/recMbbo.c b/src/rec/recMbbo.c new file mode 100644 index 000000000..7608f504b --- /dev/null +++ b/src/rec/recMbbo.c @@ -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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/src/rec/recPermissive.c b/src/rec/recPermissive.c new file mode 100644 index 000000000..6ae5a046f --- /dev/null +++ b/src/rec/recPermissive.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/src/rec/recPid.c b/src/rec/recPid.c new file mode 100644 index 000000000..b574279a3 --- /dev/null +++ b/src/rec/recPid.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/src/rec/recSel.c b/src/rec/recSel.c new file mode 100644 index 000000000..2e7e06404 --- /dev/null +++ b/src/rec/recSel.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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; itype==DB_LINK) { + nRequest=1; + status=dbGetLink(plink,DBR_FLOAT,pvalue,&options,&nRequest); + if(status!=0) return(status); + } + } + return(0); +} diff --git a/src/rec/recState.c b/src/rec/recState.c new file mode 100644 index 000000000..464b4bb92 --- /dev/null +++ b/src/rec/recState.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/src/rec/recSub.c b/src/rec/recSub.c new file mode 100644 index 000000000..8245bbe43 --- /dev/null +++ b/src/rec/recSub.c @@ -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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/src/rec/recTimer.c b/src/rec/recTimer.c new file mode 100644 index 000000000..8accf19e2 --- /dev/null +++ b/src/rec/recTimer.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +}