Files
pcas/src/dev/devApsEg.c
1994-06-08 10:49:42 +00:00

2061 lines
57 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* #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 <vxWorks.h>
#include <types.h>
#include <iosLib.h>
#include <taskLib.h>
#include <semLib.h>
#include <memLib.h>
#include <lstLib.h>
#include <vme.h>
#include <sysLib.h>
#include <stdio.h>
#include <dbDefs.h>
#include <dbCommon.h>
#include <dbAccess.h>
#include <devSup.h>
#include <dbDefs.h>
#include <link.h>
#include <choiceEg.h>
#include <ellLib.h>
#include <egRecord.h>
#include <egeventRecord.h>
#include <egDefs.h>
#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;j<EgNumLinks;j++)
{
if (EgCheckCard(j) == 0)
{
/* Lock the EG link */
semTake (EgLink[j].EgLock, WAIT_FOREVER); /******** LOCK ***************/
if (EgGetMode(&EgLink[j], 1) != EG_SEQ_MODE_ALTERNATE)
{ /* Not in ALT mode, each ram is autonomous */
if(EgLink[j].Ram1Dirty != 0)
{
/* Make sure it is disabled and not running */
if ((EgGetMode(&EgLink[j], 1) == EG_SEQ_MODE_OFF) && (EgGetBusyStatus(&EgLink[j], 1) == 0))
{ /* download the RAM */
EgClearSeq(&EgLink[j], 1);
EgLoadRamList(&EgLink[j], 1);
EgLink[j].Ram1Dirty = 0;
}
else
Spinning = 1;
}
if(EgLink[j].Ram2Dirty != 0)
{
/* Make sure it is disabled and not running */
if ((EgGetMode(&EgLink[j], 2) == EG_SEQ_MODE_OFF) && (EgGetBusyStatus(&EgLink[j], 2) == 0))
{ /* download the RAM */
EgClearSeq(&EgLink[j], 2);
EgLoadRamList(&EgLink[j], 2);
EgLink[j].Ram2Dirty = 0;
}
else
Spinning = 1;
}
}
else /* We are in ALT mode, we have one logical RAM */
{
/* See if RAM 1 is available for downloading */
if ((EgLink[j].Ram1Dirty != 0)||(EgLink[j].Ram2Dirty != 0))
{
if (EgGetAltStatus(&EgLink[j], 1) == 0)
{
EgClearSeq(&EgLink[j], 1);
EgLoadRamList(&EgLink[j], 1);
EgLink[j].Ram1Dirty = 0;
EgLink[j].Ram2Dirty = 0;
/* Turn on RAM 1 */
EgEnableAltRam(&EgLink[j], 1);
}
else if (EgGetAltStatus(&EgLink[j], 2) == 0)
{
EgClearSeq(&EgLink[j], 2);
EgLoadRamList(&EgLink[j], 2);
EgLink[j].Ram1Dirty = 0;
EgLink[j].Ram2Dirty = 0;
/* Turn on RAM 2 */
EgEnableAltRam(&EgLink[j], 2);
}
else
Spinning = 1;
}
}
/* Unlock the EG link */
semGive (EgLink[j].EgLock); /******** UNLOCK *************/
}
}
}
}
/******************************************************************************
*
* Used to init and start the EG-RAM task.
*
******************************************************************************/
STATIC long EgStartRamTask(void)
{
if ((EgRamTaskEventSem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY)) == NULL)
{
printf("EgStartRamTask(): cannot create semaphore for ram task\n");
return(-1);
}
/* vxWorks's STUPID taskSpawn... they put in varargs, but didn't enable it. */
if (taskSpawn(EGRAM_NAME, EGRAM_PRI, EGRAM_OPT, EGRAM_STACK, (FUNCPTR)EgRamTask, 0,0,0,0,0,0,0,0,0,0) == ERROR)
{
printf("EgStartRamTask(): failed to start EG-ram task\n");
return(-1);
}
return (0);
}
/******************************************************************************
*
* Called at init time to init the EG-device support code.
*
* NOTE: can be called more than once for each init pass.
*
******************************************************************************/
STATIC long EgInitDev(int pass)
{
if (pass==0)
{ /* Do any hardware initialization (no records init'd yet) */
int j;
static int firsttime = 1;
if (firsttime)
{
firsttime = 0;
EgStartRamTask();
for (j=0;j<EgNumLinks;j++)
{
if (EgCheckCard(j) == 0)
{
if ((EgLink[j].EgLock = semBCreate(SEM_Q_PRIORITY, SEM_FULL)) == NULL)
printf("EgInitDev can not create semaphore\n");
EgResetAll(&EgLink[j]);
EgLink[j].pEgRec = NULL;
EgLink[j].Ram1Speed = 0;
EgLink[j].Ram1Dirty = 0;
EgLink[j].Ram2Speed = 0;
EgLink[j].Ram2Dirty = 0;
ellInit(&(EgLink[j].EgEvent1));
ellInit(&(EgLink[j].EgEvent2));
}
}
}
}
else if (pass==1)
{ /* Records are dun.. do any additional initialization */
int j;
for (j=0;j<EgNumLinks;j++)
{
if (EgCheckCard(j) == 0)
EgScheduleRamProgram(j); /* OK to do more than once */
}
}
return(0);
}
/******************************************************************************
*
* This is called by any function that determines that the sequence RAMs are
* out of sync with the database records. We simply wake up the EG RAM task.
*
******************************************************************************/
STATIC long EgScheduleRamProgram(int card)
{
semGive(EgRamTaskEventSem);
return(0);
}
/******************************************************************************
*
* Support for initialization of EG records.
*
******************************************************************************/
STATIC long EgInitEgRec(struct egRecord *pRec)
{
EgLinkStruct *pLink;
if (EgCheckCard(pRec->out.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;j<EG_SEQ_RAM_SIZE; j++)
pBuf[j] = *pSeqData;
pEg->Control = (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;j<EG_SEQ_RAM_SIZE; j++)
*pSeqData = pBuf[j];
pEg->Control = (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(;j<EG_SEQ_RAM_SIZE; j++)
TestRamBuf[j] = EG_SEQ_RAM_EVENT_NULL;
if (EgWriteSeqRam(pParm, channel, TestRamBuf) < 0)
{
printf("setup failed\n");
return(-1);
}
return(0);
}
STATIC void SeqConfigMenu(void)
{
printf("c - clear sequence ram\n");
printf("p - print sequence ram\n");
printf("s - setup sequence ram\n");
printf("m0 - set mode to off\n");
printf("m1 - set mode to normal\n");
printf("m2 - set mode to normal-recycle\n");
printf("m3 - set mode to single\n");
printf("m4 - set mode to alternate\n");
printf("t - manual triger seq ram\n");
printf("q - quit and return to main menu\n");
printf("z - dump control and event mask regs\n");
return;
}
STATIC void PrintSeq(EgLinkStruct *pParm, int channel)
{
int j;
if (EgReadSeqRam(pParm, channel, TestRamBuf) < 0)
{
printf("Sequence ram %d is currently enabled, can not read\n");
return;
}
printf("Sequence ram %d contents:\n", channel);
for(j=0; j< 1000 /* BUG EG_SEQ_RAM_SIZE*/; j++)
{
if(TestRamBuf[j] != EG_SEQ_RAM_EVENT_NULL)
printf("%5d: %3d\n", j, TestRamBuf[j]);
}
printf("End of sequence ram dump\n");
return;
}
STATIC int ConfigSeq(EgLinkStruct *pParm, int channel)
{
volatile ApsEgStruct *pEg = pParm->pEg;
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 */