From af78cc8f3554f495a9767d656ad24c471a9b84d7 Mon Sep 17 00:00:00 2001
From: Rolf Bork <rolf@ligo.caltech.edu>
Date: Wed, 29 May 2019 11:20:42 -0500
Subject: [PATCH] Made generic functions to pass FE code timing info to EPICS.

---
 src/fe/controllerApp.c              | 114 +++++++++-------------
 src/fe/controllerCymac.c            |  47 +--------
 src/fe/controllerTS.c               | 142 +++++++++-------------------
 src/fe/timing.c                     |   2 +-
 src/include/drv/iop_adc_functions.c |   1 +
 5 files changed, 93 insertions(+), 213 deletions(-)

diff --git a/src/fe/controllerApp.c b/src/fe/controllerApp.c
index d7fa6e500..de35cd6af 100644
--- a/src/fe/controllerApp.c
+++ b/src/fe/controllerApp.c
@@ -124,21 +124,9 @@ unsigned int timeSec = 0;
 unsigned int timeSecDiag = 0;
 /* 1 - error occured on shmem; 2 - RFM; 3 - Dolphin */
 unsigned int ipcErrBits = 0;
-int adcTime;			///< Used in code cycle timing
-int adcHoldTime = 0;		///< Stores time between code cycles
-int adcHoldTimeMax = 0;		///< Stores time between code cycles
 int startGpsTime = 0;
-int adcHoldTimeMin = 0xffff;
-int adcHoldTimeAvg = 0;
-int adcHoldTimeAvgPerSec;
-int usrTime;			///< Time spent in user app code
-int usrHoldTime = 0;		///< Max time spent in user app code
 int cardCountErr = 0;
 int cycleTime;			///< Current cycle time
-int timeHold = 0;			///< Max code cycle time within 1 sec period
-int timeHoldHold = 0;			///< Max code cycle time within 1 sec period; hold for another sec
-int timeHoldWhen= 0;			///< Cycle number within last second when maximum reached; running
-int timeHoldWhenHold = 0;		///< Cycle number within last second when maximum reached
 
 struct rmIpcStr *daqPtr;
 
@@ -155,8 +143,9 @@ int dacOF[MAX_DAC_MODULES];
 
 char daqArea[2*DAQ_DCU_SIZE];		// Space allocation for daqLib buffers
 int cpuId = 1;
-adcInfo_t adcInfo;
+adcInfo_t adcinfo;
 dacInfo_t dacInfo;
+timing_diag_t timeinfo;
 int killipc = 0;
 
 
@@ -212,7 +201,6 @@ void *fe_start(void *arg)
 					///< so this helps prevent long cycles during that time.
   int dkiTrip = 0;
   RFM_FE_COMMS *pEpicsComms;		/// @param *pEpicsComms Pointer to EPICS shared memory space
-  int timeHoldMax = 0;			/// @param timeHoldMax Max code cycle time since last diag reset
   int myGmError2 = 0;			/// @param myGmError2 Myrinet error variable
   int status;				/// @param status Typical function return value
   int onePpsTime = 0;			/// @param onePpsTime One PPS diagnostic check
@@ -394,6 +382,8 @@ udelay(1000);
   // printf("Calling feCode() to initialize\n");
   iopDacEnable = feCode(cycleNum,dWord,dacOut,dspPtr[0],&dspCoeff[0], (struct CDS_EPICS *)pLocalEpics,1);
 
+// Initialize timing info variables
+   initializeTimingDiags(&timeinfo);
   
   pLocalEpics->epicsOutput.fe_status = INIT_DAC_MODS;
   /// \> Initialize DAC channels.
@@ -440,7 +430,7 @@ udelay(1000);
   timeSec = current_time_fe() -1;
 #endif
 
-  rdtscll(adcTime);
+  rdtscll(adcinfo.adcTime);
 
   /// ******************************************************************************\n
   /// Enter the infinite FE control loop  ******************************************\n
@@ -454,13 +444,13 @@ udelay(1000);
 #endif
 
 
-	// **********************************************************************************************************
+	// *******************************************************************************
 	// NORMAL OPERATION -- Wait for ADC data ready
 	// On startup, only want to read one sample such that first cycle
 	// coincides with GPS 1PPS. Thereafter, sampleCount will be 
 	// increased to appropriate number of 65536 s/sec to match desired
 	// code rate eg 32 samples each time thru before proceeding to match 2048 system.
-	// **********************************************************************************************************
+	// *******************************************************************************
 
 #ifdef NO_CPU_SHUTDOWN
   while(!kthread_should_stop()){
@@ -484,7 +474,7 @@ udelay(1000);
 #endif
 	for(ll=0;ll<sampleCount;ll++)
     {
-		status = app_adc_read(ioMemCntr,ioClock,&adcInfo,cpuClock);
+		status = app_adc_read(ioMemCntr,ioClock,&adcinfo,cpuClock);
 
 		// Return of non zero = ADC timeout error.
 		if(status)
@@ -535,27 +525,14 @@ udelay(1000);
 /// \> Cycle 18, Send timing info to EPICS at 1Hz
 	if(cycleNum ==HKP_TIMING_UPDATES)	
     {
-		pLocalEpics->epicsOutput.cpuMeter = timeHold;
-	  	pLocalEpics->epicsOutput.cpuMeterMax = timeHoldMax;
-        timeHoldHold = timeHold;
-        timeHold = 0;
-	  	timeHoldWhenHold = timeHoldWhen;
-
-	  	if (timeSec % 4 == 0) pLocalEpics->epicsOutput.adcWaitTime = adcHoldTimeMin;
-	  	else if (timeSec % 4 == 1)
-			pLocalEpics->epicsOutput.adcWaitTime =  adcHoldTimeMax;
-	  	else
-	  		pLocalEpics->epicsOutput.adcWaitTime = adcHoldTimeAvg/CYCLE_PER_SECOND;
-	  		adcHoldTimeAvgPerSec = adcHoldTimeAvg/CYCLE_PER_SECOND;
-	  		adcHoldTimeMax = 0;
-	  		adcHoldTimeMin = 0xffff;
-	  		adcHoldTimeAvg = 0;
-	  	if((adcHoldTime > CYCLE_TIME_ALRM_HI) || (adcHoldTime < CYCLE_TIME_ALRM_LO)) 
+        sendTimingDiags2Epics(pLocalEpics, &timeinfo, &adcinfo);
+
+	  	if((adcinfo.adcHoldTime > CYCLE_TIME_ALRM_HI) || (adcinfo.adcHoldTime < CYCLE_TIME_ALRM_LO)) 
 	  	{
 	  		diagWord |= FE_ADC_HOLD_ERR;
 			feStatus |= FE_ERROR_TIMING;
 	  	}
-	  	if(timeHoldMax > CYCLE_TIME_ALRM) 
+	  	if(timeinfo.timeHoldMax > CYCLE_TIME_ALRM) 
 	  	{
 	  		diagWord |= FE_PROC_TIME_ERR;
 			feStatus |= FE_ERROR_TIMING;
@@ -567,22 +544,21 @@ udelay(1000);
 			initialDiagReset = 0;
 			pLocalEpics->epicsInput.diagReset = 0;
 			pLocalEpics->epicsInput.ipcDiagReset = 1;
-			timeHoldMax = 0;
+			timeinfo.timeHoldMax = 0;
 	  		diagWord = 0;
 			ipcErrBits = 0;
 		
 	  	}
-	  	// Flip the onePPS various once/sec as a watchdog monitor.
-	  	// pLocalEpics->epicsOutput.onePps ^= 1;
 	  	pLocalEpics->epicsOutput.diagWord = diagWord;
 	}
 
-
+// *****************************************************************
 /// \> Check for requests for filter module clear history requests. This is spread out over a number of cycles.
 	// Spread out filter coeff update, but keep updates at 16 Hz
 	// here we are rounding up:
 	//   x/y rounded up equals (x + y - 1) / y
 	//
+// *****************************************************************
 	static const unsigned int mpc = (MAX_MODULES + (FE_RATE / 16) - 1) / (FE_RATE / 16); // Modules per cycle
 	unsigned int smpc = mpc * subcycle; // Start module counter
 	unsigned int empc = smpc + mpc; // End module counter
@@ -590,16 +566,22 @@ udelay(1000);
 	for (i = smpc; i < MAX_MODULES && i < empc ; i++) 
 		checkFiltReset(i, dspPtr[0], pDsp[0], &dspCoeff[0], MAX_MODULES, pCoeff[0]);
 
+// *****************************************************************
 	/// \> Check if code exit is requested
 	if(cycleNum == MAX_MODULES) 
 		vmeDone = stop_working_threads | checkEpicsReset(cycleNum, (struct CDS_EPICS *)pLocalEpics);
+// *****************************************************************
 
+// *****************************************************************
 /// \> Cycle 10 to number of BIO cards:\n
  /// - ---- Read Dio cards once per second \n
+// *****************************************************************
 
 	status = app_dio_read_write();
 
+// *****************************************************************
 /// \>  Write data to DAQ.
+// *****************************************************************
 #ifndef NO_DAQ
 	
 	// Call daqLib
@@ -615,10 +597,11 @@ udelay(1000);
 		feStatus |= FE_ERROR_DAQ;
 #endif
 
+// *****************************************************************
 /// \> Cycle 19, write updated diag info to EPICS
+// *****************************************************************
 	if(cycleNum == HKP_DIAG_UPDATES)	
     {
-	  	pLocalEpics->epicsOutput.userTime = usrHoldTime;
 	  	pLocalEpics->epicsOutput.ipcStat = ipcErrBits;
 	  	if(ipcErrBits & 0xf) feStatus |= FE_ERROR_IPC;
 	  	// Create FB status word for return to EPICS
@@ -634,14 +617,13 @@ udelay(1000);
   	  	mxDiag = mxDiagR;
 	  	if(mxStat != MX_OK)
 			feStatus |= FE_ERROR_DAQ;;
-	  	usrHoldTime = 0;
   	  	if(pLocalEpics->epicsInput.overflowReset)
 	  	{
         	if (pLocalEpics->epicsInput.overflowReset) {
             	for (ii = 0; ii < 16; ii++) {
                 	for (jj = 0; jj < cdsPciModules.adcCount; jj++) {
-                    	adcInfo.overflowAdc[jj][ii] = 0;
-                        adcInfo.overflowAdc[jj][ii + 16] = 0;
+                    	adcinfo.overflowAdc[jj][ii] = 0;
+                        adcinfo.overflowAdc[jj][ii + 16] = 0;
 						pLocalEpics->epicsOutput.overflowAdcAcc[jj][ii] = 0;
 						pLocalEpics->epicsOutput.overflowAdcAcc[jj][ii + 16] = 0;
                      }
@@ -664,7 +646,10 @@ udelay(1000);
 	{
           pLocalEpics->epicsOutput.timeDiag = timeSec;
 	}
+
+// *****************************************************************
 /// \> Cycle 20, Update latest DAC output values to EPICS
+// *****************************************************************
     if(subcycle == HKP_DAC_EPICS_UPDATES)
 	{
 		// Send DAC output values at 16Hzfb
@@ -677,48 +662,35 @@ udelay(1000);
 	    }
 	}
 
+// *****************************************************************
 /// \> Cycle 21, Update ADC/DAC status to EPICS.
+// *****************************************************************
     if(cycleNum == HKP_ADC_DAC_STAT_UPDATES)
     {
 	  	pLocalEpics->epicsOutput.ovAccum = overflowAcc;
-		feStatus |= app_adc_status_update(&adcInfo);
+		feStatus |= app_adc_status_update(&adcinfo);
 		feStatus |= app_dac_status_update(&dacInfo);
 	}
+
+    // *****************************************************************
+    // // Update end of cycle information
+    // // *****************************************************************
 	// Capture end of cycle time.
     rdtscll(cpuClock[CPU_TIME_CYCLE_END]);
 
+    captureEocTiming(cycleNum, cycle_gps_time, &timeinfo, &adcinfo);
+
 	/// \> Compute code cycle time diag information.
-	cycleTime = (cpuClock[CPU_TIME_CYCLE_END] - cpuClock[CPU_TIME_CYCLE_START])/CPURATE;
+	timeinfo.cycleTime = (cpuClock[CPU_TIME_CYCLE_END] - cpuClock[CPU_TIME_CYCLE_START])/CPURATE;
 
-	// Hold the max cycle time over the last 1 second
-	if(cycleTime > timeHold) { 
-		timeHold = cycleTime;
-		timeHoldWhen = cycleNum;
-	}
-	// Hold the max cycle time since last diag reset
-	if(cycleTime > timeHoldMax) timeHoldMax = cycleTime;
-	adcHoldTime = (cpuClock[CPU_TIME_CYCLE_START] - adcTime)/CPURATE;
-
-	// Avoid calculating the max hold time for the first few seconds
-	if (cycleNum != 0 && (startGpsTime+3) < cycle_gps_time) {
-		if(adcHoldTime > adcHoldTimeMax) adcHoldTimeMax = adcHoldTime;
-		if(adcHoldTime < adcHoldTimeMin) adcHoldTimeMin = adcHoldTime;
-		adcHoldTimeAvg += adcHoldTime;
-	}
-	adcTime = cpuClock[CPU_TIME_CYCLE_START];
-	// Calc the max time of one cycle of the user code
-	// For IOP, more interested in time to get thru ADC read code and send to slave apps
-	usrTime = (cpuClock[CPU_TIME_USR_END] - cpuClock[CPU_TIME_USR_START])/CPURATE;
-	if(usrTime > usrHoldTime) usrHoldTime = usrTime;
+    adcinfo.adcHoldTime = (cpuClock[CPU_TIME_CYCLE_START] - adcinfo.adcTime)/CPURATE;
+    adcinfo.adcTime = cpuClock[CPU_TIME_CYCLE_START];
+    // Calc the max time of one cycle of the user code
+    timeinfo.usrTime = (cpuClock[CPU_TIME_USR_END] - cpuClock[CPU_TIME_USR_START])/CPURATE;
+    if(timeinfo.usrTime > timeinfo.usrHoldTime) timeinfo.usrHoldTime = timeinfo.usrTime;
 
     /// \> Update internal cycle counters
     cycleNum += 1;
-#ifdef DIAG_TEST
-    if(pLocalEpics->epicsInput.bumpCycle != 0) {
-	  	cycleNum += pLocalEpics->epicsInput.bumpCycle;
-		pLocalEpics->epicsInput.bumpCycle = 0;
-  	}
-#endif
     cycleNum %= CYCLE_PER_SECOND;
 	clock1Min += 1;
 	clock1Min %= CYCLE_PER_MINUTE;
diff --git a/src/fe/controllerCymac.c b/src/fe/controllerCymac.c
index 1d9500423..f05c49a8e 100644
--- a/src/fe/controllerCymac.c
+++ b/src/fe/controllerCymac.c
@@ -495,7 +495,7 @@ adcInfo_t *padcinfo = (adcInfo_t *)&adcinfo;
   timeSec = remote_time((struct CDS_EPICS *)pLocalEpics);
   printf ("Using remote GPS time %d \n",timeSec);
 #else
-  timeSec = current_time() -1;
+  timeSec = current_time_fe() -1;
 #endif
 
   rdtscl(adcinfo.adcTime);
@@ -662,24 +662,10 @@ adcInfo_t *padcinfo = (adcInfo_t *)&adcinfo;
 // *****************************************************************
     if(cycleNum ==HKP_TIMING_UPDATES)	
     {
-      pLocalEpics->epicsOutput.cpuMeter = timeinfo.timeHold;
-      pLocalEpics->epicsOutput.cpuMeterMax = timeinfo.timeHoldMax;
+	  sendTimingDiags2Epics(pLocalEpics, &timeinfo, &adcinfo);
       pLocalEpics->epicsOutput.dacEnable = dacEnable;
-      timeinfo.timeHoldHold = timeinfo.timeHold;
-      timeinfo.timeHold = 0;
-      timeinfo.timeHoldWhenHold = timeinfo.timeHoldWhen;
-
-      if (timeSec % 4 == 0) pLocalEpics->epicsOutput.adcWaitTime = 
-        adcinfo.adcHoldTimeMin;
-      else if (timeSec % 4 == 1)
-        pLocalEpics->epicsOutput.adcWaitTime =  adcinfo.adcHoldTimeMax;
-      else
-        pLocalEpics->epicsOutput.adcWaitTime = adcinfo.adcHoldTimeAvg/CYCLE_PER_SECOND;
-
-      adcinfo.adcHoldTimeAvgPerSec = adcinfo.adcHoldTimeAvg/CYCLE_PER_SECOND;
-      adcinfo.adcHoldTimeMax = 0;
-      adcinfo.adcHoldTimeMin = 0xffff;
-      adcinfo.adcHoldTimeAvg = 0;
+
+
       if((adcinfo.adcHoldTime > CYCLE_TIME_ALRM_HI) || (adcinfo.adcHoldTime < CYCLE_TIME_ALRM_LO)) 
       {
         diagWord |= FE_ADC_HOLD_ERR;
@@ -697,7 +683,6 @@ adcInfo_t *padcinfo = (adcInfo_t *)&adcinfo;
         initialDiagReset = 0;
         pLocalEpics->epicsInput.diagReset = 0;
         pLocalEpics->epicsInput.ipcDiagReset = 1;
-  	// pLocalEpics->epicsOutput.diags[1] = 0;
         timeinfo.timeHoldMax = 0;
         diagWord = 0;
         ipcErrBits = 0;
@@ -970,31 +955,9 @@ adcInfo_t *padcinfo = (adcInfo_t *)&adcinfo;
     rdtscl(cpuClock[CPU_TIME_CYCLE_END]);
 
     /// \> Compute code cycle time diag information.
+	captureEocTiming(cycleNum, cycle_gps_time, &timeinfo, &adcinfo);
     timeinfo.cycleTime = (cpuClock[CPU_TIME_CYCLE_END] - cpuClock[CPU_TIME_CYCLE_START])/CPURATE;
-    // Hold the max cycle time over the last 1 second
-    if(timeinfo.cycleTime > timeinfo.timeHold) { 
-      timeinfo.timeHold = timeinfo.cycleTime;
-      timeinfo.timeHoldWhen = cycleNum;
-    }
-    // Hold the max cycle time since last diag reset
-    if(timeinfo.cycleTime > timeinfo.timeHoldMax) timeinfo.timeHoldMax = timeinfo.cycleTime;
     adcinfo.adcHoldTime = (cpuClock[CPU_TIME_CYCLE_START] - adcinfo.adcTime)/CPURATE;
-    // Avoid calculating the max hold time for the first few seconds
-    if (cycleNum != 0 && (timeinfo.startGpsTime+3) < cycle_gps_time) {
-      if(adcinfo.adcHoldTime > adcinfo.adcHoldTimeMax) 
-        adcinfo.adcHoldTimeMax = adcinfo.adcHoldTime;
-      if(adcinfo.adcHoldTime < adcinfo.adcHoldTimeMin) 
-        adcinfo.adcHoldTimeMin = adcinfo.adcHoldTime;
-      adcinfo.adcHoldTimeAvg += adcinfo.adcHoldTime;
-      if (adcinfo.adcHoldTimeMax > adcinfo.adcHoldTimeEverMax)  {
-        adcinfo.adcHoldTimeEverMax = adcinfo.adcHoldTimeMax;
-        adcinfo.adcHoldTimeEverMaxWhen = cycle_gps_time;
-      }
-      if (timeinfo.timeHoldMax > timeinfo.cpuTimeEverMax)  {
-        timeinfo.cpuTimeEverMax = timeinfo.timeHoldMax;
-        timeinfo.cpuTimeEverMaxWhen = cycle_gps_time;
-      }
-    }
     adcinfo.adcTime = cpuClock[CPU_TIME_CYCLE_START];
     // Calc the max time of one cycle of the user code
     // For IOP, more interested in time to get thru ADC read code and send to slave apps
diff --git a/src/fe/controllerTS.c b/src/fe/controllerTS.c
index 6fec66f8f..26295400d 100644
--- a/src/fe/controllerTS.c
+++ b/src/fe/controllerTS.c
@@ -70,6 +70,7 @@ int printk(const char *fmt, ...) {
 #include "fm10Gen.h"		// CDS filter module defs and C code
 #include "feComms.h"		// Lvea control RFM network defs.
 #include "daqmap.h"		// DAQ network layout
+#include "cds_types.h"
 #include "controller.h"
 
 #ifndef NO_DAQ
@@ -94,6 +95,10 @@ int printk(const char *fmt, ...) {
 
 TIMING_SIGNAL *pcieTimer;
 
+adcInfo_t adcinfo;
+dacInfo_t dacinfo;
+timing_diag_t timeinfo;
+
 // Contec 64 input bits plus 64 output bits (Standard for aLIGO)
 /// Contec6464 input register values
 unsigned int CDIO6464InputInput[MAX_DIO_MODULES]; // Binary input bits
@@ -130,6 +135,8 @@ unsigned int timeSec = 0;
 unsigned int timeSecDiag = 0;
 /* 1 - error occured on shmem; 2 - RFM; 3 - Dolphin */
 unsigned int ipcErrBits = 0;
+int cardCountErr = 0;
+#if 0
 int adcTime;			///< Used in code cycle timing
 int adcHoldTime;		///< Stores time between code cycles
 int adcHoldTimeMax;		///< Stores time between code cycles
@@ -141,14 +148,13 @@ int startGpsTime;
 int adcHoldTimeMin;
 int adcHoldTimeAvg;
 int adcHoldTimeAvgPerSec;
-int usrTime;			///< Time spent in user app code
 int usrHoldTime;		///< Max time spent in user app code
-int cardCountErr = 0;
 int cycleTime;			///< Current cycle time
 int timeHold = 0;			///< Max code cycle time within 1 sec period
 int timeHoldHold = 0;			///< Max code cycle time within 1 sec period; hold for another sec
 int timeHoldWhen= 0;			///< Cycle number within last second when maximum reached; running
 int timeHoldWhenHold = 0;		///< Cycle number within last second when maximum reached
+#endif
 
 // The following are for timing histograms written to /proc files
 #if defined(SERVO64K) || defined(SERVO32K)
@@ -247,7 +253,7 @@ void *fe_start(void *arg)
   					///< Code runs longer for first few cycles on startup as it settles in,
 					///< so this helps prevent long cycles during that time.
   int limit = OVERFLOW_LIMIT_16BIT;      /// @param limit ADC/DAC overflow test value
-  int mask = GSAI_DATA_MASK;            /// @param mask Bit mask for ADC/DAC read/writes
+  // int mask = GSAI_DATA_MASK;            /// @param mask Bit mask for ADC/DAC read/writes
   int num_outs = MAX_DAC_CHN_PER_MOD;   /// @param num_outs Number of DAC channels variable
   volatile int *packedData;		/// @param *packedData Pointer to ADC PCI data space
   volatile unsigned int *pDacData;	/// @param *pDacData Pointer to DAC PCI data space
@@ -257,7 +263,6 @@ void *fe_start(void *arg)
   int sync21ppsCycles = 0;		/// @param sync32ppsCycles Number of attempts to sync to 1PPS
   int dkiTrip = 0;
   RFM_FE_COMMS *pEpicsComms;		/// @param *pEpicsComms Pointer to EPICS shared memory space
-  int timeHoldMax = 0;			/// @param timeHoldMax Max code cycle time since last diag reset
   int myGmError2 = 0;			/// @param myGmError2 Myrinet error variable
   int status;				/// @param status Typical function return value
   float onePps;				/// @param onePps Value of 1PPS signal, if used, for diagnostics
@@ -296,9 +301,11 @@ void *fe_start(void *arg)
   static int dacTimingError = 0;
   static int dacTimingErrorPending[MAX_DAC_MODULES];
 
+#if 0
   volatile GSA_18BIT_DAC_REG *dac18bitPtr;	// Pointer to 16bit DAC memory area
   volatile GSA_20BIT_DAC_REG *dac20bitPtr;  // Pointer to 20bit DAC memory area
   volatile GSC_DAC_REG *dac16bitPtr;		// Pointer to 18bit DAC memory area
+  #endif
   unsigned int usec = 0;
   unsigned int offset = 0;
 
@@ -500,16 +507,7 @@ udelay(1000);
   iopDacEnable = feCode(cycleNum,dWord,dacOut,dspPtr[0],&dspCoeff[0], (struct CDS_EPICS *)pLocalEpics,1);
 
   // Clear timing diags.
-  adcHoldTime = 0;
-  adcHoldTimeMax = 0;
-  adcHoldTimeEverMax = 0;	
-  adcHoldTimeEverMaxWhen = 0;	
-  cpuTimeEverMax = 0;		
-  cpuTimeEverMaxWhen = 0;	
-  startGpsTime = 0;
-  adcHoldTimeMin = 0xffff;	
-  adcHoldTimeAvg = 0;		
-  usrHoldTime = 0;		
+  initializeTimingDiags(&timeinfo);
   missedCycle = 0;
 
   /// \> If IOP,  Initialize the ADC modules
@@ -527,7 +525,7 @@ udelay(1000);
 	  }
 	  // Set ADC Present Flag
   	  pLocalEpics->epicsOutput.statAdc[jj] = 1;
-	  adcRdTimeErr[jj] = 0;
+	  adcinfo.adcRdTimeErr[jj] = 0;
   }
   printf("ADC setup complete \n");
 
@@ -558,10 +556,10 @@ udelay(1000);
   timeSec = remote_time((struct CDS_EPICS *)pLocalEpics);
   printf ("Using remote GPS time %d \n",timeSec);
 #else
-  timeSec = current_time() -1;
+  timeSec = current_time_fe() -1;
 #endif
 
-  rdtscl(adcTime);
+  rdtscl(adcinfo.adcTime);
 
   /// ******************************************************************************\n
   /// Enter the infinite FE control loop  ******************************************\n
@@ -594,7 +592,7 @@ udelay(1000);
           	timeSec ++;
           	pLocalEpics->epicsOutput.timeDiag = timeSec;
 	  		if (cycle_gps_time == 0) {
-				startGpsTime = timeSec;
+				timeinfo.startGpsTime = timeSec;
 	  		}	
 	  		cycle_gps_time = timeSec;
 		}
@@ -622,16 +620,16 @@ udelay(1000);
 
 			/// - ---- Added ADC timing diagnostics to verify timing consistent and all rdy together.
 		    if(jj==0)
-			    adcRdTime[jj] = (cpuClock[CPU_TIME_ADC_WAIT] - cpuClock[CPU_TIME_CYCLE_START]) / CPURATE;
+			    adcinfo.adcRdTime[jj] = (cpuClock[CPU_TIME_ADC_WAIT] - cpuClock[CPU_TIME_CYCLE_START]) / CPURATE;
 		    else
-			    adcRdTime[jj] = adcWait;
+			    adcinfo.adcRdTime[jj] = adcWait;
 	
-		    if(adcRdTime[jj] > adcRdTimeMax[jj]) adcRdTimeMax[jj] = adcRdTime[jj];
+		    if(adcinfo.adcRdTime[jj] > adcinfo.adcRdTimeMax[jj]) adcinfo.adcRdTimeMax[jj] = adcinfo.adcRdTime[jj];
 
-		    if((jj==0) && (adcRdTimeMax[jj] > MAX_ADC_WAIT_CARD_0)) 
-			adcRdTimeErr[jj] ++;
-		    if((jj!=0) && (adcRdTimeMax[jj] > MAX_ADC_WAIT_CARD_S)) 
-			adcRdTimeErr[jj] ++;
+		    if((jj==0) && (adcinfo.adcRdTimeMax[jj] > MAX_ADC_WAIT_CARD_0)) 
+			adcinfo.adcRdTimeErr[jj] ++;
+		    if((jj!=0) && (adcinfo. adcRdTimeMax[jj] > MAX_ADC_WAIT_CARD_S)) 
+			adcinfo.adcRdTimeErr[jj] ++;
 
 		    /// - --------- If data not ready in time, abort.
 		    /// Either the clock is missing or code is running too slow and ADC FIFO
@@ -695,7 +693,7 @@ udelay(1000);
 			{
 				if((adcData[jj][ii] > limit) || (adcData[jj][ii] < -limit))
 			  	{
-					overflowAdc[jj][ii] ++;
+					adcinfo.overflowAdc[jj][ii] ++;
 					pLocalEpics->epicsOutput.overflowAdcAcc[jj][ii] ++;
 					overflowAcc ++;
 					adcOF[jj] = 1;
@@ -817,35 +815,14 @@ udelay(1000);
 /// \> Cycle 18, Send timing info to EPICS at 1Hz
 	if(cycleNum ==HKP_TIMING_UPDATES)	
     {
-	  pLocalEpics->epicsOutput.cpuMeter = timeHold;
-	  pLocalEpics->epicsOutput.cpuMeterMax = timeHoldMax;
-  	  pLocalEpics->epicsOutput.dacEnable = dacEnable;
-          timeHoldHold = timeHold;
-          timeHold = 0;
-	  timeHoldWhenHold = timeHoldWhen;
-
-#if defined(SERVO64K) || defined(SERVO32K) || defined(SERVO16K)
-	  memcpy(cycleHistMax, cycleHist, sizeof(cycleHist));
-	  memset(cycleHist, 0, sizeof(cycleHist));
-	  memcpy(cycleHistWhenHold, cycleHistWhen, sizeof(cycleHistWhen));
-	  memset(cycleHistWhen, 0, sizeof(cycleHistWhen));
-#endif
-	  if (timeSec % 4 == 0) pLocalEpics->epicsOutput.adcWaitTime = adcHoldTimeMin;
-	  else if (timeSec % 4 == 1)
-		pLocalEpics->epicsOutput.adcWaitTime =  adcHoldTimeMax;
-	  else
-	  	pLocalEpics->epicsOutput.adcWaitTime = adcHoldTimeAvg/CYCLE_PER_SECOND;
-	  adcHoldTimeAvgPerSec = adcHoldTimeAvg/CYCLE_PER_SECOND;
-	  adcHoldTimeMax = 0;
-	  adcHoldTimeMin = 0xffff;
-	  adcHoldTimeAvg = 0;
-	  if((adcHoldTime > CYCLE_TIME_ALRM_HI) || (adcHoldTime < CYCLE_TIME_ALRM_LO)) 
+      sendTimingDiags2Epics(pLocalEpics, &timeinfo, &adcinfo);
+	  if((adcinfo.adcHoldTime > CYCLE_TIME_ALRM_HI) || (adcinfo.adcHoldTime < CYCLE_TIME_ALRM_LO)) 
 	  {
 	  	diagWord |= FE_ADC_HOLD_ERR;
 		feStatus |= FE_ERROR_TIMING;
 	  
 	  }
-	  if(timeHoldMax > CYCLE_TIME_ALRM) 
+	  if(timeinfo.timeHoldMax > CYCLE_TIME_ALRM) 
 	  {
 	  	diagWord |= FE_PROC_TIME_ERR;
 		feStatus |= FE_ERROR_TIMING;
@@ -858,20 +835,20 @@ udelay(1000);
 		pLocalEpics->epicsInput.diagReset = 0;
 		pLocalEpics->epicsInput.ipcDiagReset = 1;
   		// pLocalEpics->epicsOutput.diags[1] = 0;
-		timeHoldMax = 0;
+		timeinfo.timeHoldMax = 0;
 	  	diagWord = 0;
 		ipcErrBits = 0;
 		
 		// feStatus = 0;
-        for(jj=0;jj<cdsPciModules.adcCount;jj++) adcRdTimeMax[jj] = 0;
+        for(jj=0;jj<cdsPciModules.adcCount;jj++) adcinfo.adcRdTimeMax[jj] = 0;
 	  }
 	  // Flip the onePPS various once/sec as a watchdog monitor.
 	  // pLocalEpics->epicsOutput.onePps ^= 1;
 	  pLocalEpics->epicsOutput.diagWord = diagWord;
        	  for(jj=0;jj<cdsPciModules.adcCount;jj++) {
-		if(adcRdTimeErr[jj] > MAX_ADC_WAIT_ERR_SEC)
+		if(adcinfo.adcRdTimeErr[jj] > MAX_ADC_WAIT_ERR_SEC)
 			pLocalEpics->epicsOutput.stateWord |= FE_ERROR_ADC;
-		adcRdTimeErr[jj] = 0;
+		adcinfo.adcRdTimeErr[jj] = 0;
 	  }
     }
 
@@ -914,7 +891,7 @@ udelay(1000);
 /// \> Cycle 19, write updated diag info to EPICS
 	if(cycleNum == HKP_DIAG_UPDATES)	
         {
-	  pLocalEpics->epicsOutput.userTime = usrHoldTime;
+	  pLocalEpics->epicsOutput.userTime = timeinfo.usrHoldTime;
 	  pLocalEpics->epicsOutput.ipcStat = ipcErrBits;
 	  if(ipcErrBits & 0xf) feStatus |= FE_ERROR_IPC;
 	  // Create FB status word for return to EPICS
@@ -930,14 +907,14 @@ udelay(1000);
   	  mxDiag = mxDiagR;
 	  if(mxStat != MX_OK)
 		feStatus |= FE_ERROR_DAQ;;
-	  usrHoldTime = 0;
+	  timeinfo.usrHoldTime = 0;
   	  if(pLocalEpics->epicsInput.overflowReset)
 	  {
                 if (pLocalEpics->epicsInput.overflowReset) {
                    for (ii = 0; ii < 16; ii++) {
                       for (jj = 0; jj < cdsPciModules.adcCount; jj++) {
-                         overflowAdc[jj][ii] = 0;
-                         overflowAdc[jj][ii + 16] = 0;
+                         adcinfo.overflowAdc[jj][ii] = 0;
+                         adcinfo.overflowAdc[jj][ii + 16] = 0;
 			pLocalEpics->epicsOutput.overflowAdcAcc[jj][ii] = 0;
 			pLocalEpics->epicsOutput.overflowAdcAcc[jj][ii + 16] = 0;
                       }
@@ -997,8 +974,8 @@ udelay(1000);
                 if (pLocalEpics->epicsOutput.overflowAdcAcc[jj][ii] > OVERFLOW_CNTR_LIMIT) {
 		   pLocalEpics->epicsOutput.overflowAdcAcc[jj][ii] = 0;
                 }
-		pLocalEpics->epicsOutput.overflowAdc[jj][ii] = overflowAdc[jj][ii];
-		overflowAdc[jj][ii] = 0;
+		pLocalEpics->epicsOutput.overflowAdc[jj][ii] = adcinfo.overflowAdc[jj][ii];
+		adcinfo.overflowAdc[jj][ii] = 0;
 
 	    }
 	  }
@@ -1045,49 +1022,16 @@ udelay(1000);
         rdtscl(cpuClock[CPU_TIME_CYCLE_END]);
 
 	/// \> Compute code cycle time diag information.
-	cycleTime = (cpuClock[CPU_TIME_CYCLE_END] - cpuClock[CPU_TIME_CYCLE_START])/CPURATE;
+    captureEocTiming(cycleNum, cycle_gps_time, &timeinfo, &adcinfo);
+	timeinfo.cycleTime = (cpuClock[CPU_TIME_CYCLE_END] - cpuClock[CPU_TIME_CYCLE_START])/CPURATE;
 	if (longestWrite2 < ((tempClock[3]-tempClock[2])/CPURATE)) longestWrite2 = (tempClock[3]-tempClock[2])/CPURATE;
-	// Hold the max cycle time over the last 1 second
-	if(cycleTime > timeHold) { 
-		timeHold = cycleTime;
-		timeHoldWhen = cycleNum;
-	}
-	// Hold the max cycle time since last diag reset
-	if(cycleTime > timeHoldMax) timeHoldMax = cycleTime;
-#if defined(SERVO64K) || defined(SERVO32K) || defined(SERVO16K)
-// This produces cycle time histogram in /proc file
-	{
-#if defined(SERVO64K) || defined(SERVO32K)
-		static const int nb = 31;
-#elif defined(SERVO16K)
-		static const int nb = 63;
-#endif
 
-		cycleHist[cycleTime<nb?cycleTime:nb]++;
-		cycleHistWhen[cycleTime<nb?cycleTime:nb] = cycleNum;
-	}
-#endif
-	adcHoldTime = (cpuClock[CPU_TIME_CYCLE_START] - adcTime)/CPURATE;
-	// Avoid calculating the max hold time for the first few seconds
-	if (cycleNum != 0 && (startGpsTime+3) < cycle_gps_time) {
-		if(adcHoldTime > adcHoldTimeMax) adcHoldTimeMax = adcHoldTime;
-		if(adcHoldTime < adcHoldTimeMin) adcHoldTimeMin = adcHoldTime;
-		adcHoldTimeAvg += adcHoldTime;
-		if (adcHoldTimeMax > adcHoldTimeEverMax)  {
-			adcHoldTimeEverMax = adcHoldTimeMax;
-			adcHoldTimeEverMaxWhen = cycle_gps_time;
-			//printf("Maximum adc hold time %d on cycle %d gps %d\n", adcHoldTimeMax, cycleNum, cycle_gps_time);
-		}
-		if (timeHoldMax > cpuTimeEverMax)  {
-			cpuTimeEverMax = timeHoldMax;
-			cpuTimeEverMaxWhen = cycle_gps_time;
-		}
-	}
-	adcTime = cpuClock[CPU_TIME_CYCLE_START];
+	adcinfo.adcHoldTime = (cpuClock[CPU_TIME_CYCLE_START] - adcinfo.adcTime)/CPURATE;
+	adcinfo.adcTime = cpuClock[CPU_TIME_CYCLE_START];
 	// Calc the max time of one cycle of the user code
 	// For IOP, more interested in time to get thru ADC read code and send to slave apps
-	usrTime = (cpuClock[CPU_TIME_USR_START] - cpuClock[CPU_TIME_CYCLE_START])/CPURATE;
-	if(usrTime > usrHoldTime) usrHoldTime = usrTime;
+	timeinfo.usrTime = (cpuClock[CPU_TIME_USR_START] - cpuClock[CPU_TIME_CYCLE_START])/CPURATE;
+	if(timeinfo.usrTime > timeinfo.usrHoldTime) timeinfo.usrHoldTime = timeinfo.usrTime;
 
         /// \> Update internal cycle counters
           cycleNum += 1;
diff --git a/src/fe/timing.c b/src/fe/timing.c
index de8f7e840..65e4ad0cb 100644
--- a/src/fe/timing.c
+++ b/src/fe/timing.c
@@ -100,6 +100,7 @@ inline void initializeDuotoneDiags(duotone_diag_t *dt_diag)
     dt_diag->dacDuoEnable = 0.0;
 
 }
+#endif
 
 inline void initializeTimingDiags(timing_diag_t *timeinfo)
 {
@@ -164,4 +165,3 @@ inline void captureEocTiming(int cycle, unsigned int cycle_gps, timing_diag_t *t
       }
     }
 }
-#endif
diff --git a/src/include/drv/iop_adc_functions.c b/src/include/drv/iop_adc_functions.c
index de4c7a278..9bf269856 100644
--- a/src/include/drv/iop_adc_functions.c
+++ b/src/include/drv/iop_adc_functions.c
@@ -161,6 +161,7 @@ inline int iop_adc_read (adcInfo_t *adcinfo,int cpuClk[])
 #ifdef TIME_MASTER
             pcieTimer->gps_time = timeSec;
             pcieTimer->cycle = cycleNum;
+            clflush_cache_range(&pcieTimer->gps_time,16);
 #endif
         } else {
             adcinfo->adcRdTime[jj] = adcinfo->adcWait;
-- 
GitLab