From 5c7fae961749ec3c1fa8c0f73efcb77f84df0ea8 Mon Sep 17 00:00:00 2001 From: Jim Kowalkowski Date: Wed, 16 Sep 1992 16:15:40 +0000 Subject: [PATCH] Initial revision --- src/dev/devVxiTDM.c | 503 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 503 insertions(+) create mode 100644 src/dev/devVxiTDM.c diff --git a/src/dev/devVxiTDM.c b/src/dev/devVxiTDM.c new file mode 100644 index 000000000..953d35826 --- /dev/null +++ b/src/dev/devVxiTDM.c @@ -0,0 +1,503 @@ +/* devVxiTDM.c */ +/* share/src/dev $Id$ */ + +/* Device Support Routines for Custom Vxi Time Delay Module */ +/* + * Author: Jim Kowalkowski + * Date: 8/20/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 08-20-92 jbk Initial Implementation + * ... + */ + + +/* Since this is a custom module, there is no user manual. The + information supplied here summorizing the usage. + + Simplified diagram of board: + + input 1 ---->| + | (delay module section) + input 2 ---->| + |---->4:1Mux---->8-bit digital delay line--->gate--+---> + input 3 ---->| 0-1.275us in 5ns steps | + | V + input 4 ---->| last + value + + Ten delay module sections exist for the four inputs. Each one has an + associated vxi register. So altogether there are ten of the + following registers. + + _________________________________________________________________ + bits |15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + |---------------+---+---+-------+-------------------------------| + write | unused | |TE | TS | delay setting in ns | + |---------------+---+---+-------+-------------------------------| + read | unused |TD |TE | TS | delay setting in ns | + +---------------+---+---+-------+-------------------------------+ + + where TE = trigger enable/disable + TS = trigger select (input 1-4) + TD = trigger detect (trigger detected/not detected) + + */ + +#include +#include +#include +#include +#include +#include +#include <68k/iv.h> +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Create the dsets for devVxiTDM */ + +long report(); +long init(); +long init_pd(); +long get_ioint_info(); +long write_pd(); + +typedef struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN write; +} TDM_DSET; + +/*It doesnt matter who honors report or init thus let 1st devSup do it*/ + +TDM_DSET devPdVxiTDM = { 5, report, init, init_pd, NULL, write_pd }; + +volatile int VxiTDMDebug=0; + +#define Debug(f,v) { if(VxiTDMDebug) printf(f,v); } + +/* definitions related to fields of records*/ +/* defs for gtyp and ctyp fields */ + +#define INTERNAL 0 +#define EXTERNAL 1 +#define SOFTWARE 1 +#define ACTIVE 1 +#define INACTIVE 0 + +/* Trigger Source Selection - all macros require short for reg */ +#define TRGS_CLEAR(reg) (reg&0xfcff) +#define TRGS_SET(trgs,reg) (TRGS_CLEAR(reg)|trgs<<8) +#define TRGS_VALUE(reg) ((reg&0x0300)>>8) + +#define TRGS1 0x0000 +#define TRGS2 0x0100 +#define TRGS3 0x0200 +#define TRGS4 0x0300 + +/* vxi register offsets */ +#define ID_REG_OFFSET 0x0000 +#define DEV_TYPE_REG_OFFSET 0x0002 +#define STAT_CTRL_REG_OFFSET 0x0004 +#define OFFSET_REG_OFFSET 0x0006 + +#define TRIG_ENABLE(reg) (reg|0x0400) +#define TRIG_DISABLE(reg) (reg&(~0x400)) +#define TRIG_VALUE(reg) (reg&0x0400) + +#define DELAY_CLEAR(reg) (reg&0xff00) +#define DELAY_SET(delay,reg) (DELAY_CLEAR(reg)|delay) +#define DELAY_VALUE(reg) (reg&0x00ff) + +#define TRIG_DETECT(reg) (0x0800®) + +#define VXI_BASE 0xc000 +#define CARD_SIZE 0x0040 +#define REG_OFFSET 0x0020 +#define MAXCARDS 31 +#define MAXSIG 9 +#define MAX_NANOSEC 1275e1 +#define MAX_DELAY 255e1 +#define TIME_FACT MAX_DELAY/MAX_NANOSEC +#define TIME_FACT_TO MAX_NANOSEC/MAX_DELAY + +#define CARD(la) (char *)shortaddr+CARD_SIZE*la +#define SIGNAL(la,signal) CARD(la)+REG_OFFSET+signal*2 + +#define VXI_MAKE_TDM 0xf00 +#define VXI_MODEL_TDM 0xf00 + +static unsigned long tdmDriverID; + +/* for stat-> bit per channel 1=used/valid, 0=unused/invalid, bit-0=channel-0 */ + +struct tdm_config { + FAST_LOCK lock; + unsigned short stat; + }; + +/* time unit conversion constants - want in nanoseconds + seconds,milliseconds,microseconds,nanoseconds,picoseconds */ + +static double cons[] = { + 1e9,1e6,1e3,1,1e-3 }; + +void tdmInitLA(); +void tdm_stat(); +void tdm_report(); + + + +static long report(int interest) +{ +unsigned short la,signal; +struct vxi_csr *pcsr; +struct tdm_config *tc; +epvxiDeviceSearchPattern dsp; + + printf("Report for Vxi Time Delay Module\n"); + + dsp.flags=VXI_DSP_make|VXI_DSP_model; + dsp.make=VXI_MAKE_TDM; + dsp.model=VXI_MODEL_TDM; + + if( epvxiLookupLA(&dsp,tdm_report,(void *)&interest)<0 ) + return ERROR; + +} + +static void tdm_report(unsigned la,void *interest) +{ + tdm_stat(la,(int)*(int *)interest); +} + +static long init(int after) +{ +epvxiDeviceSearchPattern dsp; + + if(after) return(0); + + tdmDriverID=epvxiUniqueDriverID(); + + dsp.flags=VXI_DSP_make|VXI_DSP_model; + dsp.make=VXI_MAKE_TDM; + dsp.model=VXI_MODEL_TDM; + + if( epvxiLookupLA(&dsp,tdmInitLA,(void *)NULL) <0) + return ERROR; + + if(epvxiRegisterMakeName(VXI_MAKE_TDM,"ANL")<0) + logMsg("%s: unable to register MAKE\n",__FILE__); + + if(epvxiRegisterModelName(VXI_MAKE_TDM,VXI_MODEL_TDM, + "Time Delay Module")<0) + logMsg("%s: unable to register MODEL\n",__FILE__); + + return OK; + +} + +static void tdmInitLA(unsigned la) +{ +int status; +struct vxi_csr *pcsr; +struct tdm_config *tc; + + status=epvxiOpen(la,tdmDriverID,sizeof(struct tdm_config),tdm_stat); + + if(status<0) + { + logMsg("%s:Device Open Failed (stat=%d)(LA=0x%02X)\n", + __FILE__,status,la); + return; + } + + pcsr=VXIBASE(la); + tc=epvxiPConfig(la,tdmDriverID,struct tdm_config *); + + if(!tc) + { + epvxiClose(la,tdmDriverID); + return; + } + + FASTLOCKINIT(&tc->lock); + + tc->stat=0; + + return; +} + + +static long init_pd(struct pulseDelayRecord *pd) +{ +struct vxiio *pvxiio = (struct vxiio *)&(pd->out.value); +int dummy; +short la,signal; +unsigned short *channel_reg; +struct vxi_csr *pcsr; +struct tdm_config *tc; + + /* out must be an VXI_IO */ + + switch (pd->out.type) + { + case (VXI_IO): + break; + + default : + recGblRecordError(S_dev_badBus,pd, + "devVxiTDM (init_record) Illegal OUT Bus Type"); + return(S_dev_badBus); + } + + /* initialize to null indicating no address found */ + + la = pvxiio->la; + + if(isdigit(pvxiio->parm[0])) + signal=pvxiio->parm[0]-'0'; + else + { + recGblRecordError(S_dev_badSignal,pd, + "devVxiTDM (init_record) Illegal SIGNAL field"); + return(S_dev_badSignal); + } + + Debug("frame = %d \n",pvxiio->frame); + Debug("slot = %d \n",pvxiio->slot); + Debug("la = %d \n",pvxiio->la); + Debug("flag = %d \n",pvxiio->flag); + Debug("signal = %d \n",signal); + Debug("parm = (%s) \n",pvxiio->parm); + + if(la>MAXCARDS) + { + recGblRecordError(S_dev_badCard,pd, + "devVxiTDM (init_record) exceeded maximum supported cards"); + return(S_dev_badCard); + } + + if(signal>MAXSIG) + { + recGblRecordError(S_dev_badSignal,pd, + "devVxiTDM (init_record) Illegal SIGNAL field"); + return(S_dev_badSignal); + } + + /* get the address of the register for this la and signal */ + + tc=epvxiPConfig(la,tdmDriverID,struct tdm_config *); + pcsr=VXIBASE(la); + + (char *)channel_reg=(char *)pcsr+REG_OFFSET; + + Debug("channel_reg = %08.8X \n",channel_reg); + + if( tc->stat&(1<lock); + + /* check if register readable */ + if(vxMemProbe(channel_reg[signal],READ, + sizeof(unsigned short),&dummy)!=OK) + { + recGblRecordError(S_dev_badSignal,pd, + "devVxiTDM (init_record) vxMemProbe failed for signal/la"); + return(S_dev_badSignal); + } + + /* enable/disable gate */ + switch(pd->gate) + { + default: + case ACTIVE: + channel_reg[signal]=TRIG_ENABLE(channel_reg[signal]); + break; + case INACTIVE: + channel_reg[signal]=TRIG_DISABLE(channel_reg[signal]); + break; + } + + FASTUNLOCK(&tc->lock); + + tc->stat|=(1<dpvt=(void *)pd; + + return(0); +} + + +static long write_pd(struct pulseDelayRecord *pr) +{ +unsigned short *channel_reg; +unsigned short la,signal; +unsigned short delay_time,channel_value,channel_read; +struct vxiio *pvxiio; +struct vxi_csr *pcsr; +struct tdm_config *tc; + + Debug("Entering write_pd for pulseDelay\n",0); + + /* will be null if init failed */ + if(!pr->dpvt) return(S_dev_NoInit); + + pvxiio = (struct vxiio *)&(pr->out.value); + + la = pvxiio->la; + + if(isdigit(pvxiio->parm[0])) + signal=pvxiio->parm[0]-'0'; + else + { + recGblRecordError(S_dev_badSignal,pr, + "devVxiTDM (init_record) Illegal SIGNAL field"); + return(S_dev_badSignal); + } + + /* get address of register for this card and signal */ + + tc=epvxiPConfig(la,tdmDriverID,struct tdm_config *); + pcsr=VXIBASE(la); + (char *)channel_reg=(char *)pcsr+REG_OFFSET; + + Debug("Channel base address = 0x%08.8X \n",channel_reg); + Debug("Channel register address = 0x%08.8X \n",&channel_reg[signal]); + + FASTLOCK(&tc->lock); + + /* set val to active if trigger detect on and a periodic scan + caused processing, special processing will set pfld */ + + if(!pr->pfld) + { + channel_read=channel_reg[signal]; + + if(TRIG_DETECT(channel_read)) + pr->val=ACTIVE; + else + pr->val=INACTIVE; + + pr->dly=(double)DELAY_VALUE(channel_read)*TIME_FACT_TO; + pr->hts=TRGS_VALUE(channel_read); + pr->gate=TRIG_VALUE(channel_read); + + Debug("trigger detect read - value = %d\n",pr->val); + } + else + { + /* initialize new channel value */ + channel_value=0x0000; + + /* compute delay time */ + + delay_time=(unsigned short)(cons[pr->unit]*pr->dly*TIME_FACT); + + Debug("delay time = %d\n",delay_time); + Debug("units = %d \n",pr->unit); + + if(delay_time > 255) delay_time=255; + + channel_value=DELAY_SET(delay_time,channel_value); + + /* enable/disable gate */ + switch(pr->gate) + { + default: + case ACTIVE: + channel_value=TRIG_ENABLE(channel_value); + break; + case INACTIVE: + channel_value=TRIG_DISABLE(channel_value); + break; + } + + /* trigger selection set */ + if(pr->hts > 3 || pr->hts < 0) + { + recGblSetSevr(pr,WRITE_ALARM,INVALID_ALARM); + recGblRecordError(S_db_badField,pr,"invalid trigger value"); + return(0); + } + + channel_value=TRGS_SET(pr->hts,channel_value); + + /* write to register */ + channel_reg[signal]=channel_value; + } + + FASTUNLOCK(&tc->lock); + + Debug("Ending channel value = %04.4X\n",channel_value); + + return(0); + +} + +static void tdm_stat(unsigned la,int level) +{ +struct tdm_config *tc; +struct vxi_csr *pcsr; +int i; + + tc=epvxiPConfig(la,tdmDriverID,struct tdm_config *); + pcsr=VXIBASE(la); + + Debug("Report level = %d\n",level); + + printf("Report for Vxi Time Delay module %d:\n",la); + printf(" Signals in use:"); + + for(i=0;i<=MAXSIG;i++) if(tc->stat&(1<