#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. * * BUG -- should add errMessage calls for problem events & include storm * control on them. * ******************************************************************************/ 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); }