#include #include #include #include #include #include #include "dasutil.h" #include "acqdef.h" #include "ppccApSem.h" #include "rtcdef.h" #include "pcs_common.h" #ifdef _SKY #include #include #include #include /* Sky Standard Math Library */ #include "fortran_printf.h" #define M_PI _PI #else #include "mathlib_simulate.h" #endif /********************************************************************** * rtc_indat.c -- * * Place digitizer data into fortran common block ... * * History: * 10-Nov-2004 TRG Handle RWM data, mostly by using NCHAN1R. Check * for SPA fault: set nhcsspa flag. * 23-Mar-2004 TRG Use waitApSem function to wait for new data from acq. * 02-Mar-2004 TRG Increase "baseline calc" timeout to 0.030 sec. * 23-Jan-2004 TRG delayUntil: add usecDelay() before checking * for newdata. * 12-Jan-2004 TRG Set rm->sopFlag and rm->eopFlag for IDL uif. * set_idl_info: new function supporting IDL uif. * 10-Nov-2003 TRG Re-calculate disd and dvmax upon new "dt". * 07-Aug-2003 TRG Remove unnceccessary "iolist count" stuff. * 30-Jul-2003 TRG Dispose of "fio" transfer for copying imeas. * We now map local "pubData" buffer, so use vmov_sp. * 28-Jul-2003 TRG Convert from doublePrecision to singlePrecision. * 30-Jun-2003 TRG Use "mapPubData_cache()", with calls to * ppc_cache_invalidate() as required. * 10-Feb-2003 TRG delayUntil: implement "timeout". * 14-Mar-2000 TRG Use pub->calBuf data, computed by acq. * 10-Jan-2000 TRG Compute VCHI in imeas[] array. * 25-Oct-1999 TRG Remove host-simulation "map" routines. They are * now in ../acq/shareMem.c. * 14-Dec-1998 TRG Create. * ***********************************************************************/ /*====================================================== * Compatibility definitions for Fortran, etc. ... *=====================================================*/ #define nstx_pcs_collect_integer FORTRAN_COMMON(nstx_pcs_collect_integer) #define nstx_pcs_collect_real FORTRAN_COMMON(nstx_pcs_collect_real) #define nstx_pcs_gen FORTRAN_COMMON(nstx_pcs_gen) /*====================================================== * Globally defined variables ... *=====================================================*/ float nstxTime; struct pubData *pub; /*====================================================== * Externally defined variables ... *=====================================================*/ #ifdef _SKY extern struct nstx_pcs_gen *Tnstx_pcs_gen; #endif extern struct nstx_pcs_collect_integer nstx_pcs_collect_integer; extern struct nstx_pcs_collect_real nstx_pcs_collect_real; extern struct nstx_pcs_gen nstx_pcs_gen; /* fortran common block */ /*====================================================== * Local variables ... *=====================================================*/ #define COMPARE_BASELINES_MAXDIFF 1.5 //max ignored diff, in bits #define DTCALC_MAX 1.0e-3 /* max dt for disd, dvmax calc */ #define MAX_DTINFO 25 #define MAX_DELAYINFO 25 #define MAX_PUBIDXWARN 25 #define USEC_DELAY 10 /* microsec delay inside delayUntil loop */ #define IMIN(A,B) (((A)<(B)) ? (A) : (B)) #define NEAREST_SHORT(X) (short)(((X)<0.0) ? ((X)-0.5) : ((X)+0.5)) static int indatCnt; /* Count num times called since sop */ static struct iolistSharedMem *iolRtc; static struct rtcConfig *rtcc; static struct rtcHostComm *rm; /* Host/Bolt communication */ static struct shmDasData *shm; static int dtCnt; static int delayCnt; static int pubIdxErrCnt; static int pubIdxWarnCnt; static int t0t1Flag,t0t1delayCnt,t0t1delayLoopCnt; static int zero=0,one=1,two=2,three=3,four=4,five=5,six=6,seven=7,eight=8; static unsigned int timeOfData; /* Time of latest data (imeas) */ static struct dtInfo { float t; float newDt; int idx; int indatCnt; int pubTime; } dtInfo[MAX_DTINFO]; static struct delayInfo { float t; int timeOfData; int targetTime; int pubTime; int refStartTime; } delayInfo[MAX_DELAYINFO]; static struct pubIdxWarn { float t; int pubIdx_waitApSem; //pubIdx from waitApSem int upubIdx; //pub->u.pubIdx int ok; //set if recovery is ok } pubIdxWarn[MAX_PUBIDXWARN]; #ifndef __ppc /**************************************************************** * ppc_cache_invalidate: * Dummy routine for non-SKYbolt2 ****************************************************************/ static void ppc_cache_invalidate( void *ptr , ... ) /* dummy for Host */ { ptr = ptr; return; } #endif /************************************************************** * make_test_filename: * Make "d_*.o" filename which includes date and time **************************************************************/ void FORTRAN_SUBROUTINE(make_test_filename)( char filename[] /* filename string */ ,int len /* num chars in filename[] */ ) { int k; time_t bintim; struct tm *tm; time(&bintim); #ifdef _SKY bintim -= LOCALTIME_CORRECTION; /* adjust for GMT on Sky */ #endif tm = localtime(&bintim); sprintf(filename,"d_%02d%02d%02d_%02d%02d.o",tm->tm_year%100, tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min); k = strlen(filename); if (k > len) { printf("make_test_filename_ *ERR* filename too long!\n"); exit(0); } else if (k < len) memset(filename+k,' ',len-k); return; } /**************************************************************** * delayUntil: * Wait until requested "pubTime" ****************************************************************/ static int delayUntil( int targetTime /* requested "pubTime" */ ,int refStartTime /* starting time */ ) { #ifdef __ppc int delta; int icnt; int pubIdx; int sts; struct pubIdxWarn *pw; unsigned int pubTime; long long btNow; long long btStartTime,btTimeoutTime; //for timeout long long btNewData; //expected time for new data static long long btLastData; //time of last data ppc_cache_invalidate((void *)pub,sizeof(*pub)); /* Invalidate cached pubData so we get new ... *-----------------------------------------------*/ pubIdx = pub->u.pubIdx; pubTime = pub->u.pubTime[pubIdx]; delta = targetTime - pubTime; if (delta>FAST_PER_SECOND || delta<0) { if (refStartTime > pubTime) return(0); /* SOP-EOP reset of pubTime */ if (delayCnt < MAX_DELAYINFO) { struct delayInfo *d; d = delayInfo + delayCnt++; d->t = pub->u.pubNstxTime[pubIdx]; d->timeOfData = timeOfData; d->targetTime = targetTime; d->pubTime = pubTime; d->refStartTime = refStartTime; } } /*------------------------------------------------------ * Set timeout depending on the current state -- * short timeout during SOP-EOP *-----------------------------------------------------*/ ppc_readtimer(&btNow); btStartTime = btNow; if (pub->u.sopeopFlag) { if (pubTime == 0) //SOP: allow time for baseline calc btTimeoutTime = btNow + SEC2BT(0.030); else //else within SOP-EOP ... btTimeoutTime = btNow + SEC2BT(0.002); } else { btTimeoutTime = btNow + SEC2BT(180.); } for ( ; btNowu.pubIdx) { if (((pubIdx+1)%NAVG_MAX) == pub->u.pubIdx) { pw = pubIdxWarn + pubIdxWarnCnt++; if (pubIdxWarnCnt <= MAX_PUBIDXWARN) { pw->t = nstxTime; pw->pubIdx_waitApSem = pubIdx; pw->upubIdx = pub->u.pubIdx; } pubIdx = pub->u.pubIdx; } else { /* Try one more time before "err" ... */ ppc_cache_invalidate((void *)pub,sizeof(*pub)); if (pubIdx != pub->u.pubIdx) { // problem still present ... shm->rtcWarnFlags |= RTCWARN_PUBIDX; if (!nstx_pcs_collect_integer.nerracq) { printf("\n%25s Data Acq *PUBIDX %d/%d* t=%.3f\n", "",pubIdx,pub->u.pubIdx,nstxTime); nstx_pcs_collect_integer.nerracq = 1 | RTCWARN_PUBIDX; } pubIdxErrCnt++; ppc_cache_invalidate((void *)pub,sizeof(*pub)); continue; } pw = pubIdxWarn + pubIdxWarnCnt++; if (pubIdxWarnCnt <= MAX_PUBIDXWARN) { pw->t = nstxTime; pw->pubIdx_waitApSem = pubIdx; pw->upubIdx = pub->u.pubIdx; } } } pubTime = pub->u.pubTime[pubIdx]; if (pubTime >= targetTime) return(0); //-------------------------------> return if (pubTime < refStartTime) { targetTime = 0; continue; /* SOP-EOP reset of pubTime */ } } shm->rtcWarnFlags |= RTCWARN_TIMEOUT; if (!nstx_pcs_collect_integer.nerracq) { printf("\n%20s Data Acq *%.3fsec TIMEOUT* t=%.3f\n", "",BT2SEC(btNow-btStartTime),nstxTime); nstx_pcs_collect_integer.nerracq = 1 | RTCWARN_TIMEOUT; } #endif return(1); //------------------------------> timeout } /**************************************************************** * getRealData: ****************************************************************/ static int getRealData( float *t /* time, in sec, within the cycle <0.0=SOP> */ ) { int i,k; int cnt; int currentDt; int idt; int idx; int targetTime; int pubIdx; int pubTime; int rtcIdt; /* desired idt for rtc: 1ms or 1sec */ float *calBuf; /* calibrated data in "pub" */ float *imeas; /* ptr to psrtc's "imeas" array */ float dtcalc; /* used in calculating disd, dvmax */ float xx; /* used in calculating disd, dvmax */ struct pubIdxWarn *pw; static int idtB4; static int npulseB4; {profile_update(&two,"getRealData: *top*",0);} imeas = nstx_pcs_collect_real.imeas; //just for convenience /*======================================================= * Check that shm is mapped (first-time flag, effectively). * Check current state: "targetTime" is positive only * during the SOP-EOP period. *======================================================*/ if (!shm) { shm = mapDasData(); rtcc = mapRtcConfig(); pub = mapPubData_cache(); iolRtc = mapRtcIolist_cache(); if (!shm || !rtcc || !pub || !iolRtc) exit(pcsmsg(2,"*EXIT* couldn't map shared mem")); atexit(unmapAllSharedMem); nstx_pcs_gen.nsopeop = 0; timeOfData = pub->u.pubTime[pub->u.pubIdx]; /* init start value */ } ppc_cache_invalidate((void *)pub,sizeof(*pub)); /* Invalidate cached pubData so we get new ... *-----------------------------------------------*/ pubIdx = pub->u.pubIdx; pubTime = pub->u.pubTime[pubIdx]; currentDt = pub->dtInClkticks; rtcIdt = (currentDt == 1) ? FAST_PER_SECOND/1000 : FAST_PER_SECOND; rtcIdt = (currentDt == 1) ? 1 : FAST_PER_SECOND; //*TEMP* 18-Jun-2003 {profile_update(&three,"getRealData: after cache_invalidate(pub)",0);} /* 1msec or 1sec */ if (pub->u.sopeopFlag) { if (!nstx_pcs_gen.nsopeop) { nstx_pcs_gen.nsopeop = 1; /* shift to SOP-EOP */ nstx_pcs_gen.newCycle = 1; /* set "firsttime" flag */ nstx_pcs_gen.nshot = rtcc->shotNumber; /* real shotNumber */ rm->sopFlag = 1; /*... for IDL uif */ npulseB4 = 0; } } else { if (nstx_pcs_gen.nsopeop) { nstx_pcs_gen.nsopeop = 0; /* shift to BETWEEN-SHOTS */ rm->eopFlag = 1; /*... for IDL uif */ } if (currentDt > 1) { if (dtCnt) { printf("\nListing of vagaries in dt:\n"); k = dtCnt - 1; for (i=0 ; i 1) printf("%4d: t=%8.4f to%8.4f %6d at %.4f pubTime=%d\n", i+1,dtInfo[i].t, dtInfo[i].t+(cnt-1)*dtInfo[i].newDt, cnt,dtInfo[i].newDt,dtInfo[i].pubTime); else printf("%4d: t=%8.4f %10s %6d at %.4f pubTime=%d\n", i+1,dtInfo[i].t,"",cnt,dtInfo[i].newDt, dtInfo[i].pubTime); } printf("%4d: t=%8.4f ..dt = %.4f\n",i+1,dtInfo[i].t, dtInfo[i].newDt); printf("\n"); fflush(stdout); dtCnt = 0; } if (delayCnt) { struct delayInfo *d; printf("Listing of delayUntil problems (delayInfo[]):\n"); for (i=0 ; it,d->timeOfData,d->targetTime,d->pubTime); } printf("\n"); fflush(stdout); delayCnt = 0; } if (t0t1delayCnt) { printf("\n"); printf("delayUntil() stats for t=0 to t=1:\n"); printf(" cnt=%d loopCnt=%d %.2f avg loops per call\n", t0t1delayCnt,t0t1delayLoopCnt, (float)t0t1delayLoopCnt/(float)t0t1delayCnt); printf("\n"); t0t1delayCnt = 0; } if (pubIdxErrCnt) { printf("\n"); pcsmsg(0,"rtc_indat: pubIdxErrCnt = %d",pubIdxErrCnt); k = (pubIdxWarnCnt < MAX_PUBIDXWARN) ? pubIdxWarnCnt : MAX_PUBIDXWARN; printf(" nstxTime pubIdx(waitApSem) u.pubIdx\n"); for (i=0 ; it,pw->pubIdx_waitApSem,pw->upubIdx, pw->ok?"ok":"*PROBLEM*"); } pcsmsg(0,"rtc_indat: pubIdxErrCnt = %d",pubIdxErrCnt); printf("\n"); pubIdxErrCnt = 0; } if (pubIdxWarnCnt) { printf("\n"); pcsmsg(0,"rtc_indat: pubIdxWarnCnt = %d",pubIdxWarnCnt); printf("\n"); pubIdxWarnCnt = 0; } } } /*======================================================= * If *NOT* using the pcs, wait for next data sample * where idt is 1 msec since previous sample. * If pcs is active, then the "wait" will occur when * waiting for next power supply voltage request. *======================================================*/ if (!nstx_pcs_collect_integer.npcon || !nstx_pcs_gen.npulse) { targetTime = (pubTime pubTime) { delayUntil(targetTime,pubTime); {profile_update(&four,"getRealData: after delayUntil",0);} /* Invalidate pubData cache was done in delayUntil *-----------------------------------------------*/ pubIdx = pub->u.pubIdx; pubTime = pub->u.pubTime[pubIdx]; } else if (targetTime < pubTime) { shm->rtcWarnFlags |= RTCWARN_MISSED_REQ_TIME; } } { #ifdef __ppc static long long btB4,btNow; if (!btB4) { ppc_readtimer(&btB4); } ppc_readtimer(&btNow); nstx_pcs_collect_real.dummy1 = BT2SEC(btNow-btB4); btB4 = btNow; #endif /* __ppc */ } /*======================================================= * Transfer latest data "block" to fortran common block *======================================================*/ *t = (float )pubTime*FAST_DT + nstx_pcs_gen.tsop; if (*t>=0.0 && *t<=1.0) { if (!t0t1Flag) { t0t1Flag = 1; t0t1delayCnt = 0; t0t1delayLoopCnt = 0; } } else { t0t1Flag = 0; } idt = pubTime - timeOfData; if (idt <= 0) idt = rtcIdt; /* must be reset of pubTime at SOP-EOP */ timeOfData = pubTime; indatCnt++; if (idt != idtB4) { nstx_pcs_gen.dt = (float )idt*FAST_DT; /* dt in seconds */ /*------------------------------------------------ * Use new dt to re-calculate disd, dvmax ... *-----------------------------------------------*/ dtcalc = (nstx_pcs_gen.dt < DTCALC_MAX) ? nstx_pcs_gen.dt : DTCALC_MAX; vsmul_sp(nstx_pcs_gen.scd,1, dtcalc, nstx_pcs_gen.disd,1, NCOILS_V0); xx = 2.0 * M_PI * nstx_pcs_gen.fac * dtcalc; vsmul_sp(nstx_pcs_gen.vdotmax,1, xx, nstx_pcs_gen.dvmax,1, NCOILS_V0); idtB4 = idt; shm->rtcWarnFlags |= RTCWARN_NEW_DT; if (nstx_pcs_gen.npulse) { if (dtCnt < MAX_DTINFO) { dtInfo[dtCnt].t = (float)*t; dtInfo[dtCnt].pubTime = pubTime; dtInfo[dtCnt].newDt = nstx_pcs_gen.dt; dtInfo[dtCnt].idx = idx; dtInfo[dtCnt].indatCnt = indatCnt; dtCnt++; } } } /*--------------------------------------------------------- * Copy all DAS data channels to common ... *--------------------------------------------------------*/ /// vfill_dp(0.0, nstx_pcs_gen.das,1,NCHAN1R); /* zero das[] */ {profile_update(&six,"getRealData: before xfr",0);} calBuf = pub->calBuf[pubIdx]; /* calibrated data buffer */ vmov_sp(calBuf,1, imeas,1, NCHAN1R); {profile_update(&seven,"getRealData: after xfr (vmov_sp)",0);} /*--------------------------------------------------------- * Check for faults in TF, OH, PF ... *--------------------------------------------------------*/ nstx_pcs_collect_integer.nhcstf = (imeas[DIGIDX1_TFFLT] >= DIG_FAULTLEVEL_VOLTS); nstx_pcs_collect_integer.nhcsoh = (imeas[DIGIDX1_OHFLT] >= DIG_FAULTLEVEL_VOLTS); nstx_pcs_collect_integer.nhcspfchi = (imeas[DIGIDX1_PFCHIFLT] >= DIG_FAULTLEVEL_VOLTS); #if (NCHANSPA > 0) nstx_pcs_collect_integer.nhcsspa = (imeas[DIGIDXRWM_SPAFLT] >= DIG_FAULTLEVEL_VOLTS); #endif #ifdef DISABLE_NHCS nstx_pcs_collect_integer.nhcstf = 0; nstx_pcs_collect_integer.nhcsoh = 0; nstx_pcs_collect_integer.nhcspfchi = 0; nstx_pcs_collect_integer.nhcsspa = 0; #endif if (pub->nerracqOutOfSync) { if (!nstx_pcs_collect_integer.nerracq) { printf("\n%25s Data Acq *SYNC ERROR* t=%.3f\n","",nstxTime); nstx_pcs_collect_integer.nerracq = 1 | RTCWARN_DATA_SYNC; } } /* calBuf to imeas */ return(1); } /****************************************************************** * indat: ******************************************************************/ int indat_( /* really a FORTRAN_SUBROUTINE, but ...*/ float *t /* time, in sec, within the cycle <0.0=SOP> */ ) { static int twentyFour=24,twentyFive=25; extern FORTRAN_SUBROUTINE(sim_indat)(float *); //Prototype #ifdef _SKY if (!rm) rm = (void *)get_share_mem_addr(); #endif #ifdef _SKY if (nstx_pcs_gen.nsubmode) #else if (1) /* always simulated data if running on host */ #endif { FORTRAN_SUBROUTINE(sim_indat)(t); /* use simulated data ...*/ timeOfData = (unsigned int) ((*t - nstx_pcs_gen.tsop)*(float)FAST_PER_SECOND + 0.5); } else { getRealData(t); /*..else, use real data */ } nstxTime = *t; //make *t available for display in msgs nstx_pcs_gen.ntdata = timeOfData; return(1); } /***************************************************************** * show_aomeas: *****************************************************************/ int FORTRAN_SUBROUTINE(show_aomeas)() { int i,k; float *aomeas; printf("\nValues in aomeas:\n"); aomeas = nstx_pcs_gen.aomeas[0]; for (i=0 ; i<10 ; i++) { for (k=i ; k<(NBRANCHES*2) ; k+=10) printf("%8d %8.3f",k+1,aomeas[k]); printf("\n"); } return(1); } /***************************************************************** * compare_baselines: * Temporary function -- compare aomeas with shm->baselineAdj *****************************************************************/ int FORTRAN_SUBROUTINE(compare_baselines)() { #ifdef _SKY int ib,ic; int diffCnt; int idx1,idx2; float cvt; float diff; float maxDiff; float aoBits; static char fmt[] = "Branch %-2d %5s:%s chan %-3d diff=%.2f bits\n"; if (nstx_pcs_gen.nsubmode) return(1); /* don't do compare in simulation mode */ printf("\n"); printf("%s -- aomeas : shm->baselineAdj diffs GT %.2f bits\n", "compare_baselines",COMPARE_BASELINES_MAXDIFF); diffCnt = 0; maxDiff = 0.0; for (ib=0 ; ib circuit %s locked out\n",circuitName(ic)); #endif continue; /* circuit is locked out */ } if (nstx_pcs_gen.kpb[ib] == 0.0) { #if 1 printf("--> branch %d multiplier 0.0: %s\n",ib,circuitName(ic)); #endif continue; /* circuit is locked out */ } idx1 = nstx_pcs_gen.nmeas[0][ib] - 1; /* 1st raw data chan */ idx2 = nstx_pcs_gen.nmeas[1][ib] - 1; /* redundant raw chan */ cvt = nstx_pcs_gen.kmeas[0][ib]; aoBits = (float)nstx_pcs_gen.aomeas[0][ib]/cvt; /*------------------------------------------------ * acq calculates and subtracts baseline, so the * "default" baseline offset is zero bits ... *-----------------------------------------------*/ /* diff = aoBits - shm->baselineAdj[idx1]; */ diff = aoBits; /* 14-Mar-2000: acq subtracts baseline */ if (fabs(diff) > maxDiff) maxDiff = fabs(diff); if (fabs(diff) >= COMPARE_BASELINES_MAXDIFF) { diffCnt++; printf(fmt, ib,circuitName(ic),"(Primary) ",idx1,diff); } if (idx2 != idx1) { cvt = nstx_pcs_gen.kmeas[1][ib]; aoBits = (float)nstx_pcs_gen.aomeas[1][ib]/cvt; /* diff = aoBits - shm->baselineAdj[idx2]; */ diff = aoBits; /* because aomeas already baseline-corrected */ if (fabs(diff) > maxDiff) maxDiff = fabs(diff); if (fabs(diff) >= COMPARE_BASELINES_MAXDIFF) { diffCnt++; printf(fmt, ib,circuitName(ic),"(Redundant)",idx2,diff); } } } printf("==> compare_baselines: maxDiff = %.2f\n",maxDiff); #endif /* _SKY */ return(1); } /**************************************************************** * set_idl_info: * Set information in rtcHostComm struct for display in * IDL user interface. ****************************************************************/ int FORTRAN_FUNCTION(set_idl_info)() { #ifdef _SKY int nbytes; /*------------------------------------------------ * Note: rm->sopFlag and rm->eopFlag are set * from within rtc_indat.c. *-----------------------------------------------*/ if (!rm) rm = (void *)get_share_mem_addr(); rm->nfaultFlag = nstx_pcs_gen.nfaultFlag; nbytes = sizeof(rm->coilTemps); sky_memcpy(rm->coilTemps,nstx_pcs_collect_real.tcoil,nbytes); nbytes = sizeof(rm->poleTemps); sky_memcpy(rm->poleTemps,nstx_pcs_collect_real.tpole,nbytes); if (nstx_pcs_gen.nfcount) { rm->msgFlag = 1; } #endif /* _SKY */ return(1); }