/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
*     National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
*     Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution. 
\*************************************************************************/

/* $Revision-Id$ */

/* recEvent.c - Record Support Routines for Event records */
/*
 *      Author:          Janet Anderson
 *      Date:            12-13-91
 */

#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include "dbDefs.h"
#include "epicsPrint.h"
#include "alarm.h"
#include "dbAccess.h"
#include "dbEvent.h"
#include "dbScan.h"
#include "dbFldTypes.h"
#include "devSup.h"
#include "errMdef.h"
#include "recSup.h"
#include "recGbl.h"
#include "menuYesNo.h"
#define GEN_SIZE_OFFSET
#include "eventRecord.h"
#undef  GEN_SIZE_OFFSET
#include "epicsExport.h"

/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
static long init_record(eventRecord *, int);
static long process(eventRecord *);
#define special NULL
static long get_value(eventRecord *, struct valueDes *);
#define cvt_dbaddr NULL
#define get_array_info NULL
#define put_array_info NULL
#define get_units NULL
#define get_precision NULL
#define get_enum_str NULL
#define get_enum_strs NULL
#define put_enum_str NULL
#define get_graphic_double NULL
#define get_control_double NULL
#define get_alarm_double NULL

rset eventRSET={
	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
};
epicsExportAddress(rset,eventRSET);

struct eventdset { /* event input dset */
	long		number;
	DEVSUPFUN	dev_report;
	DEVSUPFUN	init;
	DEVSUPFUN	init_record; /*returns: (-1,0)=>(failure,success)*/
	DEVSUPFUN	get_ioint_info;
	DEVSUPFUN	read_event;/*(0)=> success */
};
static void monitor(eventRecord *);
static long readValue(eventRecord *);


static long init_record(eventRecord *prec, int pass)
{
    struct eventdset *pdset;
    long status=0;

    if (pass==0) return(0);

    if (prec->siml.type == CONSTANT) {
	recGblInitConstantLink(&prec->siml,DBF_USHORT,&prec->simm);
    }

    if (prec->siol.type == CONSTANT) {
	recGblInitConstantLink(&prec->siol,DBF_USHORT,&prec->sval);
    }

    if( (pdset=(struct eventdset *)(prec->dset)) && (pdset->init_record) ) 
		status=(*pdset->init_record)(prec);
    return(status);
}

static long process(eventRecord *prec)
{
	struct eventdset	*pdset = (struct eventdset *)(prec->dset);
	long		 status=0;
	unsigned char    pact=prec->pact;

	if((pdset!=NULL) && (pdset->number >= 5) && pdset->read_event ) 
                status=readValue(prec); /* read the new value */
	/* check if device support set pact */
	if ( !pact && prec->pact ) return(0);
	prec->pact = TRUE;
 
	if(prec->val>0) post_event((int)prec->val);

	recGblGetTimeStamp(prec);

	/* check event list */
	monitor(prec);

	/* process the forward scan link record */
	recGblFwdLink(prec);

	prec->pact=FALSE;
	return(status);
}


static long get_value(eventRecord *prec, struct valueDes *pvdes)
{
    pvdes->field_type = DBF_USHORT;
    pvdes->no_elements=1;
    pvdes->pvalue = (void *)(&prec->val);
    return(0);
}


static void monitor(eventRecord *prec)
{
    unsigned short  monitor_mask;

    /* get previous stat and sevr  and new stat and sevr*/
    monitor_mask = recGblResetAlarms(prec);
    db_post_events(prec,&prec->val,monitor_mask|DBE_VALUE);
    return;
}

static long readValue(eventRecord *prec)
{
        long            status;
        struct eventdset   *pdset = (struct eventdset *) (prec->dset);

        if (prec->pact == TRUE){
                status=(*pdset->read_event)(prec);
                return(status);
        }

        status=dbGetLink(&(prec->siml),DBR_USHORT,&(prec->simm),0,0);

        if (status)
                return(status);

        if (prec->simm == menuYesNoNO){
                status=(*pdset->read_event)(prec);
                return(status);
        }
        if (prec->simm == menuYesNoYES){
                status=dbGetLink(&(prec->siol),DBR_USHORT,
			&(prec->sval),0,0);
                if (status==0) {
                        prec->val=prec->sval;
                        prec->udf=FALSE;
                }
        } else {
                status=-1;
                recGblSetSevr(prec,SOFT_ALARM,INVALID_ALARM);
                return(status);
        }
        recGblSetSevr(prec,SIMM_ALARM,prec->sims);

        return(status);
}
