diff --git a/NEWS b/NEWS
index 43e8a4009dd23b0d7b361e0af899e2e4d53b6a91..638dde202a5b65fe9ff348b6c4c3b08faaf9ca60 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Changes for 3.5  (NOT YET RELEASED)
 - controller.c and moduleLoad.c now split into new files to clean out #defs:
 	- controllerIop.c and moduleLoadIop.c for IOP model builds.
 	- controllerApp.c and moduleLoadApp.c for user application model builds.
+	- controllerIopUser.c and controllerAppUser.c, which are user space equivalents.
 - Removed /proc entries from all FE code. This should alleviate issue with change to /proc
   in later Linux kernels.
 ==================================================================================================
diff --git a/src/fe/controllerApp.c b/src/fe/controllerApp.c
index 87994486226cf30c5828ea4c2fafb3eb04447cab..5ed2bb5799255a714449e3feede2e9db7c4b1998 100644
--- a/src/fe/controllerApp.c
+++ b/src/fe/controllerApp.c
@@ -11,7 +11,7 @@
 /*                                                                      */
 /*----------------------------------------------------------------------*/
 
-///	@file controller.c
+///	@file controllerApp.c
 ///	@brief Main scheduler program for compiled real-time kernal object. \n
 /// 	@detail More information can be found in the following DCC document:
 ///<	<a href="https://dcc.ligo.org/cgi-bin/private/DocDB/ShowDocument?docid=7688">T0900607 CDS RT Sequencer Software</a>
diff --git a/src/fe/controllerIopUser.c b/src/fe/controllerIopUser.c
index 9a7b7290908f00298196c44b317b6be5cc30e1f6..ba48cd7e4aa6965c0582dca0bc2673b278050162 100644
--- a/src/fe/controllerIopUser.c
+++ b/src/fe/controllerIopUser.c
@@ -109,6 +109,7 @@ 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 cycleOffset = 0;
 
 
 struct rmIpcStr *daqPtr;
@@ -469,18 +470,22 @@ usleep(1000);
   printf("*******************************\n");
   printf("*     Running on timer!       *\n");
   printf("*******************************\n");
+  int timeoff = BILLION-(60000000 * cycleOffset);
   /// Sync up to the 1Hz boundary
   do {
 	usleep(1);
-    	clock_gettime(CLOCK_MONOTONIC, &myTimer[0]);
-	cycleTime = myTimer[0].tv_nsec / 1000;
-  } while(cycleTime > 10);
-  timeSec = getGpsTimeProc() - 1;
+    	clock_gettime(CLOCK_REALTIME, &myTimer[0]);
+	cycleTime = myTimer[0].tv_nsec;
+  } while(cycleTime > timeoff && cycleTime < (timeoff - 10000));
+printf("cycle time = %d\n",cycleTime);
+  timeSec = getGpsTimeProc() ;
   startGpsTime = timeSec;
   pLocalEpics->epicsOutput.startgpstime = startGpsTime;
   printf("Triggered the ADC at %d and %d usec\n",timeSec,cycleTime);
   onePpsTime = cycleNum;
 
+  nextstep = timeoff + 20000;
+
 
   /// ******************************************************************************\n
   /// Enter the infinite FE control loop  ******************************************\n
@@ -510,10 +515,14 @@ usleep(1000);
 	    {
 		    for(ii=0;ii<IO_MEMORY_SLOT_VALS;ii++)
 		    {
-			ioMemData->iodata[jj][ioMemCntr].data[ii] = cycleNum/4;
+			ioMemData->iodata[jj][ioMemCntr].data[ii] = ioMemDataIop->iodata[jj][cycleNum].data[ii];
+			dWord[jj][ii] = ioMemData->iodata[jj][ioMemCntr].data[ii];
+			ioMemDataIop->iodata[jj][cycleNum].data[ii] = 0;
 		    }
 	    	ioMemData->iodata[jj][ioMemCntr].timeSec = timeSec;;
 	    	ioMemData->iodata[jj][ioMemCntr].cycle = cycleNum;
+		ioMemDataIop->gpsSecond = timeSec;
+		ioMemDataIop->cycleNum = cycleNum;
 	    }
 	    ioMemData->gpsSecond = timeSec;
 	  clock_gettime(CLOCK_MONOTONIC, &cpuClock[CPU_TIME_CYCLE_START]);
@@ -525,10 +534,13 @@ usleep(1000);
 	 	// Increment GPS second on cycle 0
           	timeSec ++;
           	pLocalEpics->epicsOutput.timeDiag = timeSec;
-		int pll = myTimer[0].tv_nsec / 1000;
+		int pll = myTimer[0].tv_nsec / 1000 + (1000000 - (timeoff / 1000));
+		pll %= 1000000;
 		if(pll > 500000) pdiff = (1000000 - pll) * -1 ; 
 		else pdiff = pll;
-          	pLocalEpics->epicsOutput.irigbTime = (pdiff + 11);
+          	pLocalEpics->epicsOutput.irigbTime = pdiff + 10;
+          	// pLocalEpics->epicsOutput.irigbTime = (pdiff + (timeoff / 1000) + 11) ;
+		cycle_gps_time = timeSec;
 	  }
 
 
@@ -907,7 +919,7 @@ usleep(1000);
         /// \> Update internal cycle counters
           cycleNum += 1;
           cycleNum %= CYCLE_PER_SECOND;
-	  nextstep = cycleNum * cyclensec;
+	  nextstep = ((cycleNum * cyclensec) + timeoff)% 1000000000;
 	  clock1Min += 1;
 	  clock1Min %= CYCLE_PER_MINUTE;
           if(subcycle == DAQ_CYCLE_CHANGE) 
diff --git a/src/fe/moduleLoadIop.c b/src/fe/moduleLoadIop.c
index 1cc05a9800a42bda2ad4a6328a5fa1c3344a761a..500cd36ef9e69a4454721080946ae68655bb0403 100644
--- a/src/fe/moduleLoadIop.c
+++ b/src/fe/moduleLoadIop.c
@@ -12,6 +12,7 @@ extern int mbuf_allocate_area(char *name, int size, struct file *file);
 extern void *fe_start(void *arg);
 extern int run_on_timer;
 extern char daqArea[2*DAQ_DCU_SIZE];           // Space allocation for daqLib buffers
+struct task_struct *sthread;
 
 
 // MAIN routine: Code starting point ****************************************************************
diff --git a/src/fe/rcguserIop.c b/src/fe/rcguserIop.c
index f95ec9254c1ce79ea29e7ccd512fcb6e17429d5b..a0c63d71d5e1c71bc5ce26de5c6d269815fecef5 100644
--- a/src/fe/rcguserIop.c
+++ b/src/fe/rcguserIop.c
@@ -22,6 +22,7 @@
 extern int fe_start();
 extern char daqArea[2*DAQ_DCU_SIZE];           // Space allocation for daqLib buffers
 extern char *addr;
+extern int cycleOffset;
 
 // Scan a double
 #if 0
@@ -57,7 +58,7 @@ void usage()
 int main (int argc, char **argv)
 {
  	int status;
-	int ii,jj,kk;		/// @param ii,jj,kk default loop counters
+	int ii,jj,kk,mm;		/// @param ii,jj,kk default loop counters
 	char fname[128];	/// @param fname[128] Name of shared mem area to allocate for DAQ data
 	int cards;		/// @param cards Number of PCIe cards found on bus
 	int adcCnt;		/// @param adcCnt Number of ADC cards found by slave model.
@@ -74,13 +75,19 @@ int main (int argc, char **argv)
 	char *sysname;
 	char shm_name[64];
 	int c;
+	char *modelname;
 
+	cycleOffset = 0;
 
-	while ((c = getopt(argc, argv, "m:help")) != EOF) switch(c) {
+	while ((c = getopt(argc, argv, "m:t:help")) != EOF) switch(c) {
 		case 'm':
 			sysname = optarg;
 			printf("sysname = %s\n",sysname);
 			break;
+		case 't':
+			cycleOffset = atoi(optarg);
+			printf("cycle offset = %d\n",cycleOffset);
+			break;
 		case 'help':
 		default:
 			usage();
@@ -90,7 +97,19 @@ int main (int argc, char **argv)
 	kk = 0;
 
 	jj = 0;
-	// printf("cpu clock %u\n",cpu_khz);
+  	int i = 0;
+	char *p = strtok (argv[0], "/");
+	char *array[5];
+
+    while (p != NULL)
+    {
+        array[i++] = p;
+        p = strtok (NULL, "/");
+    }
+	modelname = array[i-1];
+	sysname = array[i-1];
+	
+	printf("model name is %s \n",sysname);
 
 
 	sprintf(shm_name,"%s",sysname);
@@ -139,6 +158,17 @@ int main (int argc, char **argv)
         }
 	printf("GDSSM at 0x%lx\n",_gds_shm);
 
+// Open new IO shared memory in support of no hardware I/O
+        sprintf(shm_name, "%s_io_space", sysname);
+	findSharedMemory(shm_name);
+	_io_shm = (char *)addr;
+        if (_io_shm < 0) {
+                printf("mbuf_allocate_area() failed; ret = %d\n", _io_shm);
+                return -1;
+        }
+	printf("IO SPACE at 0x%lx\n",_io_shm);
+	ioMemDataIop = (volatile IO_MEM_DATA_IOP *)(((char *)_io_shm)) ;
+
 	// Find and initialize all PCI I/O modules *******************************************************
 	  // Following I/O card info is from feCode
 	  cards = sizeof(cards_used)/sizeof(cards_used[0]);
@@ -148,7 +178,7 @@ int main (int argc, char **argv)
           //return -1;
 	printf("Initializing PCI Modules for IOP\n");
 	for(jj=0;jj<cards;jj++)
-		printf("Card % type = %d\n",cdsPciModules.cards_used[jj].type);
+		printf("Card %d type = %d\n",jj,cdsPciModules.cards_used[jj].type);
 	cdsPciModules.adcCount = 0;
 	cdsPciModules.dacCount = 0;
 	cdsPciModules.dioCount = 0;
@@ -253,19 +283,26 @@ int main (int argc, char **argv)
 
 	// Print out all the I/O information
         printf("***************************************************************************\n");
-		// Master send module counds to SLAVE via ipc shm
-		ioMemData->totalCards = status;
-		ioMemData->adcCount = cdsPciModules.adcCount;
-		ioMemData->dacCount = cdsPciModules.dacCount;
-		ioMemData->bioCount = cdsPciModules.doCount;
-		// kk will act as ioMem location counter for mapping modules
-		kk = cdsPciModules.adcCount;
+	// Master send module counds to SLAVE via ipc shm
+	ioMemData->totalCards = status;
+	ioMemData->adcCount = cdsPciModules.adcCount;
+	ioMemData->dacCount = cdsPciModules.dacCount;
+	ioMemData->bioCount = cdsPciModules.doCount;
+	// kk will act as ioMem location counter for mapping modules
+	kk = cdsPciModules.adcCount;
 	printf("%d ADC cards found\n",cdsPciModules.adcCount);
 	for(ii=0;ii<cdsPciModules.adcCount;ii++)
         {
 		// MASTER maps ADC modules first in ipc shm for SLAVES
 		ioMemData->model[ii] = cdsPciModules.adcType[ii];
 		ioMemData->ipc[ii] = ii;	// ioData memory buffer location for SLAVE to use
+		ioMemDataIop->model[ii] = cdsPciModules.adcType[ii];
+		ioMemDataIop->ipc[ii] = ii;	// ioData memory buffer location for SLAVE to use
+		for(jj=0;jj<65536;jj++) {
+			for(mm=0;mm<32;mm++) {
+				ioMemDataIop->iodata[ii][jj].data[mm] = jj - 32767;
+			}
+		}
                 if(cdsPciModules.adcType[ii] == GSC_18AISS6C)
                 {
                         printf("\tADC %d is a GSC_18AISS6C module\n",ii);
diff --git a/src/include/controller.h b/src/include/controller.h
index 59aa9ba75fc4d4adba5a8a572cf124c8636be594..71e862443d2521d2583437b8b8d537d9f481a679 100644
--- a/src/include/controller.h
+++ b/src/include/controller.h
@@ -194,11 +194,13 @@ volatile char *_epics_shm;      ///< Ptr to EPICS shared memory area
 char *_ipc_shm;                 ///< Ptr to inter-process communication area 
 char *_daq_shm;                 ///< Ptr to frame builder comm shared mem area 
 char *_gds_shm;                 ///< Ptr to frame builder comm shared mem area 
+char *_io_shm;                 	///< Ptr to user space I/O area 
 int daq_fd;                     ///< File descriptor to share memory file 
 
 long daqBuffer;                 // Address for daq dual buffers in daqLib.c
 CDS_HARDWARE cdsPciModules;     // Structure of PCI hardware addresses
 volatile IO_MEM_DATA *ioMemData;
+volatile IO_MEM_DATA_IOP *ioMemDataIop;
 volatile int vmeDone = 0;       // Code kill command
 volatile int stop_working_threads = 0;
 
@@ -351,6 +353,18 @@ double dDacHistory[(MAX_DAC_MODULES * 16)][MAX_HISTRY];
 
 #endif
 
+typedef struct duotone_diag_t {
+  float adc[IOP_IO_RATE];            // Duotone timing diagnostic variables
+  float dac[IOP_IO_RATE];
+  float timeDac;
+  float timeAdc;
+  float totalAdc;
+  float meanAdc;
+  float totalDac;
+  float meanDac;
+  int dacDuoEnable;
+}duotone_diag_t;
+
 // /proc epics channel interface
 struct proc_epics {
 	char *name;
diff --git a/src/include/drv/cdsHardware.h b/src/include/drv/cdsHardware.h
index 8dd6ebe7be66cc4025d727daeb2a865562d85eed..392087f9161a3c2570aea7e1071f97c3e16aeb19 100644
--- a/src/include/drv/cdsHardware.h
+++ b/src/include/drv/cdsHardware.h
@@ -109,6 +109,28 @@ typedef struct IO_MEM_DATA{
 	unsigned int ipcDetect[2][8];
 }IO_MEM_DATA;
 
+typedef struct IO_MEM_DATA_IOP{
+	int gpsSecond;
+	int cycleNum;
+	int totalCards;
+	int adcCount;
+	int dacCount;
+	int bioCount;
+	int model[MAX_IO_MODULES];
+	int ipc[MAX_IO_MODULES];
+	int rfmCount;
+	long pci_rfm[MAX_RFM_MODULES];	/* Remapped addresses of RFM modules	*/
+	long pci_rfm_dma[MAX_RFM_MODULES];	/* Remapped addresses of RFM modules	*/
+        int dolphinCount;
+	volatile unsigned long *dolphinRead[4]; /* read and write Dolphin memory */
+	volatile unsigned long *dolphinWrite[4]; /* read and write Dolphin memory */
+	MEM_DATA_BLOCK iodata[6][65536];
+	// Combined DAC channels map; used to check on slaves DAC channel allocations
+	unsigned int dacOutUsed[MAX_DAC_MODULES][16];
+	unsigned int ipcDetect[2][8];
+}IO_MEM_DATA_IOP;
+
+
 
 // Timing control register definitions for use with Contec1616 control of timing slave.