From dc4228900b3f55c1abbeec8abb787ad280f0d4a0 Mon Sep 17 00:00:00 2001 From: John Winans Date: Wed, 8 Jun 1994 10:49:42 +0000 Subject: [PATCH] Initial revision --- src/dev/devApsEg.c | 2060 ++++++++++++++++++++++++++++++++++++++++++ src/dev/devApsEr.c | 1151 +++++++++++++++++++++++ src/rec/recEg.c | 201 +++++ src/rec/recEgevent.c | 265 ++++++ src/rec/recEr.c | 305 +++++++ src/rec/recErevent.c | 191 ++++ 6 files changed, 4173 insertions(+) create mode 100644 src/dev/devApsEg.c create mode 100644 src/dev/devApsEr.c create mode 100644 src/rec/recEg.c create mode 100644 src/rec/recEgevent.c create mode 100644 src/rec/recEr.c create mode 100644 src/rec/recErevent.c diff --git a/src/dev/devApsEg.c b/src/dev/devApsEg.c new file mode 100644 index 000000000..8d32f7b4e --- /dev/null +++ b/src/dev/devApsEg.c @@ -0,0 +1,2060 @@ +/* #define EG_DEBUG /**/ +/* + +***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE, +AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE +AND IN ALL SOURCE LISTINGS OF THE CODE. + +(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + +Argonne National Laboratory (ANL), with facilities in the States of +Illinois and Idaho, is owned by the United States Government, and +operated by the University of Chicago under provision of a contract +with the Department of Energy. + +Portions of this material resulted from work developed under a U.S. +Government contract and are subject to the following license: For +a period of five years from March 30, 1993, the Government is +granted for itself and others acting on its behalf a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, and perform +publicly and display publicly. With the approval of DOE, this +period may be renewed for two additional five year periods. +Following the expiration of this period or periods, the Government +is granted for itself and others acting on its behalf, a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, distribute copies +to the public, perform publicly and display publicly, and to permit +others to do so. + +***************************************************************** + DISCLAIMER +***************************************************************** + +NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR +THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS, +MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL +LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR +USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS +DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY +OWNED RIGHTS. + +***************************************************************** +LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY +DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000). +*/ + +/* + * Author: John R. Winans + * Date: 07-21-93 + * + * PROBLEMS: + * -When transisioning from ALTERNATE mode to anything else, the mode MUST + * be set to OFF long enough to clear/reload the RAMS first. + * -In SINGLE mode, to rearm, the mode must be set to OFF, then back to SINGLE. + * + * Modification Log: + * ----------------- +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef EG_DEBUG +#define STATIC +#else +#define STATIC static +#endif + +#define EG_MONITOR /* Include the EG monitor program */ +#define RAM_LOAD_SPIN_DELAY 1 /* taskDelay() for waiting on RAM */ + +/* Only look at these bits when ORing on new bits in the control register */ +#define CTL_OR_MASK (0x9660) + +typedef struct ApsEgStruct +{ + unsigned short Control; + unsigned short EventMask; + unsigned short VmeEvent; + unsigned short Seq2Addr; + unsigned short Seq2Data; + unsigned short Seq1Addr; + unsigned short Seq1Data; + + unsigned short Event0Map; + unsigned short Event1Map; + unsigned short Event2Map; + unsigned short Event3Map; + unsigned short Event4Map; + unsigned short Event5Map; + unsigned short Event6Map; + unsigned short Event7Map; +}ApsEgStruct; + +typedef struct +{ + ApsEgStruct *pEg; /* pointer to card described. */ + SEM_ID EgLock; + struct egRecord *pEgRec; /* Record that represents the card */ + double Ram1Speed; /* in Hz */ + long Ram1Dirty; /* needs to be reloaded */ + double Ram2Speed; /* in Hz */ + long Ram2Dirty; /* needs to be reloaded */ + ELLLIST EgEvent1; /* RAM1 event list head */ + ELLLIST EgEvent2; /* RAM2 event list head */ +} EgLinkStruct; + +typedef struct +{ + ELLNODE node; + struct egeventRecord *pRec; +} EgEventNode; + +STATIC long EgInitDev(int pass); +STATIC long EgInitRec(struct egRecord *pRec); +STATIC long EgProcEgRec(struct egRecord *pRec); +STATIC long EgDisableFifo(EgLinkStruct *pParm); +STATIC long EgEnableFifo(EgLinkStruct *pParm); +STATIC long EgMasterEnable(EgLinkStruct *pParm); +STATIC long EgMasterDisable(EgLinkStruct *pParm); +STATIC long EgClearSeq(EgLinkStruct *pParm, int channel); +STATIC long EgSetTrigger(EgLinkStruct *pParm, unsigned int Channel, unsigned short Event); +STATIC long EgEnableTrigger(EgLinkStruct *pParm, unsigned int Channel, int state); +STATIC int EgSeqEnableCheck(EgLinkStruct *pParm, unsigned int Seq); +STATIC long EgSeqTrigger(EgLinkStruct *pParm, unsigned int Seq); +STATIC long EgSetSeqMode(EgLinkStruct *pParm, unsigned int Seq, int Mode); +STATIC long EgEnableVme(EgLinkStruct *pParm, int state); +STATIC long EgGenerateVmeEvent(EgLinkStruct *pParm, int Event); +STATIC long EgResetAll(EgLinkStruct *pParm); +STATIC int EgReadSeqRam(EgLinkStruct *pParm, int channel, unsigned char *pBuf); +STATIC int EgWriteSeqRam(EgLinkStruct *pParm, int channel, unsigned char *pBuf); +STATIC int EgDumpRegs(EgLinkStruct *pParm); +STATIC int SetupSeqRam(EgLinkStruct *pParm, int channel); +STATIC void SeqConfigMenu(void); +STATIC void PrintSeq(EgLinkStruct *pParm, int channel); +STATIC int ConfigSeq(EgLinkStruct *pParm, int channel); +STATIC void menu(void); +STATIC long EgCheckTaxi(EgLinkStruct *pParm); +STATIC long EgScheduleRamProgram(int card); +STATIC long EgGetMode(EgLinkStruct *pParm, int ram); +STATIC long EgGetRamEvent(EgLinkStruct *pParm, long Ram, long Addr); +STATIC long EgMasterEnableGet(EgLinkStruct *pParm); +STATIC long EgCheckFifo(EgLinkStruct *pParm); +STATIC long EgGetTrigger(EgLinkStruct *pParm, unsigned int Channel); +STATIC long EgGetEnableTrigger(EgLinkStruct *pParm, unsigned int Channel); +STATIC long EgGetBusyStatus(EgLinkStruct *pParm, int Ram); +STATIC long EgProgramRamEvent(EgLinkStruct *pParm, long Ram, long Addr, long Event); +STATIC long EgGetAltStatus(EgLinkStruct *pParm, int Ram); +STATIC long EgEnableAltRam(EgLinkStruct *pParm, int Ram); + +#define NUM_EG_LINKS 4 /* Total allowed number of EG boards */ + +/* Parms for the event generator task */ +#define EGRAM_NAME "EgRam" +#define EGRAM_PRI 100 +#define EGRAM_OPT VX_FP_TASK|VX_STDIO +#define EGRAM_STACK 4000 + +static EgLinkStruct EgLink[NUM_EG_LINKS]; +static int EgNumLinks = 0; +static SEM_ID EgRamTaskEventSem; +static int ConfigureLock = 0; + +/****************************************************************************** + * + * Routine used to verify that a given card number is valid. + * Returns zero if valid, nonzero otherwise. + * + ******************************************************************************/ +STATIC long EgCheckCard(int Card) +{ + if ((Card < 0)||(Card >= EgNumLinks)) + return(-1); + if (EgLink[Card].pEg == NULL) + return(-1); + return(0); +} + +/****************************************************************************** + * + * User configurable card addresses are saved in this array. + * To configure them, use the EgConfigure command from the startup script + * when booting Epics. + * + ******************************************************************************/ +int EgConfigure(int Card, unsigned long CardAddress) +{ + unsigned long Junk; + + if (ConfigureLock != 0) + { + logMsg("devApsEg: Cannot change configuration after init. Request ignored\n"); + return(-1); + } + if (Card >= NUM_EG_LINKS) + { + logMsg("devApsEg: Card number invalid, must be 0-%d\n", NUM_EG_LINKS); + return(-1); + } + if (CardAddress > 0xffff) + { + logMsg("devApsEg: Card address invalid, must be 0x0000-0xffff\n"); + return(-1); + } + if(sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO, (char*)CardAddress, (char**)&EgLink[Card].pEg)!=OK) + { + logMsg("devApsEg: Failure mapping requested A16 address\n"); + EgLink[Card].pEg = NULL; + return(-1); + } + if (vxMemProbe((char*)&(EgLink[Card].pEg->Control), READ, sizeof(short), (char*)&Junk) != OK) + { + logMsg("devApsEg: Failure probing for event receiver... Card disabled\n"); + EgLink[Card].pEg = NULL; + return(-1); + } + + if (Card >= EgNumLinks) + EgNumLinks = Card+1; + return(0); +} +/****************************************************************************** + * + * This is used to run thru the list of egevent records and dump their values + * into a sequence RAM. + * + * The caller of this function MUST hold the link-lock for the board holding + * the ram to be programmed. + * + ******************************************************************************/ +STATIC long EgLoadRamList(EgLinkStruct *pParm, long Ram) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + volatile unsigned short *pAddr; + volatile unsigned short *pData; + ELLNODE *pNode; + struct egeventRecord *pEgevent; + int LastRamPos = 0; + int AltFlag = 0; + double RamSpeed; + + if (Ram == 1) + RamSpeed = pParm->Ram1Speed; + else + RamSpeed = pParm->Ram2Speed; + + /* When in ALT mode, all event records have to be downloaded */ + if (EgGetMode(pParm, 1) == EG_SEQ_MODE_ALTERNATE) + { + pNode = ellFirst(&pParm->EgEvent1); + RamSpeed = pParm->Ram1Speed; /* RAM1 clock used when in ALT mode */ + AltFlag = 1; + } + else + { + if (Ram == 1) + pNode = ellFirst(&pParm->EgEvent1); + else + pNode = ellFirst(&pParm->EgEvent2); + } + if (Ram == 1) + { + pAddr = &pEg->Seq1Addr; + pData = &pEg->Seq1Data; + } + else + { + pAddr = &pEg->Seq2Addr; + pData = &pEg->Seq2Data; + } + /* Get first egevent record from list */ + while (pNode != NULL) + { + pEgevent = ((EgEventNode *)pNode)->pRec; + pEgevent->apos = pEgevent->dpos; /* try to get the desired pos */ + + /* If RAM position already full, fine the next available hole */ + while ((pEgevent->apos < 0x7fff) && (EgGetRamEvent(pParm, Ram, pEgevent->apos) != 0)) + ++pEgevent->apos; + + if (pEgevent->apos < 0x7fff) + { + /* put the record's event code into the RAM */ + EgProgramRamEvent(pParm, Ram, pEgevent->apos, pEgevent->enm); + + /* Remember where the last event went into the RAM */ + if (pEgevent->apos > LastRamPos) + LastRamPos = pEgevent->apos; + } + else /* Overflow the event ram... toss it out. */ + { + pEgevent->apos = 0x7fff; + } + + /* get next record */ + pNode = ellNext(pNode); + + /* In alt mode, we need all from both lists */ + if ((pNode == NULL) && (AltFlag != 0)) + { + pNode = ellFirst(&pParm->EgEvent2); + AltFlag = 0; /* prevent endless loop on EgEvent2 list! */ + } + + /* check for divide by zero problems */ + if (RamSpeed > 0) + { + /* Figure out the actual position */ + switch (pEgevent->unit) + { + case REC_EGEVENT_UNIT_TICKS: + pEgevent->adly = pEgevent->apos; + break; + case REC_EGEVENT_UNIT_FORTNIGHTS: + pEgevent->adly = ((float)pEgevent->apos / (60.0 * 60.0 * 24.0 * 14.0)) / RamSpeed; + break; + case REC_EGEVENT_UNIT_WEEKS: + pEgevent->adly = ((float)pEgevent->apos / (60.0 * 60.0 * 24.0 * 7.0)) / RamSpeed; + break; + case REC_EGEVENT_UNIT_DAYS: + pEgevent->adly = ((float)pEgevent->apos / (60.0 * 60.0 * 24.0)) / RamSpeed; + break; + case REC_EGEVENT_UNIT_HOURS: + pEgevent->adly = ((float)pEgevent->apos / (60.0 * 60.0)) / RamSpeed; + break; + case REC_EGEVENT_UNIT_MINUITES: + pEgevent->adly = ((float)pEgevent->apos / 60.0) / RamSpeed; + break; + case REC_EGEVENT_UNIT_SECONDS: + pEgevent->adly = (float)pEgevent->apos / RamSpeed; + break; + case REC_EGEVENT_UNIT_MILLISECONDS: + pEgevent->adly = (float)pEgevent->apos * (1000.0 / RamSpeed); + break; + case REC_EGEVENT_UNIT_MICROSECONDS: + pEgevent->adly = (float)pEgevent->apos * (1000000.0 / RamSpeed); + break; + case REC_EGEVENT_UNIT_NANOSECONDS: + pEgevent->adly = (float)pEgevent->apos * (1000000000.0 / RamSpeed); + break; + } + } + else + pEgevent->adly = 0; + + if (pEgevent->tpro) + printf("EgLoadRamList(%s) adly %g ramspeed %g\n", pEgevent->name, pEgevent->adly, RamSpeed); + + /* Release database monitors for dpos, apos, and adly here */ + db_post_events(pEgevent, &pEgevent->adly, DBE_VALUE|DBE_LOG); + db_post_events(pEgevent, &pEgevent->dpos, DBE_VALUE|DBE_LOG); + db_post_events(pEgevent, &pEgevent->apos, DBE_VALUE|DBE_LOG); + } + EgProgramRamEvent(pParm, Ram, LastRamPos+1, EG_SEQ_RAM_EVENT_END); + + *pAddr = 0; /* set back to 0 so will be ready to run */ + + return(0); +} +/****************************************************************************** + * + * This task is used to do the actual manipulation of the sequence RAMs on + * the event generator cards. There is only one task on the crate for as many + * EG-cards that are used. + * + * The way this works is we wait on a semaphore that is given when ever the + * data values for the SEQ-rams is altered. (This data is left in the database + * record.) When this task wakes up, it runs thru a linked list (created at + * init time) of all the event-generator records for the RAM that was logically + * updated. While doing so, it sets the event codes in the RAM. + * + * The catch is that a given RAM can not be altered when it is enabled for + * event generation. If we find that the RAM needs updating, but is busy + * This task will poll the RAM until it is no longer busy, then download + * it. + * + * This task views the RAMs as being in one of two modes. Either alt-mode, or + * "the rest". + * + * When NOT in alt-mode, we simply wait for the required RAM to become disabled + * and non-busy and then download it. + * + * In alt-mode, we can download to either of the two RAMs and then tell the + * EG to start using that RAM. The EG can only use one RAM at a time in + * alt-mode, but we still have a problem when one RAM is running, and the other + * has ALREADY been downloaded and enabled... so they are both 'busy.' + * + ******************************************************************************/ +STATIC void EgRamTask(void) +{ + int j; + int Spinning = 0; + + for (;;) + { + if (Spinning != 0) + taskDelay(RAM_LOAD_SPIN_DELAY); + else + semTake(EgRamTaskEventSem, WAIT_FOREVER); + + Spinning = 0; + for (j=0;jout.value.vmeio.card) != 0) + { + recGblRecordError(S_db_badField, (void *)pRec, "devApsEg::EgInitEgRec() bad card number"); + return(S_db_badField); + } + + if (EgLink[pRec->out.value.vmeio.card].pEgRec != NULL) + { + recGblRecordError(S_db_badField, (void *)pRec, "devApsEg::EgInitEgRec() only one record allowed per card"); + return(S_db_badField); + } + pLink = &EgLink[pRec->out.value.vmeio.card]; + + pLink->pEgRec = pRec; + pLink->Ram1Speed = pRec->r1sp; + pLink->Ram2Speed = pRec->r2sp; + +#if 0 /* We decided to init the generator from record instead of v-v */ + /* Init the record to what the card's settings are */ + pRec->enab = EgMasterEnableGet(pLink); + pRec->lena = pRec->enab; + + pRec->lmd1 = pRec->mod1 = EgGetMode(pLink, 1); + pRec->lmd2 = pRec->mod2 = EgGetMode(pLink, 2); + + pRec->fifo = EgCheckFifo(pLink); + pRec->lffo = pRec->fifo; + + pRec->let0 = pRec->et0 = EgGetTrigger(pLink, 0); + pRec->let1 = pRec->et1 = EgGetTrigger(pLink, 1); + pRec->let2 = pRec->et2 = EgGetTrigger(pLink, 2); + pRec->let3 = pRec->et3 = EgGetTrigger(pLink, 3); + pRec->let4 = pRec->et4 = EgGetTrigger(pLink, 4); + pRec->let5 = pRec->et5 = EgGetTrigger(pLink, 5); + pRec->let6 = pRec->et6 = EgGetTrigger(pLink, 6); + pRec->let7 = pRec->et7 = EgGetTrigger(pLink, 7); + + pRec->ete0 = EgGetEnableTrigger(pLink, 0); + pRec->ete1 = EgGetEnableTrigger(pLink, 1); + pRec->ete2 = EgGetEnableTrigger(pLink, 2); + pRec->ete3 = EgGetEnableTrigger(pLink, 3); + pRec->ete4 = EgGetEnableTrigger(pLink, 4); + pRec->ete5 = EgGetEnableTrigger(pLink, 5); + pRec->ete6 = EgGetEnableTrigger(pLink, 6); + pRec->ete7 = EgGetEnableTrigger(pLink, 7); + + pRec->trg1 = 0; + pRec->trg2 = 0; + pRec->clr1 = 0; + pRec->clr2 = 0; + pRec->vme = 0; +#else + + /* Keep the thing off until we are dun setting it up */ + EgMasterDisable(pLink); + + pRec->lffo = pRec->fifo; + if (pRec->fifo) + EgEnableFifo(pLink); + else + EgDisableFifo(pLink); + + /* Disable these things so I can adjust them */ + EgEnableTrigger(pLink, 0, 0); + EgEnableTrigger(pLink, 1, 0); + EgEnableTrigger(pLink, 2, 0); + EgEnableTrigger(pLink, 3, 0); + EgEnableTrigger(pLink, 4, 0); + EgEnableTrigger(pLink, 5, 0); + EgEnableTrigger(pLink, 6, 0); + EgEnableTrigger(pLink, 7, 0); + + /* Set the trigger event codes */ + pRec->let0 = pRec->et0; + EgSetTrigger(pLink, 0, pRec->et0); + pRec->let1 = pRec->et1; + EgSetTrigger(pLink, 1, pRec->et1); + pRec->let2 = pRec->et2; + EgSetTrigger(pLink, 2, pRec->et2); + pRec->let3 = pRec->et3; + EgSetTrigger(pLink, 3, pRec->et3); + pRec->let4 = pRec->et4; + EgSetTrigger(pLink, 4, pRec->et4); + pRec->let5 = pRec->et5; + EgSetTrigger(pLink, 5, pRec->et5); + pRec->let6 = pRec->et6; + EgSetTrigger(pLink, 6, pRec->et6); + pRec->let7 = pRec->et7; + EgSetTrigger(pLink, 7, pRec->et7); + + /* Set enables for the triggers not that they have valid values */ + EgEnableTrigger(pLink, 0, pRec->ete0); + EgEnableTrigger(pLink, 1, pRec->ete1); + EgEnableTrigger(pLink, 2, pRec->ete2); + EgEnableTrigger(pLink, 3, pRec->ete3); + EgEnableTrigger(pLink, 4, pRec->ete4); + EgEnableTrigger(pLink, 5, pRec->ete5); + EgEnableTrigger(pLink, 6, pRec->ete6); + EgEnableTrigger(pLink, 7, pRec->ete7); + + /* These are one-shots... init them for future detection */ + pRec->trg1 = 0; + pRec->trg2 = 0; + pRec->clr1 = 0; + pRec->clr2 = 0; + pRec->vme = 0; + + /* BUG -- have to deal with ALT mode... if either is ALT, both must be ALT */ + pRec->lmd1 = pRec->mod1; + EgSetSeqMode(pLink, 1, pRec->mod1); + pRec->lmd2 = pRec->mod2; + EgSetSeqMode(pLink, 2, pRec->mod2); + + if (pRec->enab) + EgMasterEnable(pLink); + else + EgMasterDisable(pLink); + pRec->lena = pRec->enab; + +#endif + + if (EgCheckTaxi(pLink) != 0) + pRec->taxi = 1; + else + pRec->taxi = 0; + return(0); +} + +/****************************************************************************** + * + * Process an EG record. + * + ******************************************************************************/ +STATIC long EgProcEgRec(struct egRecord *pRec) +{ + EgLinkStruct *pLink = &EgLink[pRec->out.value.vmeio.card]; + + if (pRec->tpro > 10) + printf("devApsEg::proc(%s) link%d at 0x%08.8X\n", pRec->name, + pRec->out.value.vmeio.card, pLink); + + /* Check if the card is present */ + if (EgCheckCard(pRec->out.value.vmeio.card) != 0) + return(0); + + semTake (pLink->EgLock, WAIT_FOREVER); + +#if 0 /* This should not be in here */ + if (pRec->udf != 0) + { /* Record has garbage values in it... Read from card */ + if (pRec->tpro > 10) + printf("UDF is set, reading values from card\n"); + + pRec->enab = EgMasterEnableGet(pLink); + pRec->lena = pRec->enab; + + pRec->lmd1 = pRec->mod1 = EgGetMode(pLink, 1); + pRec->lmd2 = pRec->mod2 = EgGetMode(pLink, 2); + + pRec->fifo = EgCheckFifo(pLink); + pRec->lffo = pRec->fifo; + + pRec->let0 = pRec->et0 = EgGetTrigger(pLink, 0); + pRec->let1 = pRec->et1 = EgGetTrigger(pLink, 1); + pRec->let2 = pRec->et2 = EgGetTrigger(pLink, 2); + pRec->let3 = pRec->et3 = EgGetTrigger(pLink, 3); + pRec->let4 = pRec->et4 = EgGetTrigger(pLink, 4); + pRec->let5 = pRec->et5 = EgGetTrigger(pLink, 5); + pRec->let6 = pRec->et6 = EgGetTrigger(pLink, 6); + pRec->let7 = pRec->et7 = EgGetTrigger(pLink, 7); + + pRec->trg1 = 0; + pRec->trg2 = 0; + pRec->clr1 = 0; + pRec->clr2 = 0; + pRec->vme = 0; + + if (EgCheckTaxi(pLink) != 0) + pRec->taxi = 1; + else + pRec->taxi = 0; + + } + else +#endif + { + /* Master enable */ + /*if (pRec->enab != pRec->lena)*/ + if (pRec->enab != EgMasterEnableGet(pLink)) + { + if (pRec->enab == 0) + { + if (pRec->tpro > 10) + printf(", Master Disable"); + EgMasterDisable(pLink); + } + else + { + if (pRec->tpro > 10) + printf(", Master Enable"); + EgMasterEnable(pLink); + } + pRec->lena = pRec->enab; + } + + /* Check for a mode change. */ + if (pRec->mod1 != pRec->lmd1) + { + if (pRec->tpro > 10) + printf(", Mode1=%d", pRec->mod1); + if (pRec->mod1 == EG_SEQ_MODE_ALTERNATE) + { + pRec->mod1 = EG_SEQ_MODE_ALTERNATE; + pRec->lmd1 = EG_SEQ_MODE_ALTERNATE; + pRec->mod2 = EG_SEQ_MODE_ALTERNATE; + pRec->lmd2 = EG_SEQ_MODE_ALTERNATE; + + pLink->Ram1Dirty = 1; + pLink->Ram2Dirty = 1; + } + else if (pRec->lmd1 == EG_SEQ_MODE_ALTERNATE) + { + pRec->mod2 = EG_SEQ_MODE_OFF; + pRec->lmd2 = EG_SEQ_MODE_OFF; + EgSetSeqMode(pLink, 2, EG_SEQ_MODE_OFF); + pLink->Ram1Dirty = 1; + pLink->Ram2Dirty = 1; + } + EgSetSeqMode(pLink, 1, pRec->mod1); + pRec->lmd1 = pRec->mod1; + } + if (pRec->mod2 != pRec->lmd2) + { + if (pRec->tpro > 10) + printf(", Mode2=%d", pRec->mod2); + if (pRec->mod2 == EG_SEQ_MODE_ALTERNATE) + { + pRec->mod1 = EG_SEQ_MODE_ALTERNATE; + pRec->lmd1 = EG_SEQ_MODE_ALTERNATE; + pRec->mod2 = EG_SEQ_MODE_ALTERNATE; + pRec->lmd2 = EG_SEQ_MODE_ALTERNATE; + + pLink->Ram1Dirty = 1; + pLink->Ram2Dirty = 1; + } + else if (pRec->lmd2 == EG_SEQ_MODE_ALTERNATE) + { + pRec->mod1 = EG_SEQ_MODE_OFF; + pRec->lmd2 = EG_SEQ_MODE_OFF; + EgSetSeqMode(pLink, 1, EG_SEQ_MODE_OFF); + pLink->Ram1Dirty = 1; + pLink->Ram2Dirty = 1; + } + EgSetSeqMode(pLink, 2, pRec->mod2); + pRec->lmd2 = pRec->mod2; + } + /* Deal with FIFO enable flag */ + if (pRec->fifo != pRec->lffo) + { + if (pRec->fifo == 0) + { + if (pRec->tpro > 10) + printf(", FIFO Disable"); + EgDisableFifo(pLink); + } + else + { + if (pRec->tpro > 10) + printf(", FIFO Enable"); + EgEnableFifo(pLink); + } + pRec->lffo = pRec->fifo; + } + + /* We use the manual triggers as one-shots. They get reset to zero */ + if (pRec->trg1 != 0) + { + if (pRec->tpro > 10) + printf(", Trigger-1"); + EgSeqTrigger(pLink, 1); + pRec->trg1 = 0; + } + if (pRec->trg2 != 0) + { + if (pRec->tpro > 10) + printf(", Trigger-2"); + EgSeqTrigger(pLink, 2); + pRec->trg2 = 0; + } + + /* We use the clears as as one-shots. They get reset to zero */ + if (pRec->clr1 !=0) + { + if (pRec->tpro > 10) + printf(", clear-1"); + EgClearSeq(pLink, 1); + pRec->clr1 = 0; + } + if (pRec->clr2 !=0) + { + if (pRec->tpro > 10) + printf(", clear-2"); + EgClearSeq(pLink, 2); + pRec->clr2 = 0; + } + + /* We use the VME event trigger as a one-shot. It is reset to zero */ + if (pRec->vme != 0) + { + if (pRec->tpro > 10) + printf(", VME-%d", pRec->vme); + EgGenerateVmeEvent(pLink, pRec->vme); + pRec->vme = 0; + } + + /* + * If any triggers are enabled... set their values. + * Otherwise, disable the associated trigger map register. + * + * NOTE: The EG board only allows changes to the trigger codes + * when the board is disabled. Users of these triggers must disable + * them, change the trigger event code and then re-enable them to + * get them to work. + */ + if (pRec->ete0) + { + if (pRec->et0 != EgGetTrigger(pLink, 0)) + { + EgEnableTrigger(pLink, 0, 0); + EgSetTrigger(pLink, 0, pRec->et0); + pRec->let0 = pRec->et0; + } + EgEnableTrigger(pLink, 0, 1); + } + else + EgEnableTrigger(pLink, 0, 0); + + if (pRec->ete1) + { + if (pRec->et1 != EgGetTrigger(pLink, 1)) + { + EgEnableTrigger(pLink, 1, 0); + EgSetTrigger(pLink, 1, pRec->et1); + pRec->let1 = pRec->et1; + } + EgEnableTrigger(pLink, 1, 1); + } + else + EgEnableTrigger(pLink, 1, 0); + + if (pRec->ete2) + { + if (pRec->et2 != EgGetTrigger(pLink, 2)) + { + EgEnableTrigger(pLink, 2, 0); + EgSetTrigger(pLink, 2, pRec->et2); + pRec->let2 = pRec->et2; + } + EgEnableTrigger(pLink, 2, 1); + } + else + EgEnableTrigger(pLink, 2, 0); + + if (pRec->ete3) + { + if (pRec->et3 != EgGetTrigger(pLink, 3)) + { + EgEnableTrigger(pLink, 3, 0); + EgSetTrigger(pLink, 3, pRec->et3); + pRec->let3 = pRec->et3; + } + EgEnableTrigger(pLink, 3, 1); + } + else + EgEnableTrigger(pLink, 3, 0); + + if (pRec->ete4) + { + if (pRec->et4 != EgGetTrigger(pLink, 4)) + { + EgEnableTrigger(pLink, 4, 0); + EgSetTrigger(pLink, 4, pRec->et4); + pRec->let4 = pRec->et4; + } + EgEnableTrigger(pLink, 4, 1); + } + else + EgEnableTrigger(pLink, 4, 0); + + if (pRec->ete5) + { + if (pRec->et5 != EgGetTrigger(pLink, 5)) + { + EgEnableTrigger(pLink, 5, 0); + EgSetTrigger(pLink, 5, pRec->et5); + pRec->let5 = pRec->et5; + } + EgEnableTrigger(pLink, 5, 1); + } + else + EgEnableTrigger(pLink, 5, 0); + + if (pRec->ete6) + { + if (pRec->et6 != EgGetTrigger(pLink, 6)) + { + EgEnableTrigger(pLink, 6, 0); + EgSetTrigger(pLink, 6, pRec->et6); + pRec->let6 = pRec->et6; + } + EgEnableTrigger(pLink, 6, 1); + } + else + EgEnableTrigger(pLink, 6, 0); + + if (pRec->ete7) + { + if (pRec->et7 != EgGetTrigger(pLink, 7)) + { + EgEnableTrigger(pLink, 7, 0); + EgSetTrigger(pLink, 7, pRec->et7); + pRec->let7 = pRec->et7; + } + EgEnableTrigger(pLink, 7, 1); + } + else + EgEnableTrigger(pLink, 7, 0); + + /* TAXI stuff? */ + if (EgCheckTaxi(pLink) != 0) + pRec->taxi = 1; + + if (pRec->tpro > 10) + printf("\n"); + } + semGive (pLink->EgLock); + EgScheduleRamProgram(pRec->out.value.vmeio.card); + pRec->udf = 0; + return(0); +} +struct { + long number; + void *p1; + void *p2; + void *p3; + void *p4; + void *p5; +} devEg={ 5, NULL, EgInitDev, EgInitEgRec, NULL, EgProcEgRec}; + +/****************************************************************************** + * + * Support for initialization of egevent records. + * + ******************************************************************************/ +STATIC long EgInitEgEventRec(struct egeventRecord *pRec) +{ + if (EgCheckCard(pRec->out.value.vmeio.card) != 0) + { + recGblRecordError(S_db_badField, (void *)pRec, "devApsEg::EgInitEgEventRec() bad card number"); + return(S_db_badField); + } + + pRec->self = pRec; + pRec->lram = pRec->ram; + pRec->levt = 0; /* force program on first process */ + + /* Put the event record in the proper list */ + semTake (EgLink[pRec->out.value.vmeio.card].EgLock, WAIT_FOREVER); + if (pRec->ram == REC_EGEVENT_RAM_2) + { + ellAdd(&(EgLink[pRec->out.value.vmeio.card].EgEvent2), &(pRec->eln)); + EgLink[pRec->out.value.vmeio.card].Ram2Dirty = 1; + } + else /* RAM_1 */ + { + ellAdd(&(EgLink[pRec->out.value.vmeio.card].EgEvent1), &(pRec->eln)); + EgLink[pRec->out.value.vmeio.card].Ram1Dirty = 1; + } + semGive(EgLink[pRec->out.value.vmeio.card].EgLock); + return(0); +} +/****************************************************************************** + * + * Process an EGEVENT record. + * + ******************************************************************************/ +STATIC long EgProcEgEventRec(struct egeventRecord *pRec) +{ + ApsEgStruct *pLink = EgLink[pRec->out.value.vmeio.card].pEg; + double RamSpeed; + + if (pRec->tpro > 10) + printf("devApsEg::EgProcEgEventRec(%s) link%d at 0x%08.8X\n", pRec->name, + pRec->out.value.vmeio.card, pLink); + + /* Check if the card is present */ + if (EgCheckCard(pRec->out.value.vmeio.card) != 0) + return(0); + + /* Check for ram# change */ + if (pRec->ram != pRec->lram) + { + EgLink[pRec->out.value.vmeio.card].Ram1Dirty = 1; + EgLink[pRec->out.value.vmeio.card].Ram2Dirty = 1; + + if (pRec->tpro > 10) + printf("devApsEg::EgProcEgEventRec(%s) ram-%d\n", pRec->name, pRec->ram); + + semTake (EgLink[pRec->out.value.vmeio.card].EgLock, WAIT_FOREVER); + /* Move to proper linked list */ + if (pRec->ram == REC_EGEVENT_RAM_2) + { + ellDelete(&(EgLink[pRec->out.value.vmeio.card].EgEvent1), &(pRec->eln)); + ellAdd(&(EgLink[pRec->out.value.vmeio.card].EgEvent2), &(pRec->eln)); + } + else /* RAM_1 */ + { + ellDelete(&(EgLink[pRec->out.value.vmeio.card].EgEvent2), &(pRec->eln)); + ellAdd(&(EgLink[pRec->out.value.vmeio.card].EgEvent1), &(pRec->eln)); + } + semGive(EgLink[pRec->out.value.vmeio.card].EgLock); + pRec->lram = pRec->ram; + } + + if (pRec->ram == REC_EGEVENT_RAM_2) + RamSpeed = EgLink[pRec->out.value.vmeio.card].Ram2Speed; + else + RamSpeed = EgLink[pRec->out.value.vmeio.card].Ram1Speed; + + if (pRec->enm != pRec->levt) + { + if (pRec->ram == REC_EGEVENT_RAM_2) + EgLink[pRec->out.value.vmeio.card].Ram2Dirty = 1; + else + EgLink[pRec->out.value.vmeio.card].Ram1Dirty = 1; + pRec->levt = pRec->enm; + } + /* Check for time/position change */ + if (pRec->dely != pRec->ldly) + { + /* Scale delay to actual position */ + switch (pRec->unit) + { + case REC_EGEVENT_UNIT_TICKS: + pRec->dpos = pRec->dely; + break; + case REC_EGEVENT_UNIT_FORTNIGHTS: + pRec->dpos = ((float)pRec->dely * 60.0 * 60.0 * 24.0 * 14.0) * RamSpeed; + break; + case REC_EGEVENT_UNIT_WEEKS: + pRec->dpos = ((float)pRec->dely * 60.0 * 60.0 * 24.0 * 7.0) * RamSpeed; + break; + case REC_EGEVENT_UNIT_DAYS: + pRec->dpos = ((float)pRec->dely * 60.0 * 60.0 * 24.0) * RamSpeed; + break; + case REC_EGEVENT_UNIT_HOURS: + pRec->dpos = ((float)pRec->dely * 60.0 *60.0) * RamSpeed; + break; + case REC_EGEVENT_UNIT_MINUITES: + pRec->dpos = ((float)pRec->dely * 60.0) * RamSpeed; + break; + case REC_EGEVENT_UNIT_SECONDS: + pRec->dpos = pRec->dely * RamSpeed; + break; + case REC_EGEVENT_UNIT_MILLISECONDS: + pRec->dpos = ((float)pRec->dely/1000.0) * RamSpeed; + break; + case REC_EGEVENT_UNIT_MICROSECONDS: + pRec->dpos = ((float)pRec->dely/1000000.0) * RamSpeed; + break; + case REC_EGEVENT_UNIT_NANOSECONDS: + pRec->dpos = ((float)pRec->dely/1000000000.0) * RamSpeed; + break; + } + if (pRec->tpro) + printf("EgProcEgEventRec(%s) dpos=%d\n", pRec->name, pRec->dpos); + + pRec->ldly = pRec->dely; + if (pRec->ram == REC_EGEVENT_RAM_2) + EgLink[pRec->out.value.vmeio.card].Ram2Dirty = 1; + else + EgLink[pRec->out.value.vmeio.card].Ram1Dirty = 1; + } + EgScheduleRamProgram(pRec->out.value.vmeio.card); + return(0); +} + +struct { + long number; + void *p1; + void *p2; + void *p3; + void *p4; + void *p5; +} devEgEvent={ 5, NULL, EgInitDev, EgInitEgEventRec, NULL, EgProcEgEventRec}; + +/****************************************************************************** + * + * Driver support functions. + * + * These are service routines unes to support the record init and processing + * functions above. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Return the event code from the requested RAM and physical position. + * + ******************************************************************************/ +STATIC long EgGetRamEvent(EgLinkStruct *pParm, long Ram, long Addr) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + if (EgSeqEnableCheck(pParm, Ram)) /* Can't alter a running RAM */ + return(-2); + + pEg->Control = (pEg->Control&CTL_OR_MASK)&~0x0600; /* shut off auto-inc */ + if (Ram == 1) + { + pEg->Seq1Addr = Addr; + return(pEg->Seq1Data&0xff); + } + else + { + pEg->Seq2Addr = Addr; + return(pEg->Seq2Data&0xff); + } + return(-1); +} +/****************************************************************************** + * + * Program a single evnet into a single RAM position. + * + ******************************************************************************/ +STATIC long EgProgramRamEvent(EgLinkStruct *pParm, long Ram, long Addr, long Event) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + +#ifdef EG_DEBUG + printf("EgProgramRamEvent() %d, %d, %d\n", Ram, Addr, Event); +#endif + if (EgSeqEnableCheck(pParm, Ram)) /* Can't alter a running RAM */ + return(-2); + + pEg->Control = (pEg->Control&CTL_OR_MASK)&~0x0600; /* shut off auto-inc */ + if (Ram == 1) + { + pEg->Seq1Addr = Addr; + if ((pEg->Seq1Data&0xff) != 0) + { +#ifdef EG_DEBUG + printf("Seq1 data at 0x%04.4X already %02.2X\n", Addr, pEg->Seq1Data&0xff); +#endif + return(-1); + } + pEg->Seq1Data = Event; + } + else + { + pEg->Seq2Addr = Addr; + if ((pEg->Seq2Data&0xff) != 0) + { +#ifdef EG_DEBUG + printf("Seq2 data at 0x%04.4X already %02.2X\n", Addr, pEg->Seq2Data&0xff); +#endif + return(-1); + } + pEg->Seq2Data = Event; + } + return(0); +} + +/****************************************************************************** + * + * Return a zero if no TAXI violation status set, one otherwise. + * + ******************************************************************************/ +STATIC long EgCheckTaxi(EgLinkStruct *pParm) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + return(pEg->Control & 0x0001); +} + +/****************************************************************************** + * + * Shut down the in-bound FIFO. + * + ******************************************************************************/ +STATIC long EgDisableFifo(EgLinkStruct *pParm) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x1000; /* Disable FIFO */ + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x2001; /* Reset FIFO (plus any taxi violations) */ + + return(0); +} + +/****************************************************************************** + * + * Turn on the in-bound FIFO. + * + ******************************************************************************/ +STATIC long EgEnableFifo(EgLinkStruct *pParm) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + if (pEg->Control & 0x1000) /* If enabled already, forget it */ + { + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x2001; /* Reset FIFO & taxi */ + pEg->Control = (pEg->Control&CTL_OR_MASK)&~0x1000; /* Enable the FIFO */ + } + return(0); +} + +/****************************************************************************** + * + * Return a 1 if the FIFO is enabled and a zero otherwise. + * + ******************************************************************************/ +STATIC long EgCheckFifo(EgLinkStruct *pParm) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + if (pEg->Control & 0x1000) + return(0); + return(1); +} + +/****************************************************************************** + * + * Turn on the master enable. + * + ******************************************************************************/ +STATIC long EgMasterEnable(EgLinkStruct *pParm) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + pEg->Control = (pEg->Control&CTL_OR_MASK)&~0x8000; /* Clear the disable bit */ + return(0); +} + +/****************************************************************************** + * + * Turn off the master enable. + * + ******************************************************************************/ +STATIC long EgMasterDisable(EgLinkStruct *pParm) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x8000; /* Set the disable bit */ + return(0); +} + +/****************************************************************************** + * + * Return a one of the master enable is on, and a zero otherwise. + * + ******************************************************************************/ +STATIC long EgMasterEnableGet(EgLinkStruct *pParm) +{ + if (pParm->pEg->Control&0x8000) + return(0); + + return(1); +} + +/****************************************************************************** + * + * Clear the requested sequence RAM. + * BUG -- should have an enableCheck + * + ******************************************************************************/ +STATIC long EgClearSeq(EgLinkStruct *pParm, int channel) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + if (channel == 1) + { + while(pEg->Control & 0x0014) + taskDelay(1); /* Wait for running seq to finish */ + + pEg->EventMask &= ~0x0004; /* Turn off seq 1 */ + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0004; /* Reset seq RAM address */ + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0010; /* Assert the NULL fill command */ + + /* make sure we do not set both reset event and null fill at same time */ + + while(pEg->Control & 0x0010) + taskDelay(1); /* Wait for NULL fill to complete */ + } + else if(channel == 2) + { + while(pEg->Control & 0x000a) + taskDelay(1); + + pEg->EventMask &= ~0x0002; + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0002; + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0008; + + while(pEg->Control & 0x0008) + taskDelay(1); + } + return(0); +} + +/****************************************************************************** + * + * Set the trigger event code for a given channel number. + * + ******************************************************************************/ +STATIC long EgSetTrigger(EgLinkStruct *pParm, unsigned int Channel, unsigned short Event) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + volatile unsigned short *pShort; + + if(Channel > 7) + return(-1); + + pShort = &(pEg->Event0Map); + pShort[Channel] = Event; + + return(0); +} + +/****************************************************************************** + * + * Return the event code for the requested trigger channel. + * + ******************************************************************************/ +STATIC long EgGetTrigger(EgLinkStruct *pParm, unsigned int Channel) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + if(Channel > 7) + return(0); + return(((unsigned short *)(&(pEg->Event0Map)))[Channel]); +} + +/****************************************************************************** + * + * Enable or disable event triggering for a given Channel. + * + ******************************************************************************/ +STATIC long EgEnableTrigger(EgLinkStruct *pParm, unsigned int Channel, int state) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + unsigned short j; + + if (Channel > 7) + return(-1); + + j = 0x08; + j <<= Channel; + + if (state) + pEg->EventMask |= j; + else + pEg->EventMask &= ~j; + + return(0); +} +STATIC long EgGetEnableTrigger(EgLinkStruct *pParm, unsigned int Channel) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + unsigned short j; + + if (Channel > 7) + return(0); + + j = 0x08; + j <<= Channel; + + return(pEg->EventMask & j ?1:0); +} +/****************************************************************************** + * + * Return a one if the request RAM is enabled or a zero otherwise. + * We use this function to make sure the RAM is disabled before we access it. + * + ******************************************************************************/ +STATIC int EgSeqEnableCheck(EgLinkStruct *pParm, unsigned int Seq) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + if (Seq == 1) + return(pEg->EventMask & 0x0004); + return(pEg->EventMask & 0x0002); +} + +/****************************************************************************** + * + * This routine does a manual trigger of the requested SEQ RAM. + * + ******************************************************************************/ +STATIC long EgSeqTrigger(EgLinkStruct *pParm, unsigned int Seq) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + if (Seq == 1) + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0100; + else if (Seq == 2) + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0080; + else + return(-1); + + return(0); +} +/****************************************************************************** + * + * Select mode of Sequence RAM operation. + * + * OFF: + * Stop the generation of all events from sequence RAMs. + * NORMAL: + * Set to cycle on every trigger. + * NORMAL_RECYCLE: + * Set to continuous run on first trigger. + * SINGLE: + * Set to disable self on an END event. + * ALTERNATE: + * Use one ram at a time, but use both to allow seamless modifications + * + ******************************************************************************/ +STATIC long EgSetSeqMode(EgLinkStruct *pParm, unsigned int Seq, int Mode) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + /* Stop and disable the sequence RAMs */ + if (Mode == EG_SEQ_MODE_ALTERNATE) + { + pEg->EventMask &= ~0x3006; /* Disable *BOTH* RAMs */ + pEg->Control = (pEg->Control&CTL_OR_MASK)&~0x0066; + while(pEg->Control & 0x0006) + taskDelay(1); /* Wait until finish running */ + } + else if (Seq == 1) + { + pEg->EventMask &= ~0x2004; /* Disable SEQ 1 */ + pEg->Control = (pEg->Control&CTL_OR_MASK)&~0x0044; + while(pEg->Control & 0x0004) + taskDelay(1); /* Wait until finish running */ + pEg->EventMask &= ~0x0800; /* Kill ALT mode */ + } + else if (Seq == 2) + { + pEg->EventMask &= ~0x1002; /* Disable SEQ 2 */ + pEg->Control = (pEg->Control&CTL_OR_MASK)&~0x0022; + while(pEg->Control & 0x0002) + taskDelay(1); /* Wait until finish running */ + pEg->EventMask &= ~0x0800; /* Kill ALT mode */ + } + else + return(-1); + + switch (Mode) + { + case EG_SEQ_MODE_OFF: + break; + + case EG_SEQ_MODE_NORMAL: + if (Seq == 1) + pEg->EventMask |= 0x0004; /* Enable Seq RAM 1 */ + else + pEg->EventMask |= 0x0002; /* Enable Seq RAM 2 */ + break; + + case EG_SEQ_MODE_NORMAL_RECYCLE: + if (Seq == 1) + { + pEg->EventMask |= 0x0004; /* Enable Seq RAM 1 */ + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0040; /* Set Seq 1 recycle */ + } + else + { + pEg->EventMask |= 0x0002; + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0020; + } + break; + + case EG_SEQ_MODE_SINGLE: + if (Seq == 1) + pEg->EventMask |= 0x2004; /* Enable Seq RAM 1 in single mode */ + else + pEg->EventMask |= 0x1002; + break; + + case EG_SEQ_MODE_ALTERNATE: /* The ram downloader does all the work */ + pEg->EventMask |= 0x0800; /* turn on the ALT mode bit */ + break; + + default: + return(-1); + } + return(-1); +} + +/****************************************************************************** + * + * Check to see if a sequence ram is currently running + * + ******************************************************************************/ +STATIC long EgGetBusyStatus(EgLinkStruct *pParm, int Ram) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + if (Ram == 1) + { + if (pEg->Control & 0x0004) + return(1); + return(0); + } + if (pEg->Control & 0x0002) + return(1); + return(0); +} +/****************************************************************************** + * + * Ram is assumed to be in ALT mode, check to see if the requested RAM is + * available for downloading (Not enabled and idle.) + * + * Returns zero if RAM is available or nonzero otherwise. + * + ******************************************************************************/ +STATIC long EgGetAltStatus(EgLinkStruct *pParm, int Ram) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + if (EgGetBusyStatus(pParm, Ram) != 0) + return(1); + + if (Ram == 1) + { + if (pEg->EventMask & 0x0004) + return(1); + } + else + { + if (pEg->EventMask & 0x0002) + return(1); + } + return(0); +} +/****************************************************************************** + * + * Return the operating mode of the requested sequence RAM. + * + ******************************************************************************/ +STATIC long EgGetMode(EgLinkStruct *pParm, int Ram) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + unsigned short Mask; + unsigned short Control; + + Mask = pEg->EventMask & 0x3806; + Control = pEg->Control & 0x0060; + + if (Mask & 0x0800) + return(EG_SEQ_MODE_ALTERNATE); + + if (Ram == 1) + { + Mask &= 0x2004; + Control &= 0x0040; + + if ((Mask == 0) && (Control == 0)) + return(EG_SEQ_MODE_OFF); + if ((Mask == 0x0004) && (Control == 0)) + return(EG_SEQ_MODE_NORMAL); + if ((Mask == 0x0004) && (Control == 0x0040)) + return(EG_SEQ_MODE_NORMAL_RECYCLE); + if (Mask & 0x2000) + return(EG_SEQ_MODE_SINGLE); + } + else + { + Mask &= 0x1002; + Control &= 0x0020; + + if ((Mask == 0) && (Control == 0)) + return(EG_SEQ_MODE_OFF); + if ((Mask == 0x0002) && (Control == 0)) + return(EG_SEQ_MODE_NORMAL); + if ((Mask == 0x0002) && (Control == 0x0020)) + return(EG_SEQ_MODE_NORMAL_RECYCLE); + if (Mask & 0x1000) + return(EG_SEQ_MODE_SINGLE); + } + printf("EgGetMode() seqence RAM in invalid state %04.4X %04.4X\n", pEg->Control, pEg->EventMask); + return(-1); +} + +STATIC long EgEnableAltRam(EgLinkStruct *pParm, int Ram) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + unsigned short Mask = pEg->EventMask; + if (Ram == 1) + pEg->EventMask = (Mask & ~0x0002)|0x0004; + else + pEg->EventMask = (Mask & ~0x0004)|0x0002; + return(0); +} +/****************************************************************************** + * + * Enable or disable the generation of VME events. + * + ******************************************************************************/ +STATIC long EgEnableVme(EgLinkStruct *pParm, int state) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + if (state) + pEg->EventMask |= 0x0001; + else + pEg->EventMask &= ~0x0001; + + return(0); +} + +/****************************************************************************** + * + * Send the given event code out now. + * + ******************************************************************************/ +STATIC long EgGenerateVmeEvent(EgLinkStruct *pParm, int Event) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + pEg->VmeEvent = Event; + return(0); +} +/****************************************************************************** + * + * Disable and clear everything on the Event Generator + * + ******************************************************************************/ +STATIC long EgResetAll(EgLinkStruct *pParm) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + pEg->Control = 0x8000; /* Disable all local event generation */ + pEg->EventMask = 0; /* Disable all local event generation */ + + EgDisableFifo(pParm); + + EgClearSeq(pParm, 1); + EgClearSeq(pParm, 2); + + EgSetTrigger(pParm, 0, 0); /* Clear all trigger event numbers */ + EgSetTrigger(pParm, 1, 0); + EgSetTrigger(pParm, 2, 0); + EgSetTrigger(pParm, 3, 0); + EgSetTrigger(pParm, 4, 0); + EgSetTrigger(pParm, 5, 0); + EgSetTrigger(pParm, 6, 0); + EgSetTrigger(pParm, 7, 0); + + EgEnableVme(pParm, 1); /* There is no reason to disable VME events */ + + return(0); +} + +/****************************************************************************** + * + * Read the requested sequence RAM into the buffer passed in. + * + ******************************************************************************/ +STATIC int EgReadSeqRam(EgLinkStruct *pParm, int channel, unsigned char *pBuf) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + volatile unsigned short *pSeqData; + int j; + + if (EgSeqEnableCheck(pParm, channel)) + { + pEg->Control = (pEg->Control&CTL_OR_MASK)&~0x0600; + return(-1); + } + if (channel == 1) + { + pSeqData = &pEg->Seq1Data; + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0404; /* Auto inc the address */ + pEg->Seq1Addr = 0; + } + else if (channel == 2) + { + pSeqData = &pEg->Seq2Data; + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0202; /* Auto inc the address */ + pEg->Seq2Addr = 0; + } + else + return(-1); + + for(j=0;jControl = (pEg->Control&CTL_OR_MASK)&~0x0600; /* kill the auto-inc */ + + if (channel == 1) + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0004; + else + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0002; + + return(0); +} + +/****************************************************************************** + * + * Program the requested sequence RAM from the buffer passed in. + * + ******************************************************************************/ +STATIC int EgWriteSeqRam(EgLinkStruct *pParm, int channel, unsigned char *pBuf) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + volatile unsigned short *pSeqData; + int j; + + if (EgSeqEnableCheck(pParm, channel)) + { + pEg->Control = (pEg->Control&CTL_OR_MASK)&~0x0600; /* kill the auto-inc */ + return(-1); + } + + if (channel == 1) + { + pSeqData = &pEg->Seq1Data; + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0404; /* Auto inc the address */ + pEg->Seq1Addr = 0; + } + else if (channel == 2) + { + pSeqData = &pEg->Seq2Data; + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0202; /* Auto inc the address */ + pEg->Seq2Addr = 0; + } + else + return(-1); + +#ifdef EG_DEBUG + printf("ready to download ram\n"); +#endif + taskDelay(20); + for(j=0;jControl = (pEg->Control&CTL_OR_MASK)&~0x0600; /* kill the auto-inc */ + + if (channel == 1) /* reset the config'd channel */ + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0004; + else + pEg->Control = (pEg->Control&CTL_OR_MASK)|0x0002; + +#ifdef EG_DEBUG + printf("sequence ram downloaded\n"); +#endif + taskDelay(20); + return(0); +} + +/******************************************************************************/ +/******************************************************************************/ +/****************************************************************************** + * + * The following section is a console-run test program for the event generator + * card. It is crude, but it works. + * + ******************************************************************************/ +#ifdef EG_MONITOR + +STATIC unsigned char TestRamBuf[EG_SEQ_RAM_SIZE]; + +STATIC int EgDumpRegs(EgLinkStruct *pParm) +{ + volatile ApsEgStruct *pEg = pParm->pEg; + + printf("Control = %04.4X, Event Mask = %04.4X\n", pEg->Control, pEg->EventMask); + return(0); +} +STATIC int SetupSeqRam(EgLinkStruct *pParm, int channel) +{ + int j; + + if (EgSeqEnableCheck(pParm, channel)) + { + printf("Sequence ram %d is enabled, can not reconfigure\n", channel); + return(-1); + } + + for(j=0; j<=20; j++) + TestRamBuf[j] = 100-j; + + TestRamBuf[j] = EG_SEQ_RAM_EVENT_END; + + j++; + + for(;jpEg; + char buf[100]; + + while(1) + { + SeqConfigMenu(); + if (fgets(buf, sizeof(buf), stdin) == NULL) + return; + + switch (buf[0]) + { + case 'c': + if (EgSeqEnableCheck(pParm, channel)) + { + printf("can not config, ram is enabled\n"); + break; + } + EgClearSeq(pParm, channel); + break; + + case 'p': + PrintSeq(pParm, channel); + break; + case 's': + SetupSeqRam(pParm, channel); + break; + case 'm': + switch (buf[1]) + { + case '0': + EgSetSeqMode(pParm, channel, EG_SEQ_MODE_OFF); + break; + case '1': + if (EgSeqEnableCheck(pParm, channel)) + { + printf("can not config, ram is enabled\n"); + break; + } + EgSetSeqMode(pParm, channel, 1); + break; + case '2': + if (EgSeqEnableCheck(pParm, channel)) + { + printf("can not config, ram is enabled\n"); + break; + } + EgSetSeqMode(pParm, channel, 2); + break; + case '3': + if (EgSeqEnableCheck(pParm, channel)) + { + printf("can not config, ram is enabled\n"); + break; + } + EgSetSeqMode(pParm, channel, 3); + break; + case '4': + if (EgSeqEnableCheck(pParm, channel)) + { + printf("can not config, ram is enabled\n"); + break; + } + EgSetSeqMode(pParm, channel, 4); + break; + } + break; + case 't': + EgSeqTrigger(pParm, channel); + break; + case 'z': + EgDumpRegs(pParm); + break; + case 'q': return; + } + } +} + +STATIC void menu(void) +{ + printf("r - Reset everything on the event generator\n"); + printf("m - turn on the master enable\n"); + printf("1 - configure sequence RAM 1\n"); + printf("2 - configure sequence RAM 2\n"); + printf("q - quit and return to vxWorks shell\n"); + printf("gnnn - generate a one-shot event number nnn\n"); + return; +} +int EG(void) +{ + static int Card = 0; + char buf[100]; + + printf("Event generator testerizer\n"); + printf("Enter Card number [%d]:", Card); + fgets(buf, sizeof(buf), stdin); + sscanf(buf, "%d", &Card); + + if (EgCheckCard(Card) != 0) + { + printf("Invalid card number specified\n"); + return(-1); + } + printf("Card address: %08.8X\n", EgLink[Card].pEg); + + + while (1) + { + menu(); + + if (fgets(buf, sizeof(buf), stdin) == NULL) + return(0); + + switch (buf[0]) + { + case 'r': EgResetAll(&EgLink[Card]); break; + case '1': ConfigSeq(&EgLink[Card], 1); break; + case '2': ConfigSeq(&EgLink[Card], 2); break; + case 'm': EgMasterEnable(&EgLink[Card]); break; + case 'g': EgGenerateVmeEvent(&EgLink[Card], atoi(&buf[1])); break; + case 'q': return(0); + } + } + return(0); +} +#endif /* EG_MONITOR */ diff --git a/src/dev/devApsEr.c b/src/dev/devApsEr.c new file mode 100644 index 000000000..207390764 --- /dev/null +++ b/src/dev/devApsEr.c @@ -0,0 +1,1151 @@ +#define ER_DEBUG /**/ +/* + * Author: John R. Winans + * Date: 07-21-93 + * + * ***************************************************************** + * COPYRIGHT NOTIFICATION + * ***************************************************************** + * + * THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE, + * AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE + * AND IN ALL SOURCE LISTINGS OF THE CODE. + * + * (C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + * + * Argonne National Laboratory (ANL), with facilities in the States of + * Illinois and Idaho, is owned by the United States Government, and + * operated by the University of Chicago under provision of a contract + * with the Department of Energy. + * + * Portions of this material resulted from work developed under a U.S. + * Government contract and are subject to the following license: For + * a period of five years from March 30, 1993, the Government is + * granted for itself and others acting on its behalf a paid-up, + * nonexclusive, irrevocable worldwide license in this computer + * software to reproduce, prepare derivative works, and perform + * publicly and display publicly. With the approval of DOE, this + * period may be renewed for two additional five year periods. + * Following the expiration of this period or periods, the Government + * is granted for itself and others acting on its behalf, a paid-up, + * nonexclusive, irrevocable worldwide license in this computer + * software to reproduce, prepare derivative works, distribute copies + * to the public, perform publicly and display publicly, and to permit + * others to do so. + * + * ***************************************************************** + * DISCLAIMER + * ***************************************************************** + * + * NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR + * THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS, + * MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL + * LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR + * USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS + * DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY + * OWNED RIGHTS. + * + * ***************************************************************** + * LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY + * DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#ifdef ER_DEBUG +#define STATIC +#else +#define STATIC static +#endif + +typedef struct ApsErStruct +{ + unsigned short Control; + unsigned short EventRamAddr; + unsigned short EventRamData; + unsigned short OutputPulseEnables; + unsigned short OutputLevelEnables; + unsigned short TriggerEventEnables; + unsigned short EventCounterLo; + unsigned short EventCounterHi; + unsigned short TimeStampLo; + unsigned short TimeStampHi; + + unsigned short EventFifo; + unsigned short EventTimeHi; + unsigned short DelayPulseEnables; + unsigned short DelayPulseSelect; + unsigned short PulseDelay; + unsigned short PulseWidth; + unsigned short IrqVector; + unsigned short IrqEnables; + +} ApsErStruct; + + +/* + * CONTROL_REG_OR_STRIP = bits that we should never leave set when or-ing + * on other bits in the control register. + */ +#define CONTROL_REG_OR_STRIP (~0x3c9f) + +#define NUM_EVENTS 256 + +#define ER_IRQ_ALL 0x000f +#define ER_IRQ_OFF 0x0000 +#define ER_IRQ_TELL 0xffff +#define ER_IRQ_EVENT 0x0008 +#define ER_IRQ_HEART 0x0004 +#define ER_IRQ_FIFO 0x0002 +#define ER_IRQ_TAXI 0x0001 + +typedef struct ErLinkStruct +{ + struct erRecord *pRec; + int Card; + long IrqVector; + long IrqLevel; + ApsErStruct *pEr; + SEM_ID LinkLock; /* Lock for the card */ + unsigned short ErEventTab[NUM_EVENTS]; /* current view of the RAM */ + IOSCANPVT IoScanPvt[NUM_EVENTS]; /* event-based rec processing */ + EVENT_FUNC EventFunc; + ERROR_FUNC ErrorFunc; +} ErLinkStruct; + +#define NUM_ER_LINKS 4 +static int ErNumLinks = 0; /* User configurable link limit */ +static int ConfigureLock = 0; +STATIC ErLinkStruct ErLink[NUM_ER_LINKS]; +int ErDebug = 0; + +int ErStallIrqs = 1; + +STATIC long ErMasterEnableGet(ApsErStruct *pParm); +STATIC long ErMasterEnableSet(ApsErStruct *pParm, int Enable); +STATIC long ErSetTrg(ApsErStruct *pParm, int Channel, int Enable); +STATIC long ErSetOtp(ApsErStruct *pParm, int Channel, int Enable); +STATIC long ErSetOtl(ApsErStruct *pParm, int Channel, int Enable); +STATIC long ErSetDg(ApsErStruct *pParm, int Channel, int Enable, unsigned short Delay, unsigned short Width); +STATIC unsigned short ErEnableIrq(ApsErStruct *pParm, unsigned short Mask); +STATIC int ErRegisterIrq(ErLinkStruct *pLink, int IrqVector, int IrqLevel); +STATIC long ErCheckTaxi(ApsErStruct *pParm); +STATIC int ErGetRamStatus(ApsErStruct *pParm, int Ram); +STATIC int ErResetAll(ApsErStruct *pParm); +STATIC int ErUpdateRam(ApsErStruct *pParm, unsigned short *RamBuf); +STATIC int ErProgramRam(ApsErStruct *pParm, unsigned short *RamBuf, int Ram); +STATIC int ErEnableRam(ApsErStruct *pParm, int Ram); +STATIC long proc(struct erRecord *pRec); + +/****************************************************************************** + * + * Routine used to verify that a given card number is valid. + * Returns zero if valid, nonzero otherwise. + * + ******************************************************************************/ +long ErHaveReceiver(int Card) +{ + if ((Card < 0)||(Card >= ErNumLinks)) + return(-1); + if (ErLink[Card].pEr == NULL) + return(-1); + return(256); /* Return the number of possible event codes, 0-255 */ +} +/****************************************************************************** + * + * Register a listener for the event system. Every time we get an event from + * the event receiver, we will call the registered listener and pass in the + * event number received and the tick counter value when that event was + * received. + * + ******************************************************************************/ +long ErRegisterEventHandler(int Card, EVENT_FUNC func) +{ + if (ErDebug) + printf("ErRegisterEventHandler(%d, %08.8X\n", Card, func); + + ErLink[Card].EventFunc = func; + return(0); +} +/****************************************************************************** + * + * Register a listener for the event system. Every time we get an event from + * the event receiver, we will call the registered listener and pass in the + * event number received and the tick counter value when that event was + * received. + * + ******************************************************************************/ +long ErRegisterErrorHandler(int Card, ERROR_FUNC func) +{ + if (ErDebug) + printf("ErRegisterEventHandler(%d, %08.8X\n", Card, func); + + ErLink[Card].ErrorFunc = func; + return(0); +} +/****************************************************************************** + * + * Return the current tick counter value. + * + ******************************************************************************/ +long ErGetTicks(int Card, unsigned long *Ticks) +{ + if (ErHaveReceiver(Card) < 0) + return(-1); + + /* BUG -- Do we read the HI first or the low? */ + + *Ticks = ErLink[Card].pEr->EventCounterLo; + *Ticks += ErLink[Card].pEr->EventCounterHi << 16; + + return(0); +} + +/****************************************************************************** + * + * This routine is to be called in the startup script in order to init the + * card addresses and the associated IRQ vectors and levels. + * + * By default there are no cards configured. + * + ******************************************************************************/ +int ErConfigure(int Card, unsigned long CardAddress, unsigned int IrqVector, unsigned int IrqLevel) +{ + short Junk; + + if (ConfigureLock != 0) + { + logMsg("devApsEr: Cannot change configuration after init. Request ignored\n"); + return(-1); + } + if (Card >= NUM_ER_LINKS) + { + logMsg("devApsEr: Card number invalid, must be 0-%d\n", NUM_ER_LINKS); + return(-1); + } + if (CardAddress > 0xffff) + { + logMsg("devApsEr: Card address invalid, must be 0x0000-0xffff\n"); + return(-1); + } + if(sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO, (char*)CardAddress, (char**)&ErLink[Card].pEr)!=OK) + { + logMsg("devApsEr: Failure mapping requested A16 address\n"); + ErLink[Card].pEr = NULL; + return(-1); + } + if (vxMemProbe((char*)&ErLink[Card].pEr->Control, READ, sizeof(short), (char*)&Junk) != OK) + { + logMsg("devApsEr: Failure probing for event receiver... Card disabled\n"); + ErLink[Card].pEr = NULL; + return(-1); + } + ErLink[Card].IrqVector = IrqVector; + ErLink[Card].IrqLevel = IrqLevel; + + if (Card >= ErNumLinks) + ErNumLinks = Card+1; + + return(0); +} +/****************************************************************************** + * + * A function to shut up an event receiver in case we get a ^X style reboot. + * + ******************************************************************************/ +static void ErRebootFunc(void) +{ + int j = 0; + + while (j < ErNumLinks) + { + if (ErLink[j].pEr != NULL) + ErEnableIrq(ErLink[j].pEr, ER_IRQ_OFF); + ++j; + } + return; +} +/****************************************************************************** + * + * Register and init the IRQ handlers for each ER card. + * + ******************************************************************************/ +STATIC long ErInitDev(int pass) +{ + int j; + int k; + static int OneShotFlag = 1; + + if (ErDebug) + printf("ErInitDev(%d)\n", pass); + + if (OneShotFlag) + { + OneShotFlag = 0; + rebootHookAdd(ErRebootFunc); + + ConfigureLock = 1; /* Prevent any future ErConfigure's */ + + /* Clear the record pointers */ + for (j=0;j= 0) + { + if ((ErLink[j].LinkLock = semBCreate(SEM_Q_PRIORITY, SEM_FULL)) == NULL) + return(-1); + for (k=0;k<256;k++) + { + ErLink[j].Card = j; + ErLink[j].ErEventTab[k] = 0; + /* ErLink[j].EventFunc = NULL; Should be NULL because is static */ + /* ErLink[j].ErrorFunc = NULL; */ + scanIoInit(&ErLink[j].IoScanPvt[k]); + } + ErLink[j].pRec = NULL; + ErResetAll(ErLink[j].pEr); + ErRegisterIrq(&ErLink[j], ErLink[j].IrqVector, ErLink[j].IrqLevel); + } + } + } + if (pass == 1) + { + for (j=0;j= 0) + ErEnableIrq(ErLink[j].pEr, ER_IRQ_ALL); + } + return(0); +} +#if 0 +scum() +{ + int j; + + for (j=0;j= 0) + ErEnableIrq(ErLink[j].pEr, ER_IRQ_ALL); +} +#endif +/****************************************************************************** + * + * Init routine for the ER record type. + * + ******************************************************************************/ +STATIC long init_record(struct erRecord *pRec) +{ + ErLinkStruct *pLink; + unsigned long mask; + + if (ErDebug) + printf("devApsEr::init_record() entered\n"); + + if (ErHaveReceiver(pRec->out.value.vmeio.card) < 0) + { + recGblRecordError(S_db_badField, (void *)pRec, "devApsEr::ErInitErRec() Invalid card number"); + return(S_db_badField); + } + pLink = &ErLink[pRec->out.value.vmeio.card]; + + /* Make sure we only have one record for a given ER card */ + if (pLink->pRec != NULL) + { + recGblRecordError(S_db_badField, (void *)pRec, "devApsEr::ErInitErRec() onlyone record allowed per card"); + return(S_db_badField); + } + pLink->pRec = pRec; + + proc(pRec); + + return(0); +} +/****************************************************************************** + * + * Process routine for the ER record type. + * + ******************************************************************************/ +STATIC long proc(struct erRecord *pRec) +{ + ErLinkStruct *pLink = &ErLink[pRec->out.value.vmeio.card]; + + if (pRec->tpro > 10) + printf("devApsEr::proc(%s) entered\n", pRec->name); + + /* Make sure the card is present */ + if (ErHaveReceiver(pRec->out.value.vmeio.card) < 0) + return(0); + + semTake(pLink->LinkLock, WAIT_FOREVER); + + if (pRec->enab != ErMasterEnableGet(pLink->pEr)) + ErMasterEnableSet(pLink->pEr, pRec->enab); + + ErSetTrg(pLink->pEr, 0, pRec->trg0); + ErSetTrg(pLink->pEr, 1, pRec->trg1); + ErSetTrg(pLink->pEr, 2, pRec->trg2); + ErSetTrg(pLink->pEr, 3, pRec->trg3); + ErSetTrg(pLink->pEr, 4, pRec->trg4); + ErSetTrg(pLink->pEr, 5, pRec->trg5); + ErSetTrg(pLink->pEr, 6, pRec->trg6); + + ErSetOtp(pLink->pEr, 0, pRec->otp0); + ErSetOtp(pLink->pEr, 1, pRec->otp1); + ErSetOtp(pLink->pEr, 2, pRec->otp2); + ErSetOtp(pLink->pEr, 3, pRec->otp3); + ErSetOtp(pLink->pEr, 4, pRec->otp4); + ErSetOtp(pLink->pEr, 5, pRec->otp5); + ErSetOtp(pLink->pEr, 6, pRec->otp6); + ErSetOtp(pLink->pEr, 7, pRec->otp7); + ErSetOtp(pLink->pEr, 8, pRec->otp8); + ErSetOtp(pLink->pEr, 9, pRec->otp9); + ErSetOtp(pLink->pEr, 10, pRec->otpa); + ErSetOtp(pLink->pEr, 11, pRec->otpb); + ErSetOtp(pLink->pEr, 12, pRec->otpc); + ErSetOtp(pLink->pEr, 13, pRec->otpd); + + ErSetOtl(pLink->pEr, 0, pRec->otl0); + ErSetOtl(pLink->pEr, 1, pRec->otl1); + ErSetOtl(pLink->pEr, 2, pRec->otl2); + ErSetOtl(pLink->pEr, 3, pRec->otl3); + ErSetOtl(pLink->pEr, 4, pRec->otl4); + ErSetOtl(pLink->pEr, 5, pRec->otl5); + ErSetOtl(pLink->pEr, 6, pRec->otl6); + + ErSetDg(pLink->pEr, 0, pRec->dg0e, pRec->dg0d, pRec->dg0w); + ErSetDg(pLink->pEr, 1, pRec->dg1e, pRec->dg1d, pRec->dg1w); + ErSetDg(pLink->pEr, 2, pRec->dg2e, pRec->dg2d, pRec->dg2w); + ErSetDg(pLink->pEr, 3, pRec->dg3e, pRec->dg3d, pRec->dg3w); + + if (ErCheckTaxi(pLink->pEr) != 0) + pRec->taxi = 1; + else + pRec->taxi = 0; + + semGive(pLink->LinkLock); + + pRec->udf = 0; + return(0); +} +ErDsetStruct devEr={ 5, NULL, ErInitDev, init_record, NULL, proc}; + +/****************************************************************************** + * + * Init routine for the EREVENT record type. + * + ******************************************************************************/ +STATIC long ErEventInitRec(struct ereventRecord *pRec) +{ + if (ErDebug) + printf("ErEventInitRec(%s)\n", pRec->name); + + if (ErHaveReceiver(pRec->out.value.vmeio.card) < 0) + { + recGblRecordError(S_db_badField, (void *)pRec, "devApsEr::ErEventInitRec() invalid card number in INP field"); + return(S_db_badField); + } + if ((pRec->out.value.vmeio.signal < 0)||(pRec->out.value.vmeio.signal > 255)) + { + recGblRecordError(S_db_badField, (void *)pRec, "devApsEr::ErEventInitRec() invalid signal number in INP field"); + return(S_db_badField); + } + + pRec->lenm = 300; /* Force setting on first process */ + pRec->lout = 0; /* Clear the 'last' event mask */ + return(0); +} +/****************************************************************************** + * + * Process routine for the EREVENT record type. + * + ******************************************************************************/ +STATIC long ErEventProc(struct ereventRecord *pRec) +{ + ErLinkStruct *pLink = &ErLink[pRec->out.value.vmeio.card]; + int DownLoadRam = 0; + unsigned short Mask; + + if (pRec->tpro > 10) + printf("ErEventProc(%s) entered\n", pRec->name); + + /* Make sure the card is present */ + if (ErHaveReceiver(pRec->out.value.vmeio.card) < 0) + return(0); + + if (pRec->enab != 0) + { + if (pRec->tpro > 10) + printf("ErEventProc(%s) enable=true\n", pRec->name); + + semTake(pLink->LinkLock, WAIT_FOREVER); + if (pRec->enm != pRec->lenm) + { + if (pRec->tpro > 10) + printf("ErEventProc(%s) event number changed %d-%d\n", pRec->name, pRec->lenm, pRec->enm); + /* Transfer the event info to new position */ + if ((pRec->lenm < 256) && (pRec->lenm >= 0)) + pLink->ErEventTab[pRec->lenm] = 0; + + DownLoadRam = 1; + pRec->lenm = pRec->enm; + } + /* Build event mask */ + /* NOTE: that we never latch the time in the 32 bit latch */ + + Mask = 0; + if (pRec->out0 != 0) Mask |= 0x0001; + if (pRec->out1 != 0) Mask |= 0x0002; + if (pRec->out2 != 0) Mask |= 0x0004; + if (pRec->out3 != 0) Mask |= 0x0008; + if (pRec->out4 != 0) Mask |= 0x0010; + if (pRec->out5 != 0) Mask |= 0x0020; + if (pRec->out6 != 0) Mask |= 0x0040; + if (pRec->out7 != 0) Mask |= 0x0080; + if (pRec->out8 != 0) Mask |= 0x0100; + if (pRec->out9 != 0) Mask |= 0x0200; + if (pRec->outa != 0) Mask |= 0x0400; + if (pRec->outb != 0) Mask |= 0x0800; + if (pRec->outc != 0) Mask |= 0x1000; + if (pRec->outd != 0) Mask |= 0x2000; + if (pRec->vme != 0) Mask |= 0x8000; + + if (pRec->tpro > 10) + printf("ErEventProc(%s) New RAM mask is 0x%04.4X\n", pRec->name, Mask); + if (Mask != pRec->lout) + DownLoadRam = 1; + + if (DownLoadRam != 0) + { + if (pRec->enm != 0) + { + pLink->ErEventTab[pRec->enm] = Mask; + pRec->lout = Mask; + } + ErUpdateRam(pLink->pEr, pLink->ErEventTab); + } + if (pRec->tpro > 10) + printf("ErEventProc(%s) I/O operations complete\n", pRec->name); + semGive(pLink->LinkLock); + } + else + { + /* BUG kill event if was ever enabled! */ + } + + return(0); +} +ErDsetStruct devErevent={ 5, NULL, NULL, ErEventInitRec, NULL, ErEventProc}; +/****************************************************************************** + * + * Routine to initialize an event record. This is a regular EPICS event + * record!! Not an ER or EG event record. We allow the user to use the + * regular epics event records to request processing on an event that is + * received from the event receiver. + * + * All we gotta do here is set the dpvt field to point to the proper + * IOSCANEVENT field so that we can later return it on getIoScanInfo() calls. + * + ******************************************************************************/ +STATIC long ErEpicsEventInit(struct eventRecord *pRec) +{ + pRec->dpvt = NULL; /* In case problems arise below */ + + if(ErDebug) + printf("ErEpicsEventInit(%s) %d %d\n", pRec->name, pRec->inp.value.vmeio.card, pRec->inp.value.vmeio.signal); + + if (ErHaveReceiver(pRec->inp.value.vmeio.card) < 0) + { + recGblRecordError(S_db_badField, (void *)pRec, "devApsEr::ErEventInitRec() invalid card number in INP field"); + return(S_db_badField); + } + if ((pRec->inp.value.vmeio.signal < 0)||(pRec->inp.value.vmeio.signal > 255)) + { + recGblRecordError(S_db_badField, (void *)pRec, "devApsEr::ErEventInitRec() invalid signal number in INP field"); + return(S_db_badField); + } + + pRec->dpvt = &ErLink[pRec->inp.value.vmeio.card].IoScanPvt[pRec->inp.value.vmeio.signal]; + return(0); +} +/****************************************************************************** + * + * Routine to get the IOSCANPVT value for an EVENT record type. + * + ******************************************************************************/ +STATIC long ErEpicsEventGetIoScan(int cmd, struct eventRecord *pRec, IOSCANPVT *pPvt) +{ + *pPvt = *((IOSCANPVT*)(pRec->dpvt)); + return(0); +} +ErDsetStruct devErEpicsEvent={5, NULL, NULL, ErEpicsEventInit, ErEpicsEventGetIoScan, NULL}; + +/****************************************************************************** + * + * Inquire as to if the card is enabled or not. + * + ******************************************************************************/ +STATIC long ErMasterEnableGet(ApsErStruct *pParm) +{ + volatile ApsErStruct *pEr = pParm; + return((pEr->Control & 0x8000) != 0); +} +/****************************************************************************** + * + * Enable/disable the card. + * + ******************************************************************************/ +STATIC long ErMasterEnableSet(ApsErStruct *pParm, int Enable) +{ + volatile ApsErStruct *pEr = pParm; + + if (Enable != 0) + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x8000; + else + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)&~0x8000; + return(0); +} +/****************************************************************************** + * + * Check to see if we have a taxi violation and reset it if so. + * + ******************************************************************************/ +STATIC long ErCheckTaxi(ApsErStruct *pParm) +{ + volatile ApsErStruct *pEr = pParm; + + if (pEr->Control & 0x0001) + { + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x0001; + return(1); + } + return(0); +} +/****************************************************************************** + * + * Set/clear an enable bit in the trigger mask. + * + ******************************************************************************/ +STATIC long ErSetTrg(ApsErStruct *pParm, int Channel, int Enable) +{ + volatile ApsErStruct *pEr = pParm; + unsigned short mask; + + mask = 1; + mask <<= Channel; + + if (Enable != 0) + pEr->TriggerEventEnables |= mask; + else + pEr->TriggerEventEnables &= ~mask; + return(0); +} +/****************************************************************************** + * + * Set/clear an enable bit in the one-shot mask. + * + ******************************************************************************/ +STATIC long ErSetOtp(ApsErStruct *pParm, int Channel, int Enable) +{ + volatile ApsErStruct *pEr = pParm; + unsigned short mask; + + mask = 1; + mask <<= Channel; + + if (Enable != 0) + pEr->OutputPulseEnables |= mask; + else + pEr->OutputPulseEnables &= ~mask; + return(0); +} +/****************************************************************************** + * + * Set/clear an enable bit in the level-trigger mask. + * + ******************************************************************************/ +STATIC long ErSetOtl(ApsErStruct *pParm, int Channel, int Enable) +{ + volatile ApsErStruct *pEr = pParm; + unsigned short mask; + + mask = 1; + mask <<= Channel; + + if (Enable != 0) + pEr->OutputLevelEnables |= mask; + else + pEr->OutputLevelEnables &= ~mask; + return(0); +} +/****************************************************************************** + * + * Set/clear an enable bit in the programmable pulse delay mask. If enabling + * a channel, the delay and width are also set. + * + ******************************************************************************/ +STATIC long ErSetDg(ApsErStruct *pParm, int Channel, int Enable, unsigned short Delay, unsigned short Width) +{ + volatile ApsErStruct *pEr = pParm; + unsigned short mask; + + mask = 1; + mask <<= Channel; + + if (Enable != 0) + { + pEr->DelayPulseSelect = Channel; + pEr->PulseDelay = Delay; + pEr->PulseWidth = Width; + pEr->DelayPulseEnables |= mask; + } + else + pEr->DelayPulseEnables &= ~mask; + return(0); +} +/****************************************************************************** + * + * A debugging aid that dumps out all the regs on the ER board. + * + ******************************************************************************/ +STATIC int ErDumpRegs(ApsErStruct *pParm) +{ + volatile ApsErStruct *pEr = pParm; + + printf("%04.4X %04.4X %04.4X %04.4X %04.4X %04.4X %04.4X %04.4X %04.4X %04.4X\n", + pEr->Control, pEr->EventRamAddr, pEr->EventRamData, pEr->OutputPulseEnables, + pEr->OutputLevelEnables, pEr->TriggerEventEnables, pEr->EventCounterLo, + pEr->EventCounterHi, pEr->TimeStampLo, pEr->TimeStampHi); + + printf("%04.4X %04.4X %04.4X %04.4X %04.4X %04.4X %04.4X %04.4X\n", + pEr->EventFifo, pEr->EventTimeHi, pEr->DelayPulseEnables, pEr->DelayPulseSelect, + pEr->PulseDelay, pEr->PulseWidth, pEr->IrqVector, pEr->IrqEnables); + + return(0); +} + +/****************************************************************************** + * + * Reset, clear and disable everything on the board. + * + ******************************************************************************/ +STATIC int ErResetAll(ApsErStruct *pParm) +{ + volatile ApsErStruct *pEr = pParm; + + pEr->Control = 0x201d; + pEr->Control = 0x208d; + + while(pEr->Control & 0x0080) + taskDelay(1); + + pEr->OutputPulseEnables = 0; + pEr->OutputLevelEnables = 0; + pEr->DelayPulseEnables = 0; + pEr->DelayPulseSelect = 0; + pEr->IrqEnables = 0; + + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x8000; + + return(0); +} +/****************************************************************************** + * + * Receive a hardware IRQ from an ER board. + * + ******************************************************************************/ +STATIC void ErIrqHandler(ErLinkStruct *pLink) +{ + volatile ApsErStruct *pEr = pLink->pEr; + unsigned short mask; + unsigned short j; + unsigned short k; + short z; + unsigned long Time; + + mask = pEr->Control; + if(ErDebug > 9) + logMsg("ErIrqHandler() control =%04.4X\n", mask); + + if (mask&0x1000) + { /* Got a lost heart beat */ + pEr->Control = (mask&CONTROL_REG_OR_STRIP)|0x1000; + + if (pLink->ErrorFunc != NULL) + (*pLink->ErrorFunc)(pLink->Card, ERROR_HEART); + + if(ErDebug) + logMsg("ErIrqHandler() lost heart beat\n"); + } + + /* Read any stuff from the FIFO */ + if (mask&0x0800) + { + pEr->Control = (mask&CONTROL_REG_OR_STRIP)|0x0800; + if(ErDebug > 10) + logMsg("ErIrqHandler() clearing event with %04.4X\n", (mask&CONTROL_REG_OR_STRIP)|0x0800); + + z = 10; /* Make sure we don't get into a major spin loop */ + while ((pEr->Control & 0x0002)&&(--z > 0)) + { + unsigned short EventNum; + + j = pEr->EventFifo; + k = pEr->EventTimeHi; + + /* Mark the event time in the proper array place */ + EventNum = j & 0x00ff; + Time = (k<<8)|(j>>8); + + if (pLink->EventFunc != NULL) + { + (*pLink->EventFunc)(pLink->Card, EventNum, Time); + if(ErDebug) + logMsg("ErIrqHandler() Calling %08.8X", pLink->EventFunc); + } + + if(ErDebug) + logMsg("ErIrqHandler() %06.6X-%02.2X\n", Time, EventNum); + + /* Schedule processing for any event-driven records */ + scanIoRequest(pLink->IoScanPvt[EventNum]); + } + } + /* Kill any fifo overflow status */ + if (mask&0x0004) + { + pEr->Control = (mask&CONTROL_REG_OR_STRIP)|0x0004; + + if (pLink->ErrorFunc != NULL) + (*pLink->ErrorFunc)(pLink->Card, ERROR_LOST); + + if(ErDebug) + logMsg("ErIrqHandler() FIFO overflow %04.4X\n", (mask&CONTROL_REG_OR_STRIP)|0x0004); + } + if (mask&0x0001) + { + pEr->Control = (mask&CONTROL_REG_OR_STRIP)|0x0001; + + if (pLink->ErrorFunc != NULL) + (*pLink->ErrorFunc)(pLink->Card, ERROR_TAXI); + + if(ErDebug) + logMsg("ErIrqHandler() taxi violation %04.4X\n", pEr->Control = (mask&CONTROL_REG_OR_STRIP)|0x0001); + } + /* + * Disable and then re-enable the IRQs so board re-issues any + * that are still pending + */ + + pEr->Control = (mask&CONTROL_REG_OR_STRIP)&~0x4000; + pEr->Control = (mask&CONTROL_REG_OR_STRIP)| 0x4000; + + return; +} + +/****************************************************************************** + * + * Set up the IRQs for the receiver. + * (Should only be called once.) + * + ******************************************************************************/ +STATIC int ErRegisterIrq(ErLinkStruct *pLink, int IrqVector, int IrqLevel) +{ + volatile ApsErStruct *pEr = pLink->pEr; + + if (IrqVector != -1) + { + intConnect(INUM_TO_IVEC(IrqVector), ErIrqHandler, pLink); + sysIntEnable(IrqLevel); + pEr->IrqVector = IrqVector; + } + return(0); +} + +/****************************************************************************** + * + * Enable or disable the IRQs from the Event Receiver. + * + ******************************************************************************/ +STATIC unsigned short ErEnableIrq(ApsErStruct *pParm, unsigned short Mask) +{ + volatile ApsErStruct *pEr = pParm; + if (Mask == ER_IRQ_OFF) + { + pEr->IrqEnables = 0; + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP) & ~0x4000; + } + else if (Mask == ER_IRQ_TELL) + { + if (pEr->Control & 0x4000) + return(pEr->IrqEnables & ER_IRQ_ALL); + } + else + { + pEr->IrqEnables = Mask; + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x4000; + } + + return(0); +} + +/****************************************************************************** + * + * We load what ever RAM is not running. And Enable it. + * + ******************************************************************************/ +STATIC int ErUpdateRam(ApsErStruct *pParm, unsigned short *RamBuf) +{ + int ChosenRam = 2; + + /* Find the idle RAM */ + if (ErGetRamStatus(pParm, 1) == 0) + ChosenRam = 1; /* RAM 1 is currently idle */ + + ErProgramRam(pParm, RamBuf, ChosenRam); + + ErEnableRam(pParm, ChosenRam); + return(0); +} +/****************************************************************************** + * + * Download the entire RAM from a buffer. + * + ******************************************************************************/ +STATIC int ErProgramRam(ApsErStruct *pParm, unsigned short *RamBuf, int Ram) +{ + volatile ApsErStruct *pEr = pParm; + int j; + + if(ErDebug) + printf("RAM download for RAM %d\n", Ram); + + if (Ram == 1) + { + if ((pEr->Control&0x0300) == 0x0200) + return(-1); /* RAM 1 is enabled */ + + /* select VME access to ram 1 */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP) & ~0x0040; + } + else + if (Ram == 2) + { + if ((pEr->Control&0x0300) == 0x0300) + return(-1); /* RAM 2 is enabled */ + + /* select VME access to ram 2 */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x0040; + } + else + return(-1); + + /* Reset RAM address */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x0010; + + /* enable auto increment */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x0020; + + pEr->EventRamAddr = 0; + + for (j=0; j<256; j++) + { + pEr->EventRamData = RamBuf[j]; + if((ErDebug)&&(RamBuf[j] != 0)) + printf("%d: %d\n", j, RamBuf[j]); + } + /* Turn off auto-increment */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP) & ~0x0020; + return(0); +} + +/****************************************************************************** + * + * Print the entire RAM from a buffer. We skip the null events. + * + ******************************************************************************/ +STATIC int ErDumpRam(ApsErStruct *pParm, int Ram) +{ + volatile ApsErStruct *pEr = pParm; + int j; + int x, y; + + if (Ram == 1) + { + if ((pEr->Control&0x0300) == 0x0200) + return(-1); /* RAM 1 is enabled */ + + /* select VME access to ram 1 */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP) & ~0x0040; + } + else + if (Ram == 2) + { + if ((pEr->Control&0x0300) == 0x0300) + return(-1); /* RAM 2 is enabled */ + + /* select VME access to ram 2 */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x0040; + } + else + return(-1); + + /* Reset RAM address */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x0010; + + /* enable auto increment */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP)|0x0020; + + pEr->EventRamAddr = 0; + + for (j=0; j<256; j++) + { + x = pEr->EventRamAddr & 0x00ff; + y = pEr->EventRamData; + if (y != 0) + printf("RAM %d, %d\n", x, y); + } + + /* turn off auto-increment */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP) & ~0x0020; + + return(0); +} + +/****************************************************************************** + * + * Select the specified RAM for operation + * + ******************************************************************************/ +STATIC int ErEnableRam(ApsErStruct *pParm, int Ram) +{ + volatile ApsErStruct *pEr = pParm; + + if (Ram == 0) + { + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP) & ~0x0200; + return(0); + } + if (Ram == 1) + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP) & ~0x0100; + else if (Ram == 2) + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP) | 0x0100; + else + return(-1); + + /* Set the map enable bit */ + pEr->Control = (pEr->Control&CONTROL_REG_OR_STRIP) | 0x0200; + + return(0); +} +/****************************************************************************** + * + * Return 1 if the requested RAM is enabled, 0 otherwise. We return -1 on + * error. + * + ******************************************************************************/ +STATIC int ErGetRamStatus(ApsErStruct *pParm, int Ram) +{ + volatile ApsErStruct *pEr = pParm; + + /* Check if RAM map is not enabled */ + if ((pEr->Control & 0x0200) == 0) + return(0); + + if (Ram == 1) + return((pEr->Control & 0x0100) == 0); + + if (Ram == 2) + return((pEr->Control & 0x0100) != 0); + + return(-1); /* We should never get here, invalid RAM number */ +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + + +static int DumpEventFifo(ApsErStruct *pParm) +{ + unsigned short j; + unsigned short k; + volatile ApsErStruct *pEr = pParm; + + while (pEr->Control & 0x0002) + { + j = pEr->EventFifo; + k = pEr->EventTimeHi; + printf("FIFO event: %04.4X%04.4X\n", k, j); + } + return(0); +} + +static void MainMenu(void) +{ + printf("r - Reset everything on the event receiver\n"); + printf("f - drain the event FIFO\n"); + printf("1 - dump event RAM 1\n"); + printf("2 - dump event RAM 2\n"); + printf("z - Dump event receiver regs\n"); + printf("q - quit\n"); +} +int ER(void) +{ + static int Card = 0; + char buf[100]; + + printf("Event receiver testerizer\n"); + printf("Enter Card number [%d]:", Card); + fgets(buf, sizeof(buf), stdin); + sscanf(buf, "%d", &Card); + + if (ErHaveReceiver(Card) < 0) + { + printf("Invalid card number specified\n"); + return(-1); + } + printf("Card address: %08.8X\n", ErLink[Card].pEr); + + while(1) + { + MainMenu(); + + if (fgets(buf, sizeof(buf), stdin) == NULL) + break; + + switch (buf[0]) + { + case 'r': ErResetAll(ErLink[Card].pEr); break; + case 'd': ErEnableRam(ErLink[Card].pEr, 0); break; + case 'f': DumpEventFifo(ErLink[Card].pEr); break; + case '1': ErDumpRam(ErLink[Card].pEr, 1); break; + case '2': ErDumpRam(ErLink[Card].pEr, 2); break; + case 'z': ErDumpRegs(ErLink[Card].pEr); break; + case 'q': return(0); + } + } + return(0); +} diff --git a/src/rec/recEg.c b/src/rec/recEg.c new file mode 100644 index 000000000..830396cd6 --- /dev/null +++ b/src/rec/recEg.c @@ -0,0 +1,201 @@ +/* + +***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE, +AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE +AND IN ALL SOURCE LISTINGS OF THE CODE. + +(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + +Argonne National Laboratory (ANL), with facilities in the States of +Illinois and Idaho, is owned by the United States Government, and +operated by the University of Chicago under provision of a contract +with the Department of Energy. + +Portions of this material resulted from work developed under a U.S. +Government contract and are subject to the following license: For +a period of five years from March 30, 1993, the Government is +granted for itself and others acting on its behalf a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, and perform +publicly and display publicly. With the approval of DOE, this +period may be renewed for two additional five year periods. +Following the expiration of this period or periods, the Government +is granted for itself and others acting on its behalf, a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, distribute copies +to the public, perform publicly and display publicly, and to permit +others to do so. + +***************************************************************** + DISCLAIMER +***************************************************************** + +NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR +THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS, +MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL +LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR +USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS +DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY +OWNED RIGHTS. + +***************************************************************** +LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY +DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000). +*/ + +/* + * + * Author: John Winans + * Date: 8/27/93 + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define STATIC static + +STATIC void EgMonitor(struct egRecord *pRec); + +/* Create RSET - Record Support Entry Table*/ +#define report NULL +#define initialize NULL +STATIC long EgInitRec(struct egRecord *, int); +STATIC long EgProc(struct egRecord *); +#define special NULL +STATIC long EgGetValue(); +#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 + +struct rset egRSET={ + RSETNUMBER, + report, + initialize, + EgInitRec, + EgProc, + special, + EgGetValue, + 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 }; + + + +STATIC long EgInitRec(struct egRecord *pRec, int pass) +{ + EgDsetStruct *pDset = (EgDsetStruct *) pRec->dset; + + if (pass == 1) + { + /* Init the card via driver calls */ + /* Make sure we have a usable device support module */ + if (pDset == NULL) + { + recGblRecordError(S_dev_noDSET,(void *)pRec, "eg: EgInitRec"); + return(S_dev_noDSET); + } + if (pDset->number < 5) + { + recGblRecordError(S_dev_missingSup,(void *)pRec, "eg: EgInitRec"); + return(S_dev_missingSup); + } + if( pDset->initRec != NULL) + return(*pDset->initRec)(pRec); + } + pRec->taxi = 0; + + return(0); +} +/****************************************************************************** + ******************************************************************************/ +STATIC long EgProc(struct egRecord *pRec) +{ + EgDsetStruct *pDset = (EgDsetStruct *) pRec->dset; + + pRec->pact=TRUE; + + pRec->ltax = pRec->taxi; /* The only monitorable field we can change */ + + if (pRec->tpro > 10) + printf("recEg::EgProc(%s) entered\n", pRec->name); + + if (pDset->proc != NULL) + (*pDset->proc)(pRec); + + /* Take care of time stamps and such */ + pRec->udf=FALSE; + /*tsLocalTime(&pRec->time);*/ + recGblGetTimeStamp(pRec); + + /* Deal with monitor stuff */ + EgMonitor(pRec); + /* process the forward scan link record */ + recGblFwdLink(pRec); + + pRec->pact=FALSE; + return(0); +} +/****************************************************************************** + * + * Value fields are worthless. + * + ******************************************************************************/ +STATIC long EgGetValue(struct egRecord *pRec, struct valueDes *pvdes) +{ + pvdes->field_type = DBF_CHAR; + pvdes->no_elements=1; + (char *)(pvdes->pvalue) = pRec->val; + return(0); +} + +/****************************************************************************** + * + ******************************************************************************/ +STATIC void EgMonitor(struct egRecord *pRec) +{ + unsigned short monitor_mask; + + monitor_mask = recGblResetAlarms(pRec); + monitor_mask |= (DBE_VALUE | DBE_LOG); + db_post_events(pRec, &pRec->val, monitor_mask); + + if (pRec->taxi != pRec->ltax) + db_post_events(pRec, &pRec->taxi, monitor_mask); + + return; +} diff --git a/src/rec/recEgevent.c b/src/rec/recEgevent.c new file mode 100644 index 000000000..57a0dda78 --- /dev/null +++ b/src/rec/recEgevent.c @@ -0,0 +1,265 @@ +/* + +***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE, +AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE +AND IN ALL SOURCE LISTINGS OF THE CODE. + +(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + +Argonne National Laboratory (ANL), with facilities in the States of +Illinois and Idaho, is owned by the United States Government, and +operated by the University of Chicago under provision of a contract +with the Department of Energy. + +Portions of this material resulted from work developed under a U.S. +Government contract and are subject to the following license: For +a period of five years from March 30, 1993, the Government is +granted for itself and others acting on its behalf a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, and perform +publicly and display publicly. With the approval of DOE, this +period may be renewed for two additional five year periods. +Following the expiration of this period or periods, the Government +is granted for itself and others acting on its behalf, a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, distribute copies +to the public, perform publicly and display publicly, and to permit +others to do so. + +***************************************************************** + DISCLAIMER +***************************************************************** + +NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR +THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS, +MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL +LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR +USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS +DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY +OWNED RIGHTS. + +***************************************************************** +LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY +DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000). +*/ + +/* + * Author: John Winans + * Date: 8/27/93 + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define STATIC static + +STATIC void EgEventMonitor(struct egeventRecord *pRec); + +/* Create RSET - Record Support Entry Table*/ +#define report NULL +#define initialize NULL +STATIC long EgEventInitRec(struct egeventRecord *, int); +STATIC long EgEventProc(struct egeventRecord *); +#define special NULL +STATIC long EgEventGetValue(); +#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 +static long get_graphic_double(struct dbAddr *paddr, struct dbr_grDouble *pgd); +static long get_control_double(struct dbAddr *paddr, struct dbr_ctrlDouble *pcd); +static long get_alarm_double(struct dbAddr *paddr, struct dbr_alDouble *pad); + +struct rset egeventRSET={ + RSETNUMBER, + report, + initialize, + EgEventInitRec, + EgEventProc, + special, + EgEventGetValue, + 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 }; + + + +STATIC long EgEventInitRec(struct egeventRecord *pRec, int pass) +{ + EgDsetStruct *pDset = (EgDsetStruct *) pRec->dset; + +printf("EgEventInitRec(%s, %d)\n", pRec->name, pass); + if (pass == 1) + { + /* Init the card via driver calls */ + /* Make sure we have a usable device support module */ + if (pDset == NULL) + { + recGblRecordError(S_dev_noDSET,(void *)pRec, "eg: EgEventInitRec"); + return(S_dev_noDSET); + } + if (pDset->number < 5) + { + recGblRecordError(S_dev_missingSup,(void *)pRec, "eg: EgEventInitRec"); + return(S_dev_missingSup); + } + if( pDset->initRec != NULL) + return(*pDset->initRec)((void *)pRec); + } + return(0); +} +/****************************************************************************** + ******************************************************************************/ +STATIC long EgEventProc(struct egeventRecord *pRec) +{ + EgDsetStruct *pDset = (EgDsetStruct *) pRec->dset; + + pRec->pact=TRUE; + + if (pRec->tpro > 10) + printf("recEgEvent::EgEventProc(%s) entered\n", pRec->name); + + if (pDset->proc) + (*pDset->proc)((void *)pRec); + + /* Take care of time stamps and such */ + pRec->udf=FALSE; + /* tsLocalTime(&pRec->time);*/ + recGblGetTimeStamp(pRec); + + /* Deal with monitor stuff */ + EgEventMonitor(pRec); + /* process the forward scan link record */ + recGblFwdLink(pRec); + + pRec->pact=FALSE; + return(0); +} +/****************************************************************************** + * + * Value fields are worthless. + * + ******************************************************************************/ +STATIC long EgEventGetValue(struct egeventRecord *pRec, struct valueDes *pvdes) +{ + pvdes->field_type = DBF_CHAR; + pvdes->no_elements=1; + (char *)(pvdes->pvalue) = pRec->val; + return(0); +} + +/****************************************************************************** + * + ******************************************************************************/ +STATIC void EgEventMonitor(struct egeventRecord *pRec) +{ + unsigned short monitor_mask; + + monitor_mask = recGblResetAlarms(pRec); + monitor_mask |= (DBE_VALUE | DBE_LOG); + db_post_events(pRec, &pRec->val, monitor_mask); +#if 0 /* this is done in the device support code */ + db_post_events(pRec, &pRec->adly, monitor_mask); + db_post_events(pRec, &pRec->dpos, monitor_mask); + db_post_events(pRec, &pRec->apos, monitor_mask); +#endif + return; +} +/****************************************************************************** + * + * + ******************************************************************************/ +static long get_graphic_double(struct dbAddr *paddr, struct dbr_grDouble *pgd) +{ + struct egeventRecord *pRec=(struct egeventRecord *)paddr->precord; + + if(paddr->pfield==(void *)&pRec->val) + { + pgd->upper_disp_limit = 0; + pgd->lower_disp_limit = 0; + } + else if(paddr->pfield==(void *)&pRec->dely + || paddr->pfield==(void *)&pRec->adly + || paddr->pfield==(void *)&pRec->dpos + || paddr->pfield==(void *)&pRec->apos) + { + pgd->upper_disp_limit = (32*1024) - 1; + pgd->lower_disp_limit = 0; + } + else if(paddr->pfield==(void *)&pRec->enm) + { + pgd->upper_disp_limit = 255; + pgd->lower_disp_limit = 0; + } + else + recGblGetGraphicDouble(paddr,pgd); + return(0); +} + +static long get_control_double(struct dbAddr *paddr, struct dbr_ctrlDouble *pcd) +{ + struct egeventRecord *pRec=(struct egeventRecord *)paddr->precord; + + if(paddr->pfield==(void *)&pRec->val) + { + pcd->upper_ctrl_limit = 0; + pcd->lower_ctrl_limit = 1; + } + else if(paddr->pfield==(void *)&pRec->dely + || paddr->pfield==(void *)&pRec->adly + || paddr->pfield==(void *)&pRec->dpos + || paddr->pfield==(void *)&pRec->apos) + { + pcd->upper_ctrl_limit = (32*1024) -1; + pcd->lower_ctrl_limit = 0; + } + else + recGblGetControlDouble(paddr,pcd); + return(0); +} + +static long get_alarm_double(struct dbAddr *paddr, struct dbr_alDouble *pad) +{ + struct egeventRecord *pRec=(struct egeventRecord *)paddr->precord; +#if 0 + { + pad->upper_alarm_limit = 2; + pad->upper_warning_limit = 2; + pad->lower_warning_limit = -1; + pad->lower_alarm_limit = -1; + } else +#endif + recGblGetAlarmDouble(paddr,pad); + return(0); +} diff --git a/src/rec/recEr.c b/src/rec/recEr.c new file mode 100644 index 000000000..f98ddd0af --- /dev/null +++ b/src/rec/recEr.c @@ -0,0 +1,305 @@ +/* + +***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE, +AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE +AND IN ALL SOURCE LISTINGS OF THE CODE. + +(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + +Argonne National Laboratory (ANL), with facilities in the States of +Illinois and Idaho, is owned by the United States Government, and +operated by the University of Chicago under provision of a contract +with the Department of Energy. + +Portions of this material resulted from work developed under a U.S. +Government contract and are subject to the following license: For +a period of five years from March 30, 1993, the Government is +granted for itself and others acting on its behalf a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, and perform +publicly and display publicly. With the approval of DOE, this +period may be renewed for two additional five year periods. +Following the expiration of this period or periods, the Government +is granted for itself and others acting on its behalf, a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, distribute copies +to the public, perform publicly and display publicly, and to permit +others to do so. + +***************************************************************** + DISCLAIMER +***************************************************************** + +NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR +THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS, +MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL +LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR +USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS +DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY +OWNED RIGHTS. + +***************************************************************** +LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY +DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000). +*/ + +/* + * + * Author: John Winans + * Date: 9/27/93 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define STATIC static + +STATIC void ErMonitor(struct erRecord *pRec); + +/* Create RSET - Record Support Entry Table*/ +#define report NULL +#define initialize NULL +STATIC long ErInitRec(struct erRecord *, int); +STATIC long ErProc(struct erRecord *); +#define ErSpecial NULL +STATIC long ErGetValue(); +#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 +static long get_graphic_double(struct dbAddr *paddr, struct dbr_grDouble *pgd); +static long get_control_double(struct dbAddr *paddr, struct dbr_ctrlDouble *pcd); +static long get_alarm_double(struct dbAddr *paddr, struct dbr_alDouble *pad); + +struct rset erRSET={ + RSETNUMBER, + report, + initialize, + ErInitRec, + ErProc, + ErSpecial, + ErGetValue, + 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 }; + + +/****************************************************************************** + * + * Init an ER record. + * + ******************************************************************************/ +STATIC long ErInitRec(struct erRecord *pRec, int pass) +{ + ErDsetStruct *pDset = (ErDsetStruct *) pRec->dset; + + if (pass == 1) + { + /* Init the card via driver calls */ + /* Make sure we have a usable device support module */ + if (pDset == NULL) + { + recGblRecordError(S_dev_noDSET,(void *)pRec, "er: ErInitRec"); + return(S_dev_noDSET); + } + if (pDset->number < 5) + { + recGblRecordError(S_dev_missingSup,(void *)pRec, "er: ErInitRec"); + return(S_dev_missingSup); + } + if( pDset->init_record != NULL) + return(*pDset->init_record)(pRec); + } + pRec->taxi = 0; + + return(0); +} +/****************************************************************************** + * + * Process an ER record. + * + ******************************************************************************/ +STATIC long ErProc(struct erRecord *pRec) +{ + ErDsetStruct *pDset = (ErDsetStruct *) pRec->dset; + + pRec->pact=TRUE; + + pRec->ltax = pRec->taxi; /* The only monitorable field we can change */ + + if (pRec->tpro > 10) + printf("recEr::ErProc(%s) entered\n", pRec->name); + + if (pDset->proc != NULL) + (*pDset->proc)(pRec); + + /* Take care of time stamps and such */ + pRec->udf=FALSE; + /* tsLocalTime(&pRec->time);*/ + recGblGetTimeStamp(pRec); + + /* Deal with monitor stuff */ + ErMonitor(pRec); + /* process the forward scan link record */ + recGblFwdLink(pRec); + + pRec->pact=FALSE; + return(0); +} +#if 0 /* this is not needed */ +/****************************************************************************** + * + * Used to check for changed field values + * + ******************************************************************************/ +STATIC long ErSpecial(struct dbAddr *paddr, int after) +{ + struct erRecord *pRec = (struct erRecord *)(paddr->precord); + void *p + + if(!after) + return(0); + + /* Make sure we have the proper special flag type spec'd */ + if (pdbAddr->special != SPC_MOD) + { + recGblDbaddrError(S_db_badChoice,pdbAddr,"bp: special"); + return(S_db_badChoice); + } + p = (void *)(pdbAddr->pfield); + + /* Figure out which field has been changed */ + if (p == &pRec->dg0d) + pRec->dgcm |= 1; + else ... + + return(0); +} +#endif +/****************************************************************************** + * + * Value fields are worthless. + * + ******************************************************************************/ +STATIC long ErGetValue(struct erRecord *pRec, struct valueDes *pvdes) +{ + pvdes->field_type = DBF_CHAR; + pvdes->no_elements=1; + (char *)(pvdes->pvalue) = pRec->val; + return(0); +} + +/****************************************************************************** + * + * Post any events for fields that might have changed while processing. + * + ******************************************************************************/ +STATIC void ErMonitor(struct erRecord *pRec) +{ + unsigned short monitor_mask; + + monitor_mask = recGblResetAlarms(pRec); + monitor_mask |= (DBE_VALUE | DBE_LOG); + db_post_events(pRec, &pRec->val, monitor_mask); + + if (pRec->taxi != pRec->ltax) + db_post_events(pRec, &pRec->taxi, monitor_mask); + + return; +} +static long get_graphic_double(struct dbAddr *paddr, struct dbr_grDouble *pgd) +{ + struct erRecord *pRec=(struct erRecord *)paddr->precord; + + if(paddr->pfield==(void *)&pRec->val) + { + pgd->upper_disp_limit = 0; + pgd->lower_disp_limit = 0; + } + else if(paddr->pfield==(void *)&pRec->dg0d + || paddr->pfield==(void *)&pRec->dg0w + || paddr->pfield==(void *)&pRec->dg1d + || paddr->pfield==(void *)&pRec->dg1w + || paddr->pfield==(void *)&pRec->dg2d + || paddr->pfield==(void *)&pRec->dg2w + || paddr->pfield==(void *)&pRec->dg3d + || paddr->pfield==(void *)&pRec->dg3w) + { + pgd->upper_disp_limit = 64*1024; + pgd->lower_disp_limit = 0; + } + else + recGblGetGraphicDouble(paddr,pgd); + return(0); +} + +static long get_control_double(struct dbAddr *paddr, struct dbr_ctrlDouble *pcd) +{ + struct erRecord *pRec=(struct erRecord *)paddr->precord; + + if(paddr->pfield==(void *)&pRec->val) + { + pcd->upper_ctrl_limit = 0; + pcd->lower_ctrl_limit = 1; + } + else if(paddr->pfield==(void *)&pRec->dg0d + || paddr->pfield==(void *)&pRec->dg0w + || paddr->pfield==(void *)&pRec->dg1d + || paddr->pfield==(void *)&pRec->dg1w + || paddr->pfield==(void *)&pRec->dg2d + || paddr->pfield==(void *)&pRec->dg2w + || paddr->pfield==(void *)&pRec->dg3d + || paddr->pfield==(void *)&pRec->dg3w) + { + pcd->upper_ctrl_limit = 64*1024; + pcd->lower_ctrl_limit = 0; + } + else + recGblGetControlDouble(paddr,pcd); + return(0); +} + +static long get_alarm_double(struct dbAddr *paddr, struct dbr_alDouble *pad) +{ + struct erRecord *pRec=(struct erRecord *)paddr->precord; +#if 0 + { + pad->upper_alarm_limit = 2; + pad->upper_warning_limit = 2; + pad->lower_warning_limit = -1; + pad->lower_alarm_limit = -1; + } else +#endif + recGblGetAlarmDouble(paddr,pad); + return(0); +} diff --git a/src/rec/recErevent.c b/src/rec/recErevent.c new file mode 100644 index 000000000..680eb0363 --- /dev/null +++ b/src/rec/recErevent.c @@ -0,0 +1,191 @@ +/* + +***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE, +AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE +AND IN ALL SOURCE LISTINGS OF THE CODE. + +(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + +Argonne National Laboratory (ANL), with facilities in the States of +Illinois and Idaho, is owned by the United States Government, and +operated by the University of Chicago under provision of a contract +with the Department of Energy. + +Portions of this material resulted from work developed under a U.S. +Government contract and are subject to the following license: For +a period of five years from March 30, 1993, the Government is +granted for itself and others acting on its behalf a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, and perform +publicly and display publicly. With the approval of DOE, this +period may be renewed for two additional five year periods. +Following the expiration of this period or periods, the Government +is granted for itself and others acting on its behalf, a paid-up, +nonexclusive, irrevocable worldwide license in this computer +software to reproduce, prepare derivative works, distribute copies +to the public, perform publicly and display publicly, and to permit +others to do so. + +***************************************************************** + DISCLAIMER +***************************************************************** + +NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR +THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS, +MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL +LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR +USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS +DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY +OWNED RIGHTS. + +***************************************************************** +LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY +DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000). +*/ + +/* + * + * Author: John Winans + * Date: 8/27/93 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define STATIC static + +STATIC void ErEventMonitor(struct ereventRecord *pRec); + +/* Create RSET - Record Support Entry Table*/ +#define report NULL +#define initialize NULL +STATIC long ErEventInitRec(struct ereventRecord *, int); +STATIC long ErEventProc(struct ereventRecord *); +#define special NULL +STATIC long ErEventGetValue(); +#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 + +struct rset ereventRSET={ + RSETNUMBER, + report, + initialize, + ErEventInitRec, + ErEventProc, + special, + ErEventGetValue, + 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 }; + + + +STATIC long ErEventInitRec(struct ereventRecord *pRec, int pass) +{ + EreventDsetStruct *pDset = (EreventDsetStruct *) pRec->dset; + + if (pass == 1) + { + /* Init the card via driver calls */ + /* Make sure we have a usable device support module */ + if (pDset == NULL) + { + recGblRecordError(S_dev_noDSET,(void *)pRec, "eg: ErEventInitRec"); + return(S_dev_noDSET); + } + if (pDset->number < 5) + { + recGblRecordError(S_dev_missingSup,(void *)pRec, "eg: ErEventInitRec"); + return(S_dev_missingSup); + } + if( pDset->initRec != NULL) + return(*pDset->initRec)(pRec); + } + return(0); +} +/****************************************************************************** + ******************************************************************************/ +STATIC long ErEventProc(struct ereventRecord *pRec) +{ + EreventDsetStruct *pDset = (EreventDsetStruct *) pRec->dset; + + pRec->pact=TRUE; + + if (pRec->tpro > 10) + printf("recErEvent::ErEventProc(%s) entered\n", pRec->name); + + if (pDset->proc) + (*pDset->proc)(pRec); + + /* Take care of time stamps and such */ + pRec->udf=FALSE; + /* tsLocalTime(&pRec->time);*/ + recGblGetTimeStamp(pRec); + + /* Deal with monitor stuff */ + ErEventMonitor(pRec); + /* process the forward scan link record */ + recGblFwdLink(pRec); + + pRec->pact=FALSE; + return(0); +} +/****************************************************************************** + * + * Value fields are worthless. + * + ******************************************************************************/ +STATIC long ErEventGetValue(struct ereventRecord *pRec, struct valueDes *pvdes) +{ + pvdes->field_type = DBF_CHAR; + pvdes->no_elements=1; + (char *)(pvdes->pvalue) = pRec->val; + return(0); +} + +/****************************************************************************** + * + ******************************************************************************/ +STATIC void ErEventMonitor(struct ereventRecord *pRec) +{ + unsigned short monitor_mask; + + monitor_mask = recGblResetAlarms(pRec); + monitor_mask |= (DBE_VALUE | DBE_LOG); + db_post_events(pRec, &pRec->val, monitor_mask); + return; +}