diff --git a/src/rec/recSubArray.c b/src/rec/recSubArray.c new file mode 100644 index 000000000..1a9f36ca8 --- /dev/null +++ b/src/rec/recSubArray.c @@ -0,0 +1,360 @@ +/* recSubArray.c */ +/* recSubArray.c - Record Support Routines for SubArray records + * + * + * Author: Carl Lionberger + * Date: 090293 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * The Control Systems Group + * Systems Engineering Department + * Lawrence Berkeley Laboratory + * + * NOTES: + * Derived from waveform record. + * Modification Log: + * ----------------- + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Create RSET - Record Support Entry Table*/ +#define report NULL +#define initialize NULL +static long init_record(); +static long process(); +#define special NULL +static long get_value(); +static long cvt_dbaddr(); +static long get_array_info(); +static long put_array_info(); +static long get_units(); +static long get_precision(); +#define get_enum_str NULL +#define get_enum_strs NULL +#define put_enum_str NULL +static long get_graphic_double(); +static long get_control_double(); +#define get_alarm_double NULL + +struct rset subArrayRSET={ + RSETNUMBER, + report, + initialize, + init_record, + process, + special, + get_value, + cvt_dbaddr, + get_array_info, + put_array_info, + get_units, + get_precision, + get_enum_str, + get_enum_strs, + put_enum_str, + get_graphic_double, + get_control_double, + get_alarm_double }; + +struct sadset { /* subArray dset */ + long number; + DEVSUPFUN dev_report; + DEVSUPFUN init; + DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/ + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_sa; /*returns: (-1,0)=>(failure,success)*/ +}; + +/*sizes of field types*/ +static int sizeofTypes[] = {MAX_STRING_SIZE,1,1,2,2,4,4,4,8,2}; + +static void monitor(); +static long readValue(); + +/*Following from timing system */ +extern unsigned int gts_trigger_counter; + + +static long init_record(psa,pass) + struct subArrayRecord *psa; + int pass; +{ + struct sadset *pdset; + long status; + + if (pass==0){ + if(psa->malm<=0) psa->malm=1; + + if(psa->ftvl>DBF_ENUM) psa->ftvl=2; + psa->bptr = (char *)calloc(psa->malm,sizeofTypes[psa->ftvl]); + psa->nord = 0; + return(0); + } + + /* must have dset defined */ + if(!(pdset = (struct sadset *)(psa->dset))) { + recGblRecordError(S_dev_noDSET,(void *)psa,"sa: init_record"); + return(S_dev_noDSET); + } + /* must have read_sa function defined */ + if( (pdset->number < 5) || (pdset->read_sa == NULL) ) { + recGblRecordError(S_dev_missingSup,(void *)psa,"sa: init_record"); + return(S_dev_missingSup); + } + if( pdset->init_record ) { + if((status=(*pdset->init_record)(psa))) return(status); + } + return(0); +} + +static long process(psa) + struct subArrayRecord *psa; +{ + struct sadset *pdset = (struct sadset *)(psa->dset); + long status; + unsigned char pact=psa->pact; + + if( (pdset==NULL) || (pdset->read_sa==NULL) ) { + psa->pact=TRUE; + recGblRecordError(S_dev_missingSup,(void *)psa,"read_sa"); + return(S_dev_missingSup); + } + /* event throttling */ + if (psa->scan == SCAN_IO_EVENT){ + if ((psa->evnt != 0) && (gts_trigger_counter != 0)){ + if ((gts_trigger_counter % psa->evnt) != 0){ + return(0); + } + } + } + if (pact) return(0); + status=readValue(psa); /* read the new value */ + if (!pact && psa->pact) return(0); + psa->pact = TRUE; + + psa->udf=FALSE; + tsLocalTime(&psa->time); + monitor(psa); + + /* process the forward scan link record */ + recGblFwdLink(psa); + + psa->pact=FALSE; + return(0); +} + +static long get_value(psa,pvdes) + struct subArrayRecord *psa; + struct valueDes *pvdes; +{ + pvdes->pvalue = psa->bptr; + if (!psa->udf && psa->nelm > psa->nord) + pvdes->no_elements=psa->nord; + else + pvdes->no_elements=psa->nelm; + pvdes->field_type = psa->ftvl; + return(0); +} + +static long cvt_dbaddr(paddr) + struct dbAddr *paddr; +{ + struct subArrayRecord *psa=(struct subArrayRecord *)paddr->precord; + + paddr->pfield = psa->bptr; + if (!psa->udf && psa->nelm > psa->nord) + paddr->no_elements = psa->nord; + else + paddr->no_elements = psa->nelm; + paddr->field_type = psa->ftvl; + paddr->field_size = sizeofTypes[psa->ftvl]; + paddr->dbr_field_type = psa->ftvl; + return(0); +} + +static long get_array_info(paddr,no_elements,offset) + struct dbAddr *paddr; + long *no_elements; + long *offset; +{ + struct subArrayRecord *psa=(struct subArrayRecord *)paddr->precord; + + if (!psa->udf && psa->nelm > psa->nord) + *no_elements = psa->nord; + else + *no_elements = psa->nelm; + *offset = 0; + return(0); +} + +static long put_array_info(paddr,nNew) + struct dbAddr *paddr; + long nNew; +{ + struct subArrayRecord *psa=(struct subArrayRecord *)paddr->precord; + + if(nNew > psa->malm) + psa->nord = psa->malm; + else + psa->nord = nNew; + return(0); +} + +static long get_units(paddr,units) + struct dbAddr *paddr; + char *units; +{ + struct subArrayRecord *psa=(struct subArrayRecord *)paddr->precord; + + strncpy(units,psa->egu,sizeof(psa->egu)); + return(0); +} + +static long get_precision(paddr,precision) + struct dbAddr *paddr; + long *precision; +{ + struct subArrayRecord *psa=(struct subArrayRecord *)paddr->precord; + + *precision = psa->prec; + if(paddr->pfield==psa->bptr) + return(0); + recGblGetPrec(paddr,precision); + return(0); +} + +static long get_graphic_double(paddr,pgd) + struct dbAddr *paddr; + struct dbr_grDouble *pgd; +{ + struct subArrayRecord *psa=(struct subArrayRecord *)paddr->precord; + + if(paddr->pfield==psa->bptr) { + pgd->upper_disp_limit = psa->hopr; + pgd->lower_disp_limit = psa->lopr; + return(0); + } + if(paddr->pfield==(void *)&psa->indx) { + pgd->upper_disp_limit = psa->malm - 1; + pgd->lower_disp_limit = 0; + return(0); + } + if(paddr->pfield==(void *)&psa->nelm) { + pgd->upper_disp_limit = psa->malm; + pgd->lower_disp_limit = 1; + return(0); + } + recGblGetGraphicDouble(paddr,pgd); + return(0); +} +static long get_control_double(paddr,pcd) + struct dbAddr *paddr; + struct dbr_ctrlDouble *pcd; +{ + struct subArrayRecord *psa=(struct subArrayRecord *)paddr->precord; + + if(paddr->pfield==psa->bptr) { + pcd->upper_ctrl_limit = psa->hopr; + pcd->lower_ctrl_limit = psa->lopr; + return(0); + } + if(paddr->pfield==psa->bptr) { + pcd->upper_ctrl_limit = psa->malm - 1; + pcd->lower_ctrl_limit = 0; + return(0); + } + if(paddr->pfield==psa->bptr) { + pcd->upper_ctrl_limit = psa->malm; + pcd->lower_ctrl_limit = 1; + return(0); + } + recGblGetControlDouble(paddr,pcd); + return(0); +} + +static void monitor(psa) + struct subArrayRecord *psa; +{ + unsigned short monitor_mask; + short stat,sevr,nsta,nsev; + + /* get previous stat and sevr and new stat and sevr*/ + recGblResetSevr(psa,stat,sevr,nsta,nsev); + + /* Flags which events to fire on the value field */ + monitor_mask = 0; + + /* alarm condition changed this scan */ + if (stat!=nsta || sevr!=nsev) { + /* post events for alarm condition change*/ + monitor_mask = DBE_ALARM; + /* post stat and nsev fields */ + db_post_events(psa,&psa->stat,DBE_VALUE); + db_post_events(psa,&psa->sevr,DBE_VALUE); + } + monitor_mask |= (DBE_LOG|DBE_VALUE); + if(monitor_mask) + db_post_events(psa, psa->bptr, monitor_mask); + return; +} + +static long readValue(psa) + struct subArrayRecord *psa; +{ + long status; + struct sadset *pdset = (struct sadset *) (psa->dset); + + if (psa->nelm > psa->malm) + { + psa->nelm = psa->malm; + } + if (psa->indx >= psa->malm) + { + psa->indx = psa->malm - 1; + } + status = (*pdset->read_sa)(psa); + + if (psa->nord <= 0) + { + status = -1; + psa->indx = 0; + } + return(status); +} +