diff --git a/src/drv/drvCaenV265.c b/src/drv/drvCaenV265.c new file mode 100644 index 000000000..ed42f1f3b --- /dev/null +++ b/src/drv/drvCaenV265.c @@ -0,0 +1,807 @@ +/* share/src/drv @(#)drvCaenV265.c 1.1 9/2/94 */ +/* drvCaenV265.c - Driver/Device Support Routines for CAEN V265 + * + * Author: Jeff Hill (johill@lanl.gov) + * Date: 8-11-94 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * MIT Bates Lab + * + * Modification Log: + * ----------------- + */ + +/* + * ANSI C Includes + */ +#include +#include +#include +#include + +/* + * vxWorks includes + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * EPICS include + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * base address, base interrupt vector, + * number of cards, & interrupt level + */ +#define CAIN_V265_A24_BASE (0x000000) +#define CAIN_V265_INTVEC_BASE (0xA0) +#define CAIN_V265_MAX_CARD_COUNT (8) +#define CAIN_V265_INT_LEVEL (6) + + + + +/* + * all device registers declared + * ANSI C volatile so we dont need to + * use the -fvolatile flag (and dont + * limit the optimizer) + */ +typedef volatile int16_t devReg; + +struct caenV265 { + devReg csr; + devReg clear; + devReg DAC; + devReg gate; + const devReg data; + const devReg pad1[(0xf8-0x8)/2]; + const devReg fixed; + const devReg identifier; + const devReg version; +}; +#define CAENV265ID 0x0812 + +/* + * Insert or extract a bit field using the standard + * masks and shifts defined below + */ +#ifdef __STDC__ +#define INSERT(FIELD,VALUE)\ + (((VALUE)&(FD_ ## FIELD ## _M))<<(FD_ ## FIELD ## _S)) +#define EXTRACT(FIELD,VALUE)\ + ( ((VALUE)>>(FD_ ## FIELD ## _S)) &(FD_ ## FIELD ## _M)) +#else /*__STDC__*/ +#define INSERT(FIELD,VALUE)\ + (((VALUE)&(FD_/* */FIELD/* */_M))<<(FD_/* */FIELD/* */_S)) +#define EXTRACT(FIELD,VALUE)\ + ( ((VALUE)>>(FD_/* */FIELD/* */_S)) &(FD_/* */FIELD/* */_M)) +#endif /*__STDC__*/ + +/* + * in the constants below _M is a right justified mask + * and _S is a shift required to right justify the field + */ + +/* + * csr register + */ +#define FD_FULL_M (0x1) +#define FD_FULL_S (14) +#define FD_READY_M (0x1) +#define FD_READY_S (15) +#define FD_BUSY_FULL_M (0x3) +#define FD_BUSY_FULL_S (14) +#define FD_IVEC_M (0xff) +#define FD_IVEC_S (0) +#define FD_ILEVEL_M (0x7) +#define FD_ILEVEL_S (8) + +/* + * series/version register + */ +#define FD_SERIES_M (0xfff) +#define FD_SERIES_S (0) +#define FD_VERSION_M (0xf) +#define FD_VERSION_S (12) + +/* + * data register + */ +#define FD_CHANNEL_M (0x7) +#define FD_CHANNEL_S (13) +#define FD_RANGE_M (1) +#define FD_RANGE_S (12) +#define FD_DATA_M (0xfff) +#define FD_DATA_S (0) + +struct channel{ + int16_t signal; + char newData; +}; + +enum adc_range {adc_12, adc_15, NUMBER_OF_ADC_RANGES}; +#define NUMBER_OF_SIGNALS 8 +#define NUMBER_OF_FIFO_ENTRIES (16*NUMBER_OF_SIGNALS*NUMBER_OF_ADC_RANGES) +LOCAL struct caenV265Config{ + struct caenV265 *pCaenV265; /* pointer to the card */ + struct channel chan[NUMBER_OF_SIGNALS][NUMBER_OF_ADC_RANGES]; + IOSCANPVT scanpvt; + WDOG_ID wdid; +}caenV265Info[CAIN_V265_MAX_CARD_COUNT]; + +#ifdef __STDC__ +#define SHOW_OFFSET(STRUCT,FIELD) \ +printf( "%s.%s is at 0x%X\n", \ + #STRUCT, \ + #FIELD, \ + offsetof(struct STRUCT, FIELD)) +#endif + +LOCAL void caenV265ISR(unsigned card); +LOCAL int caenV265Shutdown(void); +LOCAL int caenV265IdTest(struct caenV265 *pCaenV265); +int caenV265Test(unsigned card); +LOCAL void caenV265ReadData(struct caenV265Config *pCaenV256Config); +LOCAL int caenV265TestVal(unsigned card, unsigned dacVal); +LOCAL int caenV265IntEnable(unsigned card); + +/* + * device support entry table + */ +LOCAL long caenV265InitRecord(struct aiRecord *pai); +LOCAL long caenV265AiRead(struct aiRecord *pai); +LOCAL long caenV265SpecialLinconv(struct aiRecord *pai, int after); +LOCAL long caenV265GetIoIntInfo(int cmd, struct aiRecord *pai, IOSCANPVT *ppvt); +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_ai; + DEVSUPFUN special_linconv; +} devCaenV265 ={ + 6, + NULL, + NULL, + caenV265InitRecord, + caenV265GetIoIntInfo, + caenV265AiRead, + caenV265SpecialLinconv}; + +/* + * driver support entry table + */ +LOCAL long caenV265Init(void); +LOCAL long caenV265IOReport(int level); +struct { + long number; + DRVSUPFUN report; + DRVSUPFUN init; +} drvCaenV265 ={ + 2, + caenV265IOReport, + caenV265Init}; + + + +/* + * verify that register + * offsets match the doc. + */ +#ifdef DEBUG +void offsettest() +{ + SHOW_OFFSET(caenV265, version); + SHOW_OFFSET(caenV265, identifier); + SHOW_OFFSET(caenV265, fixed); + SHOW_OFFSET(caenV265, data); + SHOW_OFFSET(caenV265, gate); + SHOW_OFFSET(caenV265, DAC); + SHOW_OFFSET(caenV265, clear); + SHOW_OFFSET(caenV265, csr); + + return; +} +#endif + + +/* + * caenV265InitRecord() + */ +LOCAL long caenV265InitRecord(struct aiRecord *pai) +{ + struct vmeio *pvmeio; + + /* ai.inp must be an VME_IO */ + switch (pai->inp.type) { + case (VME_IO): + break; + default : + recGblRecordError(S_db_badField,(void *)pai, + "devAiXy566Se (init_record) Illegal INP field"); + return(S_db_badField); + } + + pvmeio = (struct vmeio *)&(pai->inp.value); + + /* + * check for bad signal or card number + */ + if ( pvmeio->signal >= NUMBER_OF_SIGNALS || + pvmeio->card >= CAIN_V265_MAX_CARD_COUNT ) { + + recGblRecordError( + S_db_badField, + (void *)pai, + "devCaenV265 bad card or signal number"); + return -1; + } + + if(!caenV265Info[pvmeio->card].pCaenV265){ + recGblRecordError( + S_db_badField, + (void *)pai, + "devCaenV265 card does not exist"); + return -1; + } + + /* set linear conversion slope*/ + pai->eslo = (pai->eguf-pai->egul)/FD_DATA_M; + + return(0); +} + + +/* + * caenV265AiRead() + */ +LOCAL long caenV265AiRead(struct aiRecord *pai) +{ + int16_t value; + struct vmeio *pvmeio; + + pvmeio = (struct vmeio *)&(pai->inp.value); + + /* + * check for bad signal or card number + */ + if ( pvmeio->signal >= NUMBER_OF_SIGNALS || + pvmeio->card >= CAIN_V265_MAX_CARD_COUNT ) { + + recGblSetSevr(pai, READ_ALARM, INVALID_ALARM); + return -1; + } + + /* + * uninitialized data? + */ + if (!caenV265Info[pvmeio->card].chan[pvmeio->signal][adc_12].newData) { + recGblSetSevr(pai, READ_ALARM, INVALID_ALARM); + return -1; + } + + value = caenV265Info[pvmeio->card].chan[pvmeio->signal][adc_12].signal; + pai->rval = value; + + return 0; +} + + +/* + * caenV265SpecialLinconv() + */ +LOCAL long caenV265SpecialLinconv(struct aiRecord *pai, int after) +{ + if(!after) { + return 0; + } + + /* set linear conversion slope*/ + pai->eslo = (pai->eguf-pai->egul)/FD_DATA_M; + return 0; +} + + +/* + * caenV265GetIoIntInfo() + */ +LOCAL long caenV265GetIoIntInfo( +int cmd, +struct aiRecord *pai, +IOSCANPVT *ppvt) +{ + struct vmeio *pvmeio; + + pvmeio = (struct vmeio *)&(pai->inp.value); + + /* + * check for bad card number + */ + if ( pvmeio->card >= CAIN_V265_MAX_CARD_COUNT ) { + logMsg( + "%s.%d:devCaenV265 bad card number %d %s\n", + (int)__FILE__, + __LINE__, + pvmeio->card, + (int)pai->name,0,0); + recGblRecordError( + S_db_badField, + (void *)pai, + "devCaenV265 bad card number"); + return -1; + } + + *ppvt = &caenV265Info[pvmeio->card].scanpvt; + + return 0; +} + + +/* + * caenV265Init() + */ +LOCAL long caenV265Init(void) +{ + unsigned card; + struct caenV265 *pCaenV265; + int status; + + status = rebootHookAdd(caenV265Shutdown); + if(status){ + errMessage(S_dev_internal,"reboot hook add failed"); + return ERROR; + } + + status = sysBusToLocalAdrs( + VME_AM_STD_SUP_DATA, + CAIN_V265_A24_BASE, + (char **)&pCaenV265); + if(status!=OK){ + errPrintf( + S_dev_badA24, + __FILE__, + __LINE__, + "caenV265Init"); + return ERROR; + } + + for(card=0; cardclear = 0; /* any rw op resets the device */ + pCaenV265->DAC = 0; /* set test-signal "offset" to zero */ + + /* + * attach ISR + */ + vec = CAIN_V265_INTVEC_BASE+card; + status = intConnect( + INUM_TO_IVEC(vec), + caenV265ISR, + card); + assert(status>=0); + + /* + * Enable interrupts + */ + caenV265IntEnable(card); + } + status = sysIntEnable(CAIN_V265_INT_LEVEL); + assert(status>=0); + + return OK; +} + + +/* + * caenV265ISR() + */ +LOCAL void caenV265ISR(unsigned card) +{ + struct caenV265Config *pCaenV256Config = &caenV265Info[card]; + struct caenV265 *pCaenV265 = pCaenV256Config->pCaenV265; + unsigned signal; + int16_t csr; + static unsigned ticks; + unsigned newTicks; + + /* + * If its full then its more efficient + * to read it out without checking + * in between each read + */ + csr = pCaenV265->csr; + if (EXTRACT(FULL,csr)) { + for( signal=0; + signalcsr; + } + + /* + * limit the EPICS scan rate + */ + newTicks = tickGet(); + if(newTicks == ticks){ + /* + * Disable Interrupts + */ + pCaenV265->csr = 0; + + /* + * start a watch dog after one tick + * so that we limit the int rate to + * the system tick rate. + */ + wdStart(pCaenV256Config->wdid, + 1, + caenV265IntEnable, + card); + + return; + } + else{ + ticks = newTicks; + } + + /* + * tell EPICS to scan on int + */ + scanIoRequest(&caenV265Info[card].scanpvt); + + return; +} + + +/* + * caenV265IntEnable + */ +LOCAL int caenV265IntEnable(unsigned card) +{ + struct caenV265Config *pCaenV256Config = &caenV265Info[card]; + struct caenV265 *pCaenV265 = pCaenV256Config->pCaenV265; + unsigned vec; + int16_t newcsr; + + + vec = CAIN_V265_INTVEC_BASE+card; + newcsr = INSERT(IVEC, vec) | INSERT(ILEVEL, CAIN_V265_INT_LEVEL); + pCaenV265->csr = newcsr; + + return OK; +} + + +/* + * caenV265ReadData() + */ +LOCAL void caenV265ReadData(struct caenV265Config *pCaenV256Config) +{ + struct caenV265 *pCaenV265 = pCaenV256Config->pCaenV265; + int16_t val = pCaenV265->data; + int16_t data = EXTRACT(DATA, val); + unsigned range = EXTRACT(RANGE, val); + unsigned signal = EXTRACT(CHANNEL, val); + + if(range>=NUMBER_OF_ADC_RANGES){ + logMsg("caenV265ReadData: bad range number\n",0,0,0,0,0,0); + return; + } + if(signal>=NUMBER_OF_SIGNALS){ + logMsg("caenV265ReadData: bad signal number\n",0,0,0,0,0,0); + return; + } + pCaenV256Config->chan[signal][range].signal=data; + pCaenV256Config->chan[signal][range].newData=TRUE; + + return; +} + + +/* + * caenV265IdTest() + */ +LOCAL int caenV265IdTest(struct caenV265 *pCaenV265) +{ + int status; + int16_t id; + + /* + * Is a card present + */ + status = vxMemProbe( + (char *)&pCaenV265->identifier, + READ, + sizeof(id), + (char *)&id); + if(status!=OK){ + return FALSE; + } + + /* + * Is the correct type of card present + */ + if(id!=CAENV265ID){ + errPrintf( + S_dev_wrongDevice, + __FILE__, + __LINE__, + "caenV265IdTest"); + return FALSE; + } + return TRUE; +} + + +/* + * caenV265Shutdown() + * turns off interrupts so that dont foul up the boot + */ +LOCAL int caenV265Shutdown(void) +{ + struct caenV265 *pCaenV265; + unsigned card; + + for(card=0; cardcsr=0; + } + } + return OK; +} + + +/* + * caenV265Test() + */ +int caenV265Test(unsigned card) +{ + unsigned dacVal; + struct caenV265Config cofigCpy; + unsigned range; + unsigned signal; + + + dacVal=0; + caenV265TestVal(card, dacVal); + while(dacValpCaenV265; + unsigned signal; + + if(!pCaenV265){ + return ERROR; + } + + if(!caenV265IdTest(pCaenV265)){ + return ERROR; + } + + /* + * clear the module + */ + pCaenV265->clear=0; + + /* + * generate a test signal + */ + pCaenV265->DAC=dacVal; + + /* + * generate a test gate + */ + for( signal=0; + signalgate=0; + taskDelay(1); + } + while(!caenV265Info[card].chan[signal][adc_12].newData){ + pCaenV265->gate=0; + taskDelay(1); + } + } + + /* + * turn off test signal + */ + pCaenV265->clear=0; + pCaenV265->DAC=0; + + return OK; +} + + +/* + * caenV265IOReport() + */ +LOCAL long caenV265IOReport(int level) +{ + struct caenV265 *pCaenV265; + unsigned card; + unsigned signal; + unsigned range; + char *pVersion[] = {"NIM","ECL"}; + char *pState[] = { + "FIFO empty", + "FIFO full", + "FIFO partially filled", + "FIFO full"}; + + for (card=0; cardversion)]); + printf("\tseries = %d\n", + EXTRACT(SERIES, pCaenV265->version)); + printf("\tstate = %s\n", + pState[EXTRACT(BUSY_FULL,pCaenV265->csr)]); + printf("\tint level = %d\n", + EXTRACT(ILEVEL,pCaenV265->csr)); + printf("\tint vec = 0x%02X\n", + EXTRACT(IVEC,pCaenV265->csr)); + printf( "\tbase addr= 0x%X on the %s\n", + (unsigned)caenV265Info[card].pCaenV265, + sysModel()); + + for( range=0; + range\n", + signal); + } + } + + } + } + return OK; +}