Files
pcas/src/drv/drvComet.c
1994-06-22 15:35:59 +00:00

640 lines
16 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.
/* comet_driver.c */
/* base/src/drv $Id$ */
/*
* Author: Leo R. Dalesio
* Date: 5-92
*
* 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
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* .01 joh 071092 added argument to calloc()
* .02 joh 071092 stripped the hkv2f specific portion off the comet
* std addr base specification and left it at base
* addr zero which is most likely wrong.
* .03 joh 071492 use extended (A32) address space
* instead of standard (A24) address space
* for the base address of the waveform memory
* (changed arg to sysBusToLocalAdrs()
* .04 joh 071592 fixed to use correct size when incrementing
* to the waveform memory of the second card
* .05 joh 071592 modified A16 & A32 base addr to match AT8
* address standard
* .06 bg 071792 moved addresses to module_types.h
* .07 joh 080592 added io report routines
* .08 ms 080692 added comet_mode routine, modified comet_driver
* and cometDoneTask to allow an external routine
* to control hardware scan mode. Added variable
* scan_control to flag operating mode.
* .09 mrk 082692 added DSET
* .10 joh 082792 fixed uninitialized csr pointer in comet_driver()
* function
* .11 lrd 091692 add signal support
* .12 joh 092992 card number validation now based on module_types.h.
* signal number checking now based on the array element
* count.
* .13 mrk 080293 Added call to taskwdInsert
* .14 mgb 080493 Removed V5/V4 and EPICS_V2 conditionals
*/
static char *sccsID = "@(#)drvComet.c 1.11\t9/16/92";
/*
* Code Portions
*
* comet_init()
* comet_driver(card, pcbroutine, parg)
* cometDoneTask()
* comet_io_report()
* comet_mode(card,mode,arg,val)
*
*/
#include <vxWorks.h>
#include <iv.h>
#include <types.h>
#include <module_types.h>
#include <task_params.h>
#include <fast_lock.h>
#include <vme.h>
#include <drvSup.h>
#include <dbDefs.h>
#include <dbScan.h>
#include <taskwd.h>
#define COMET_NCHAN 4
#define COMET_CHANNEL_MEM_SIZE 0x20000 /* bytes */
#define COMET_DATA_MEM_SIZE (COMET_CHANNEL_MEM_SIZE*COMET_NCHAN)
static char *shortaddr;
static short scan_control; /* scan type/rate (if >0 normal, <=0 external control) */
/* comet conrtol register map */
struct comet_cr{
unsigned char csrh; /* control and status register - high byte */
unsigned char csrl; /* control and status register - low byte */
unsigned char lcrh; /* location status register - high byte */
unsigned char lcrl; /* location status register - low byte */
unsigned char gdcrh; /* gate duration status register - high byte*/
unsigned char gdcrl; /* gate duration status register - low byte */
unsigned char cdr; /* channel delay register */
unsigned char acr; /* auxiliary control register */
char pad[0x100-8];
};
/* defines for the control status register - high byte */
#define DIGITIZER_ACTIVE 0x80 /* 1- Active */
#define ARM_DIGITIZER 0x40 /* 1- Arm the digitizer */
#define CIRC_BUFFER_ENABLED 0x20 /* 0- Stop when memory is full */
#define WRAP_MODE_ENABLED 0x10 /* 0- Disable wrap around */
#define AUTO_RESET_LOC_CNT 0x08 /* 1- Reset addr to 0 on trigger */
#define EXTERNAL_TRIG_ENABLED 0x04 /* 1- use external clk to trigger */
#define EXTERNAL_GATE_ENABLED 0x02 /* 0- use pulse start conversion */
#define EXTERNAL_CLK_ENABLED 0x01 /* 0- uses the internal clock */
/* commands for the COMET digitizer */
#define COMET_INIT_CSRH
#define COMET_INIT_READ
/* mode commands for the COMET digitizer */
#define READREG 0
#define WRITEREG 1
#define SCANCONTROL 2
#define SCANSENSE 3
#define SCANDONE 4
/* register selects */
#define COMET_CSR 0
#define COMET_LCR 1
#define COMET_GDCR 2
#define COMET_CDACR 3
/* defines for the control status register - low byte */
#define SOFTWARE_TRIGGER 0x80 /* 1- generates a software trigger */
#define UNUSED 0x60
#define CHAN_DELAY_ENABLE 0x10 /* 0- digitize on trigger */
#define DIG_RATE_SELECT 0x0f
/* digitizer rates - not defined but available for 250KHz to 122Hz */
#define COMET_5MHZ 0x0000
#define COMET_2MHZ 0x0001
#define COMET_1MHZ 0x0002
#define COMET_500KHZ 0x0003
/* defines for the auxiliary control register */
#define ONE_SHOT 0x10
#define ALL_CHANNEL_MODE 0x80
/* comet configuration data */
struct comet_config{
struct comet_cr *pcomet_csr; /* pointer to the control/status register */
unsigned short *pdata; /* pointer to data area for this COMET card */
void (*psub)(); /* subroutine to call on end of conversion */
void *parg[4]; /* argument to return to the arming routine */
FAST_LOCK lock; /* mutual exclusion lock */
IOSCANPVT ioscanpvt;
unsigned long nelements; /* number of elements to digitize/read */
};
/* task ID for the comet done task */
int cometDoneTaskId;
struct comet_config *pcomet_config;
static long report();
static long init();
struct {
long number;
DRVSUPFUN report;
DRVSUPFUN init;
} drvComet={
2,
report,
init};
/*
* cometDoneTask
*
* wait for comet waveform record cycle complete
* and call back to the database with the waveform size and address
*
*/
void
cometDoneTask()
{
register unsigned card;
register struct comet_config *pconfig;
register long i;
while(TRUE)
{
if (scan_control <= 0)
taskDelay(2);
else
{
taskDelay(scan_control);
/* printf("DoneTask: entering for loop...\n"); */
/* check each card for end of conversion */
for(card=0, pconfig = pcomet_config; card < 2;card++, pconfig++)
{
/* is the card present */
if (!pconfig->pcomet_csr)
{
if (card == 0)
{
/*
printf("DoneTask: checking card present?...\n");
printf("DoneTask: pconfig->pcomet_csr %x...\n",pconfig->pcomet_csr);
*/
}
continue;
}
/* is the card armed */
if (!pconfig->psub)
{
if (card == 0)
{
/* printf("DoneTask: checking card armed?...\n"); */
}
continue;
}
/* is the digitizer finished conversion */
/* printf("pconfig->pdata: %x \n", pconfig->pdata); */
if (*(pconfig->pdata+pconfig->nelements) == 0xffff)
{
if (card == 0)
{
/* printf("DoneTask: finished conversion?...\n"); */
}
continue;
}
/* printf("DoneTask: pcomet_config->pcomet_csr %x...\n",pcomet_config->pcomet_csr); */
/* printf("DoneTask: DONE\n"); */
#if 0
/* reset each of the control registers */
pconfig->pcomet_csr->csrh = pconfig->pcomet_csr->csrl = 0;
pconfig->pcomet_csr->lcrh = pconfig->pcomet_csr->lcrl = 0;
pconfig->pcomet_csr->gdcrh = pconfig->pcomet_csr->gdcrl = 0;
pconfig->pcomet_csr->acr = 0;
#endif
/* clear the pointer to the subroutine to allow rearming */
/* pconfig->psub = NULL; */
/* post the event */
/* - is there a bus error for long references to this card?? copy into VME mem? */
if(pconfig->parg[0])
{
(*pconfig->psub)(pconfig->parg[0],pconfig->pdata);
}
if(pconfig->parg[1])
{
(*pconfig->psub)(pconfig->parg[1],(((char*)pconfig->pdata)+0x20000));
}
if(pconfig->parg[2])
{
(*pconfig->psub)(pconfig->parg[2],(((char*)pconfig->pdata)+0x40000));
}
if(pconfig->parg[3])
{
(*pconfig->psub)(pconfig->parg[3],(((char*)pconfig->pdata)+0x60000));
}
}
}
}
}
/*
* COMET_INIT
*
* intialize the driver for the COMET digitizer from omnibyte
*
*/
comet_init()
{
register struct comet_config *pconfig;
short readback,got_one,card;
int status;
struct comet_cr *pcomet_cr;
unsigned char *extaddr;
/* free memory and delete tasks from previous initialization */
if (cometDoneTaskId)
{
taskwdRemove(cometDoneTaskId);
if ((status = taskDelete(cometDoneTaskId)) < 0)
logMsg("\nCOMET: Failed to delete cometDoneTask: %d",status);
}
else
{
pcomet_config = (struct comet_config *)calloc(wf_num_cards[COMET],sizeof(struct comet_config));
if (pcomet_config == 0)
{
logMsg("\nCOMET: Couldn't allocate memory for the configuration data");
return;
}
}
/* get the standard and short address locations */
if ((status = sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO,wf_addrs[COMET],&pcomet_cr)) != OK){
logMsg("\nCOMET: failed to map VME A16 base address\n");
return;
}
if ((status = sysBusToLocalAdrs(VME_AM_EXT_SUP_DATA,wf_memaddrs[COMET],&extaddr)) != OK){
logMsg("\nCOMET: failed to map VME A32 base address\n");
return;
}
/* determine which cards are present */
got_one = FALSE;
pconfig = pcomet_config;
for ( card = 0;
card < 2;
card++, pconfig++, pcomet_cr++, extaddr+= COMET_DATA_MEM_SIZE){
/* is the card present */
if (vxMemProbe(pcomet_cr,READ,sizeof(readback),&readback) != OK)
{
continue;
}
if (vxMemProbe(extaddr,READ,sizeof(readback),&readback) != OK)
{
logMsg("\nCOMET: Found CSR but not data RAM %x\n",extaddr);
continue;
}
/* initialize the configuration data */
pconfig->pcomet_csr = pcomet_cr;
pconfig->pdata = (unsigned short *) extaddr;
got_one = TRUE;
FASTLOCKINIT(&pcomet_config[card].lock);
/* initialize the card */
pcomet_cr->csrh = ARM_DIGITIZER | AUTO_RESET_LOC_CNT;
pcomet_cr->csrl = COMET_1MHZ;
pcomet_cr->lcrh = pcomet_cr->lcrl = 0;
pcomet_cr->gdcrh = 0;
pcomet_cr->gdcrl = 1;
pcomet_cr->cdr = 0;
/* run it once */
pcomet_cr->csrl |= SOFTWARE_TRIGGER;
taskDelay(1);
/* reset */
pcomet_cr->csrl = COMET_5MHZ;
pcomet_cr->acr = ONE_SHOT | ALL_CHANNEL_MODE;
scanIoInit(&pconfig->ioscanpvt);
} /*end of for loop*/
/* initialization for processing comet digitizers */
if(got_one)
{
/* start the waveform readback task */
scan_control = 2; /* scan rate in vxWorks clock ticks */
cometDoneTaskId = taskSpawn("cometWFTask",WFDONE_PRI,WFDONE_OPT,WFDONE_STACK,(FUNCPTR) cometDoneTask);
taskwdInsert(cometDoneTaskId,NULL,NULL);
}
}
static long report(level)
int level;
{
comet_io_report(level);
return(0);
}
static long init()
{
comet_init();
return(0);
}
/*
* COMET_DRIVER
*
* initiate waveform read
*
*/
comet_driver(card, signal, pcbroutine, parg, nelements)
register short card;
register unsigned short signal;
unsigned int *pcbroutine;
unsigned int *parg; /* pointer to the waveform record */
unsigned long nelements;
{
register struct comet_cr *pcomet_csr;
register struct comet_config *pconfig;
register unsigned short *pcomet_data;
register char *dummy;
/* printf("comet_driver: BEGIN...\n"); */
/* printf("comet_driver: nelements: %d ...\n",nelements); */
/* check for valid card number */
if(card >= wf_num_cards[COMET])
return ERROR;
pconfig = (pcomet_config+card);
if(signal >= NELEMENTS(pconfig->parg))
return ERROR;
pconfig->nelements = nelements * 2;
/* printf("comet_driver: check for card present...\n"); */
/* check for card present */
if(!pconfig->pcomet_csr) return ERROR;
/* mutual exclusion area */
FASTLOCK(&pconfig->lock);
/* printf("comet_driver: mark the card as armed...\n"); */
/* mark the card as armed */
/* if (pconfig->parg[signal] != 0) */
pconfig->parg[signal] = parg;
/* if (pconfig->psub) return; */
pconfig->psub = (void (*)()) pcbroutine;
/* exit mutual exclusion area */
FASTUNLOCK(&pconfig->lock);
pcomet_csr = pconfig->pcomet_csr;
/* reset each of the control registers */
pcomet_csr->csrh = pcomet_csr->csrl = 0;
pcomet_csr->lcrh = pcomet_csr->lcrl = 0;
pcomet_csr->gdcrh = pcomet_csr->gdcrl = 0;
pcomet_csr->acr = 0;
/* arm the card */
*(pconfig->pdata+pconfig->nelements) = 0xffff;
/* printf("comet_driver: pconfig->pcomet_csr %x...\n",pconfig->pcomet_csr); */
if (scan_control > 0)
{
#if 0 /* for debugging purposes */
pcomet_csr->gdcrh = 0x03; /* # samples per channel */
pcomet_csr->gdcrl = 0xe8; /* # samples per channel */
#endif
pcomet_csr->gdcrh = (pconfig->nelements >> 8) & 0xff; /* # samples per channel */
pcomet_csr->gdcrl = pconfig->nelements & 0xff; /* # samples per channel */
pcomet_csr->acr = ONE_SHOT | ALL_CHANNEL_MODE; /* disarm after the trigger */
pcomet_csr->csrl = COMET_5MHZ; /* sample at 5MhZ */
/* arm, reset location counter to 0 on trigger, use external trigger */
pcomet_csr->csrh = ARM_DIGITIZER | AUTO_RESET_LOC_CNT | EXTERNAL_TRIG_ENABLED;
/* printf("comet_driver: gdcrh: %x gdcrl: %x nelements: %x\n ",pcomet_csr->gdcrh,pcomet_csr->gdcrl, pconfig->nelements); */
}
else
pcomet_csr->csrh |= ARM_DIGITIZER;
/* printf("comet_driver: pconfig->pcomet_csr %x...\n",pconfig->pcomet_csr); */
/* printf("comet_driver: END...\n"); */
return OK;
}
/*
* COMET_IO_REPORT
*
* print status for all cards in the specified COMET address range
*/
comet_io_report(level)
short int level;
{
struct comet_config *pconfig;
unsigned card;
unsigned nelements;
int status;
pconfig = pcomet_config;
for(card=0; card < wf_num_cards[COMET]; card++){
if(!pconfig->pcomet_csr)
continue;
printf( "WF: COMET:\tcard=%d\n", card);
if (level >= 2){
printf("enter the number of elements to dump:");
status = scanf("%d",&nelements);
if(status == 1){
comet_dump(card, nelements);
}
}
pconfig++;
}
return OK;
}
/*
* comet_dump
*
*/
int comet_dump(card, n)
unsigned card;
unsigned n;
{
unsigned short *pdata;
unsigned short *psave;
unsigned short *pbegin;
unsigned short *pend;
if (card >= wf_num_cards[COMET])
return ERROR;
pdata = pcomet_config[card].pdata;
psave = (unsigned short *) malloc(n * sizeof(*psave));
if(!psave){
return ERROR;
}
pbegin = psave;
pend = &psave[n];
for( pdata = pcomet_config[card].pdata;
psave<pend;
pdata++,psave++){
*psave = *pdata;
}
psave = pbegin;
for( ;
psave<pend;
psave++){
if((psave-pbegin)%8 == 0){
printf("\n\t");
}
printf("%04X ", *psave);
}
printf("\n");
free(pbegin);
return OK;
}
/*
* comet_mode
*
* controls and reports operating mode
*
*/
comet_mode(card,mode,arg,val)
short card;
unsigned short mode, arg, val;
{
unsigned char *cptr;
int i;
if (card >= wf_num_cards[COMET])
return ERROR;
if (!pcomet_config[card].pcomet_csr)
return ERROR;
switch (mode)
{
case READREG:
/*cptr = (unsigned char *)pcomet_config[card].pcomet_csr;
for (i = 0; i < 6; i++, cptr++)
printf("%x %x\n",cptr,*cptr);*/
cptr = (unsigned char *)pcomet_config[card].pcomet_csr; /* point to offset 0 */
cptr += arg<<1; /* build new offset */
val = (*cptr++)<<8; /* read value and return */
val |= *cptr;
return val;
break;
case WRITEREG:
cptr = (unsigned char *)pcomet_config[card].pcomet_csr;
cptr += arg<<1;
*cptr++ = val>>8;
*cptr = val;
break;
case SCANCONTROL:
scan_control = val;
break;
case SCANSENSE:
return scan_control;
break;
case SCANDONE:
if (!pcomet_config[card].psub)
return ERROR;
/*pcomet_config[card].psub = NULL;*/ /* clear the pointer to subroutine to allow rearming */
(*pcomet_config[card].psub)(pcomet_config[card].parg,0xffff,pcomet_config[card].pdata);
break;
default:
return ERROR;
}
return OK;
}
/*********************************************/
cometGetioscanpvt(card,scanpvt)
short card;
IOSCANPVT *scanpvt;
{
register struct comet_config *pconfig;
pconfig=pcomet_config;
pconfig+=card;
if ((card >= wf_num_cards[COMET]) || (card < 0)) /* make sure hardware exists */
return(0);
/*
This is present in the mix driver...I don't know if I really need it.
if (!pconfig->present)
return(0);
*/
*scanpvt = pconfig->ioscanpvt;
return(0);
}