diff --git a/install b/install
index a3b0af97b2defbcd18ecdeca7248ab556598088e..21459dd5787212365ad06124356ca8593e321b2c 100755
--- a/install
+++ b/install
@@ -35,6 +35,7 @@ site_letter=${ifo:0:1}
 upper_system=`echo $system | tr a-z A-Z`
 targetcpu=`grep TARGET_CPU ${MODEL_INC_DIR}/${system}.h | head -1 | awk '{print $3}'`
 cur_date=`date +%y%m%d_%H%M%S`
+ligo_group='advligorts'
 
 RTCDS=/opt/rtcds/${site,,*}/${ifo,,*}
 TARGET=$RTCDS/target/${system}
@@ -61,6 +62,8 @@ else
     cp -p ${EPICS_SRC_DIR}/config/${ifo}${upper_system}.txt  $RTCDS/chans/${upper_system}.txt
 fi
 
+chgrp $ligo_group $RTCDS/chans/filter_archive/$system
+
 ##########
 
 echo "Installing EPICS sequencer..."
@@ -74,8 +77,14 @@ mkdir -p $TARGET/{bin,scripts,logs}
 chmod 775 $TARGET/logs
 mkdir -p $RTCDS/chans/tmp
 chmod 775 $RTCDS/chans/tmp
+chgrp $ligo_group $RTCDS/chans/tmp
 mkdir -p $TARGET/${system}epics/burt
 chmod 775 $TARGET/${system}epics/burt
+
+mkdir -p $RTCDS/log/${system}/
+chgrp $ligo_group $RTCDS/log/${system}/
+chmod g+rwx $RTCDS/log/${system}/
+
 if [ -e $RTCDS/target_archive/${system}/${system}_$cur_date/${system}epics/burt ]; then
     cp -pr $RTCDS/target_archive/${system}/${system}_$cur_date/${system}epics/burt $TARGET/${system}epics
 fi
@@ -86,6 +95,8 @@ if test -e $TARGET/${system}epics/db/*/autoBurt.req; then
     mv -f $TARGET/${system}epics/db/*/autoBurt.req $TARGET/${system}epics || exit 3
 fi
 
+chgrp $ligo_group $TARGET/${system}epics/burt/
+
 ##########
 
 echo "Installing EPICS screens..."
@@ -170,7 +181,9 @@ if [ x$gds_node != "x" ]; then
     echo "Installing auto-generated DAQ config file..."
 
     mkdir -p  $RTCDS/chans/daq
-    mkdir -p  $RTCDS/chans/daq/archive
+    mkdir -p  $RTCDS/chans/daq/archive/
+    chgrp $ligo_group $RTCDS/chans/daq/archive/
+    chmod g+rwx  $RTCDS/chans/daq/archive/
     if test -e $RTCDS/chans/daq/${upper_system}.ini; then
         mv -f $RTCDS/chans/daq/${upper_system}.ini $RTCDS/chans/daq/archive/${upper_system}_${cur_date}.ini || exit 2
         #
diff --git a/src/daqd/net_writer.cc b/src/daqd/net_writer.cc
index 08fe705e7a488155faf8aaa2258b143da948c0a0..32aa1844c396d75f2a62f181d8f7b970962c0578 100644
--- a/src/daqd/net_writer.cc
+++ b/src/daqd/net_writer.cc
@@ -929,11 +929,6 @@ net_writer_c::consumer( )
                 char* data = buffptr->block_ptr( nb );
                 for ( int i = 0; i < num_channels; i++ )
                 {
-                    printf( "Byteswap %s rate=%d type=%d\n",
-                            channels[ i ].name,
-                            channels[ i ].sample_rate,
-                            channels[ i ].data_type );
-
                     if ( channels[ i ].bps == 4 )
                     {
                         for ( int j = 0; j < channels[ i ].sample_rate; j++ )
diff --git a/src/drv/CMakeLists.txt b/src/drv/CMakeLists.txt
index 52b2a08e7ede9ad031332553286d1c54649223c5..3cdf506e9093fb6ea6a73de33e7d522497d03804 100644
--- a/src/drv/CMakeLists.txt
+++ b/src/drv/CMakeLists.txt
@@ -4,7 +4,7 @@ add_subdirectory(gpstime/tests)
 add_subdirectory(gpstime/gps_module_utils)
 add_subdirectory(python)
 
-add_library(shmem STATIC shmem.c rfm.c)
+add_library(shmem STATIC shmem.c)
 target_include_directories(shmem PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
 target_include_directories(shmem PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/mbuf)
 target_compile_options(shmem PRIVATE -fPIC)
diff --git a/src/drv/gpstime/Makefile b/src/drv/gpstime/Makefile
index 8139d2d76b2d6e8e84cd79de924cc459cdbe40aa..ad71dbc77f4686daa925ae5217816ddeed70d848 100644
--- a/src/drv/gpstime/Makefile
+++ b/src/drv/gpstime/Makefile
@@ -26,6 +26,8 @@ INSTDIR		:= /lib/modules/$(KVER)/extra
 
 SYMVERSDIR	:= /var/cache/$(MODULENAME)
 
+SUDO_USER?= controls
+
 obj-m += $(MODULENAME).o
 $(MODULENAME)-y := $(MODULENAME)_core.o 
 $(MODULENAME)-y += ../../include/drv/spectracomGPS.o
@@ -57,7 +59,7 @@ install:
 	    rm -f /dev/$(MODULENAME) ; \
 	fi
 	mknod /dev/$(MODULENAME) c `grep $(MODULENAME) /proc/devices|awk '{print $$1}'` 0
-	chown controls /dev/$(MODULENAME)
+	chown $(SUDO_USER) /dev/$(MODULENAME)
 	# save Module.symvers if possible
 	mkdir -p $(SYMVERSDIR) || true
 	if [ -w $(SYMVERSDIR) ]; then cp Module.symvers $(SYMVERSDIR); fi
diff --git a/src/drv/mbuf/Makefile b/src/drv/mbuf/Makefile
index 254e96047b2757690cf7889301b9df5742996950..cd57f7d8d811a6413fa7d68534ebcf85b8792412 100644
--- a/src/drv/mbuf/Makefile
+++ b/src/drv/mbuf/Makefile
@@ -24,6 +24,8 @@ INSTDIR		:= /lib/modules/$(KVER)/extra
 
 SYMVERSDIR	:= /var/cache/$(MODULENAME)
 
+SUDO_USER?= controls
+
 ifeq ($(KERNELRELEASE),)
 #all:	$(MODULENAME)_test
 all:
@@ -50,7 +52,7 @@ install:
 	    rm -f /dev/$(MODULENAME) ; \
 	fi
 	mknod /dev/$(MODULENAME) c `grep $(MODULENAME) /proc/devices|awk '{print $$1}'` 0
-	chown controls /dev/$(MODULENAME)
+	chown $(SUDO_USER) /dev/$(MODULENAME)
 	# save Module.symvers if possible
 	mkdir -p $(SYMVERSDIR) || true
 	if [ -w $(SYMVERSDIR) ]; then cp Module.symvers $(SYMVERSDIR); fi
diff --git a/src/drv/rfm.c b/src/drv/rfm.c
deleted file mode 100644
index a2c1b414c54de4e45e666adccda675190e469883..0000000000000000000000000000000000000000
--- a/src/drv/rfm.c
+++ /dev/null
@@ -1,70 +0,0 @@
-///	@file src/drv/rfm.c
-/// 	@brief Routines for finding shared memory locations.
-
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <fcntl.h>
-#include <time.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <ctype.h>
-
-#include "mbuf/mbuf.h"
-
-#include "findSharedMemory.h"
-
-
-///  Search shared memory device file names in /rtl_mem_*
-///	@param[in] *sys_name	Name of system, required to attach shared memory.
-///	@return			Pointer to start of shared memory segment for this system.
-volatile void *
-findSharedMemory(char *sys_name)
-{
-    int ss_mb = 64;
-    if (!strcmp(sys_name, "ipc")) ss_mb = 32;
-    if (!strcmp(sys_name, "shmipc")) ss_mb = 16;
-
-    return findSharedMemorySize(sys_name, ss_mb);
-}
-
-volatile void *
-findSharedMemorySize(char *sys_name, int size_mb)
-{
-    volatile unsigned char *addr = 0;
-    char *s;
-    int fd;
-    char sys[128];
-    strcpy(sys, sys_name);
-    for(s = sys; *s; s++) *s=tolower(*s);
-
-
-    int size_bytes = size_mb*1024*1024;
-    printf("Making mbuff area %s with size %d\n", sys, size_bytes);
-
-    if ((fd = open ("/dev/mbuf", O_RDWR | O_SYNC)) < 0) {
-        fprintf(stderr, "Couldn't open /dev/mbuf read/write\n");
-        return 0;
-    }
-
-    struct mbuf_request_struct req = {0, {0,}};
-    req.size = size_bytes;
-    strcpy(req.name, sys);
-    if (ioctl (fd, IOCTL_MBUF_ALLOCATE, &req) < req.size) return NULL;
-
-    addr = (volatile unsigned char *)mmap(0, size_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-    if (addr == MAP_FAILED) {
-        printf("return was %d\n", errno);
-        perror("mmap");
-        _exit(-1);
-    }
-    printf(" %s mmapped address is %p\n", sys, addr);
-    return addr;
-}
-
diff --git a/src/drv/rts-logger/README.md b/src/drv/rts-logger/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ab9a5981718c65047f73bb8db9834543e49f6894
--- /dev/null
+++ b/src/drv/rts-logger/README.md
@@ -0,0 +1,49 @@
+# RTS Logger
+This is a kernel module that allows real time modules to log messages before AND after they are isolated on a core. It works by providing a print function exported by this module that other modules use to pass their messages for printing. Because this module is not CPU isolated it is free to pass those messages to the kernel message buffer. 
+
+# Example Use
+```c
+//At top of file, define the logging prefix (usually the module name) before logger include
+#define RTS_LOG_PREFIX "logger_test"
+#include "rts-logger.h"
+
+...
+
+//Log info message
+RTSLOG_INFO("There are %d DACs used by the model.\n", num_dacs);
+
+if(some_check < 2)
+{
+    RTSLOG_ERROR("There was a fatal issue!\n");
+    pLocalEpics->epicsOutput.fe_status = DAQ_INIT_ERROR;
+    wait_for_exit_signal();
+    atomic_set(&g_atom_has_exited, 1);
+}
+
+```
+
+### Output (dmesg) Would Look Like
+```
+[17764.891415] logger_test: INFO - There are 2 DACs used by the model.
+[17764.896527] logger_test: ERROR - There was a fatal issue!
+```
+
+### journalctl
+You can follow all kernel messages using the command:
+```
+sudo journalctl -t kernel -f
+```
+
+If you wanted to filter for the realtime module named `x1tst`, you can use `grep`
+```
+sudo journalctl -t kernel -f | grep x1tst
+```
+
+# Structure
+```
+include/    # Contains shared header file that other modules would use for logger declarations.
+module/     # Main logger module implementation.
+test/       # Test module that spams the logger from a couple of threads.
+userspace/  # Userspace implementation for the logger
+```
+
diff --git a/src/drv/rts-logger/module/Makefile b/src/drv/rts-logger/module/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..3454b02453fd7516568e9a03cfe0a77730f2f67a
--- /dev/null
+++ b/src/drv/rts-logger/module/Makefile
@@ -0,0 +1,19 @@
+mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
+mkfile_dir := $(dir $(mkfile_path))
+
+# obj-m specifie we're a kernel module.
+obj-m += rts-logger.o
+
+EXTRA_CFLAGS += -I$(mkfile_dir)/../../../include/ -I$(mkfile_dir) 
+
+# Set the path to the Kernel build utils.
+KBUILD=/lib/modules/$(shell uname -r)/build/
+ 
+default:
+	$(MAKE) -C $(KBUILD) M=$(PWD) modules
+
+clean:
+	$(MAKE) -C $(KBUILD) M=$(PWD) clean
+
+menuconfig:
+	$(MAKE) -C $(KBUILD) M=$(PWD) menuconfig
diff --git a/src/drv/rts-logger/module/rts-logger.c b/src/drv/rts-logger/module/rts-logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..49280fbe8b429a50b17975617a27ee98b672a741
--- /dev/null
+++ b/src/drv/rts-logger/module/rts-logger.c
@@ -0,0 +1,341 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>  // for threads
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/llist.h>
+
+#include "drv/rts-logger.h"
+
+//  Define the module metadata.
+#define MODULE_NAME "rts_logger"
+MODULE_AUTHOR("Ezekiel Dohmen ezekiel.dohmen@caltech.edu");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("A logging kernel module for isolated real time LIGO kernel modules");
+MODULE_VERSION("0.1");
+
+//
+// Global options
+//
+#define MAX_MSG_TO_READ_AT_ONCE 1024
+#define MAX_SYSFS_NUM_IN_SZ 12 //Max sized string we will take as input from sysfs
+
+
+//
+// Start Module Parameters
+//
+int MP_DEFAULT_LOG_LEVEL = RTSLOG_LOG_LEVEL_INFO;
+module_param(MP_DEFAULT_LOG_LEVEL, int, S_IRUSR);
+
+//Will get set to MP_DEFAULT_LOG_LEVEL on init 
+//but can be reset with sysfs "debug_level"
+atomic_t g_log_level = ATOMIC_INIT(0);
+
+
+
+//
+// Input message buffer locking and stats
+//
+#define MAX_BUFFERED_MSG (1<<12) //(4096) This must be a power of 2, because we are using a fast mod below
+#define MAX_MSG_LENGTH 2048
+static char print_buffer[MAX_BUFFERED_MSG][MAX_MSG_LENGTH];
+volatile static bool ready_for_print[MAX_BUFFERED_MSG];
+
+static int cur_empty_index = 0;
+static int next_to_print = 0;
+atomic_t g_num_filled = ATOMIC_INIT(0); 
+spinlock_t g_check_and_dec_lock;
+
+static int num_dropped_no_space = 0;
+atomic_t g_dump_to_dmesg = ATOMIC_INIT(1);
+
+
+
+//
+// Sysfs data
+//
+static ssize_t sysfs_no_space_dropped(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
+static ssize_t sysfs_dump_to_dmesg_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
+static ssize_t sysfs_dump_to_dmesg_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);
+static ssize_t sysfs_debug_level_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
+static ssize_t sysfs_debug_level_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);
+
+/* sysfs related structures */
+static struct kobject *g_sysfs_dir = NULL;
+
+/* individual sysfs debug attributes */
+static struct kobj_attribute sysfs_no_space_dropped_attr = __ATTR(no_space_dropped, 0444, sysfs_no_space_dropped, NULL);
+static struct kobj_attribute sysfs_dump_to_dmesg_attr = __ATTR(dump_to_dmesg, 0644, sysfs_dump_to_dmesg_show, sysfs_dump_to_dmesg_store);
+static struct kobj_attribute sysfs_debug_level_attr = __ATTR(debug_level, 0644, sysfs_debug_level_show, sysfs_debug_level_store);
+
+/* group attributes together for bulk operations */
+static struct attribute *g_sysfs_fields[] = {
+        &sysfs_no_space_dropped_attr.attr,
+        &sysfs_dump_to_dmesg_attr.attr,
+        &sysfs_debug_level_attr.attr,
+        NULL,
+};
+
+static struct attribute_group g_attr_group = {
+        .attrs = g_sysfs_fields,
+};
+
+
+
+//
+// Printer thread
+//
+static struct task_struct *printer_thread;
+static char thread_name[] = {"printer_thread"};
+
+void rtslog_print(int level, const char * fmt, ...)
+{
+    int  index;
+    va_list args;
+
+    if (level < atomic_read(&g_log_level) ) return;
+
+    va_start(args, fmt);
+
+
+    spin_lock(&g_check_and_dec_lock); //Lock so we can get our index
+
+    //If we are full return
+    if(atomic_read(&g_num_filled) == MAX_BUFFERED_MSG)
+    {
+        ++num_dropped_no_space;
+        spin_unlock(&g_check_and_dec_lock);
+        return;
+    }
+
+    index = cur_empty_index;
+    cur_empty_index = ((cur_empty_index + 1) & (MAX_BUFFERED_MSG - 1));
+    atomic_inc(&g_num_filled); //If we have two threads that mark ready, but have not finished writing to the print buffer we have an issue
+    spin_unlock(&g_check_and_dec_lock); //We unlock here
+
+    vsnprintf(print_buffer[index], MAX_MSG_LENGTH, fmt, args);
+    ready_for_print[index] = 1;
+
+    va_end(args);
+
+}
+EXPORT_SYMBOL(rtslog_print);
+
+int rtslog_get_num_dropped_no_space( void )
+{
+    return num_dropped_no_space;
+}
+EXPORT_SYMBOL(rtslog_get_num_dropped_no_space);
+
+int rtslog_get_num_ready_to_print( void)
+{
+    return atomic_read(&g_num_filled);
+}
+EXPORT_SYMBOL(rtslog_get_num_ready_to_print);
+
+int rtslog_set_log_level(int new_level)
+{
+    if(new_level < RTSLOG_LOG_LEVEL_DEBUG || new_level > RTSLOG_LOG_LEVEL_ERROR) return 0;
+
+    atomic_set(&g_log_level, new_level);
+    return 1;
+}
+EXPORT_SYMBOL(rtslog_set_log_level);
+
+int rtslog_get_log_level( void )
+{
+    return atomic_read(&g_log_level);
+}
+EXPORT_SYMBOL(rtslog_get_log_level);
+
+int printer_thread_fn( void * pv ) 
+{
+    int num_read = 0;
+    while(!kthread_should_stop()) {
+
+        while(!kthread_should_stop() && atomic_read(&g_num_filled) > 0 && num_read < MAX_MSG_TO_READ_AT_ONCE)
+        {
+
+            //If num filled is ready but ready_for_print is not, we are waiting for 
+            //the vsnprintf to complete, which will be fast
+            if(ready_for_print[next_to_print] == 0)
+            {
+                schedule();
+                num_read++;
+                continue;
+            }
+
+
+            if ( atomic_read(&g_dump_to_dmesg) )
+            {
+                printk("%s", print_buffer[next_to_print]);
+            }
+
+            ready_for_print[next_to_print] = 0;
+            next_to_print = ((next_to_print + 1) & (MAX_BUFFERED_MSG - 1));
+            atomic_dec(&g_num_filled);
+            num_read++;
+        }
+        num_read = 0;
+
+        // If there are no mesages ready for printing, we can give up the CPU
+        // for a while
+        if( atomic_read(&g_num_filled) == 0)
+            usleep_range(1000, 2500);
+        else //We have more messages
+            schedule();
+    }
+    return 0;
+}
+
+
+static int __init logger_init(void)
+{
+
+    int ret;
+
+    // Set the default log level and other defaults
+    atomic_set(&g_log_level, (int)MP_DEFAULT_LOG_LEVEL);
+    spin_lock_init(&g_check_and_dec_lock);
+    memset((void*)ready_for_print, 0, sizeof(bool) * MAX_BUFFERED_MSG);
+
+
+    //
+    // Sysfs init
+    //
+    g_sysfs_dir = kobject_create_and_add("rts_logger", kernel_kobj);
+    if (g_sysfs_dir == NULL) {
+        printk(KERN_ERR " - " MODULE_NAME "Could not create /sys/kernel/rts_logger directory!\n");
+        return -EPERM;
+    }
+
+    if (sysfs_create_group(g_sysfs_dir, &g_attr_group) != 0) {
+        printk(KERN_ERR " - " MODULE_NAME "Could not create /sys/kernel/rts_logger/... fields!\n");
+        ret = -EPERM;
+        goto out_remove_sysfs;
+    }
+
+
+    //
+    // Start the printer kthread
+    printer_thread = kthread_run(printer_thread_fn, NULL, thread_name);
+    if( !printer_thread )
+    {
+        printk(KERN_ERR " - " MODULE_NAME " - Could not create the reader kthread.\n");
+        return -1;
+    }
+
+
+
+
+    printk(MODULE_NAME " - Successfully started the " MODULE_NAME " kernel module.\n");
+    return 0;
+
+
+    // error case cleanup
+    out_remove_sysfs:
+        kobject_del(g_sysfs_dir);
+
+    return ret;
+ 
+}
+
+static void __exit logger_exit(void)
+{
+    //Stop the printer thread
+    kthread_stop(printer_thread);
+
+    //Clean up sysfs
+    sysfs_remove_group(g_sysfs_dir, &g_attr_group);
+    kobject_del(g_sysfs_dir);
+
+    printk(MODULE_NAME " - Shutting down.\n");
+    return;
+}
+
+module_init(logger_init);
+module_exit(logger_exit);
+
+
+
+
+//
+// Sysfs related data/code
+//
+
+bool parseInt(const char *buf, size_t count, int * result, int * error_code)
+{
+    char localbuff[MAX_SYSFS_NUM_IN_SZ] = {0,};
+
+    if(count > MAX_SYSFS_NUM_IN_SZ)
+    {
+        *error_code = -E2BIG;
+        return false;
+    }
+
+    memcpy(localbuff, buf, count);
+    localbuff[count] = '\0';
+
+    if ((*error_code = kstrtoint(localbuff, 10, result)) != 0) {
+        return false ;
+    }
+
+    return true;
+
+}
+
+
+static ssize_t sysfs_no_space_dropped(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+    return sprintf(buf, "%d\n", num_dropped_no_space);
+}
+
+static ssize_t sysfs_dump_to_dmesg_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+    return sprintf(buf, "%d\n", atomic_read(&g_dump_to_dmesg) );
+}
+
+static ssize_t sysfs_dump_to_dmesg_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
+{
+    int enabled, res;
+
+    if( !parseInt(buf, count, &enabled, &res) ) return res;
+
+    if(enabled >= 1) 
+        atomic_set(&g_dump_to_dmesg, 1); 
+    else
+        atomic_set(&g_dump_to_dmesg, 0);
+
+    return (ssize_t) count;
+}
+
+static ssize_t sysfs_debug_level_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+    return sprintf(buf, "%d\n", atomic_read(&g_log_level));
+}
+
+static ssize_t sysfs_debug_level_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
+{
+    int new_level, res;
+
+    if( !parseInt(buf, count, &new_level, &res) ) return res;
+
+    if(new_level < RTSLOG_LOG_LEVEL_DEBUG || new_level > RTSLOG_LOG_LEVEL_ERROR) return -EINVAL;
+
+    atomic_set(&g_log_level, new_level);
+
+    return (ssize_t) count;
+
+}
+
+
+
+
+
+
+
+
+
diff --git a/src/drv/rts-logger/test/Makefile b/src/drv/rts-logger/test/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..dedd9beaa666431d27245db783b3eeafd0509572
--- /dev/null
+++ b/src/drv/rts-logger/test/Makefile
@@ -0,0 +1,21 @@
+mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
+mkfile_dir := $(dir $(mkfile_path))
+
+KBUILD_EXTRA_SYMBOLS += $(mkfile_dir)/../module/Module.symvers
+
+EXTRA_CFLAGS += -I$(mkfile_dir)/../../../include/
+
+# obj-m specifie we're a kernel module.
+obj-m += logger-test.o
+
+# Set the path to the Kernel build utils.
+KBUILD=/lib/modules/$(shell uname -r)/build/
+ 
+default:
+	$(MAKE) -C $(KBUILD) M=$(PWD) modules
+
+clean:
+	$(MAKE) -C $(KBUILD) M=$(PWD) clean
+
+menuconfig:
+	$(MAKE) -C $(KBUILD) M=$(PWD) menuconfig
diff --git a/src/drv/rts-logger/test/logger-test.c b/src/drv/rts-logger/test/logger-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..9cd5c89ec766a8733a40f31b4f4698e99032852f
--- /dev/null
+++ b/src/drv/rts-logger/test/logger-test.c
@@ -0,0 +1,92 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>  // for threads
+
+//  Define the module metadata.
+#define MODULE_NAME "logger_test"
+MODULE_AUTHOR("Ezekiel Dohmen ezekiel.dohmen@caltech.edu");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("A logging kernel module for isolated real time LIGO kernel modules");
+MODULE_VERSION("0.1");
+
+#define RTS_LOG_PREFIX MODULE_NAME
+#include "drv/rts-logger.h"
+
+int MP_JUST_QUERY_NUM_READY = 0;
+module_param(MP_JUST_QUERY_NUM_READY, int, S_IRUSR);
+
+
+static struct task_struct *g_thread;
+static char thread_name[] = {"test thread"};
+
+int thread_fn( void * pv ) 
+{
+    while(!kthread_should_stop()) {
+        
+         RTSLOG_INFO("Thread print.\n");
+         usleep_range(100, 500);
+
+        schedule();
+    }
+    return 0;
+}
+
+
+static int __init logger_init(void)
+{
+
+    if (MP_JUST_QUERY_NUM_READY == 1)
+    {
+         printk(MODULE_NAME " - rtslog_get_num_ready_to_print() : %d\n", rtslog_get_num_ready_to_print());
+         return -5;
+    }
+
+    
+    g_thread = kthread_run(thread_fn, NULL, thread_name);
+    if( !g_thread )
+    {
+        printk(KERN_ERR " - " MODULE_NAME " - Could not create the reader kthread.\n");
+        return -5;
+    }
+
+    int i;
+    for(i=0; i<500; ++i)
+    {
+        RTSLOG_INFO("test %d\n", i);
+        RTSLOG_DEBUG("we should not see this message\n");
+        usleep_range(100, 500);
+    }
+
+    printk(MODULE_NAME " - Successfully started the " MODULE_NAME " kernel module.\n");
+
+
+    return 0;
+}
+
+static void __exit logger_exit(void)
+{
+    kthread_stop(g_thread);
+
+    RTSLOG_RAW("RAW Test\n");
+    RTSLOG_RAW("RAW Test with arg (%s)\n", "arg");
+    RTSLOG_DEBUG("DEBUG Test\n");
+    RTSLOG_DEBUG("DEBUG Test with arg (%s)\n", "arg");
+    RTSLOG_INFO("INFO Test\n");
+    RTSLOG_INFO("INFO Test with arg (%s)\n", "arg");
+    RTSLOG_WARN("WARNING Test\n");
+    RTSLOG_WARN("WARNING Test with arg (%s)\n", "arg");
+    RTSLOG_ERROR("ERROR Test\n");
+    RTSLOG_ERROR("ERROR Test with arg (%s)\n", "arg");
+
+    usleep_range(10000, 10001);
+
+    printk(MODULE_NAME " - There were %d dropped messages because of space.\n", rtslog_get_num_dropped_space() );
+    printk(MODULE_NAME " - rtslog_get_num_ready_to_print() : %d\n", rtslog_get_num_ready_to_print());
+
+    printk(MODULE_NAME " - Shutting down.\n");
+    return;
+}
+
+module_init(logger_init);
+module_exit(logger_exit);
diff --git a/src/drv/rts-logger/userspace/usp-rts-logger.c b/src/drv/rts-logger/userspace/usp-rts-logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..63273f4cd982719cd4c5a928f6d2f27313a4ed9e
--- /dev/null
+++ b/src/drv/rts-logger/userspace/usp-rts-logger.c
@@ -0,0 +1,48 @@
+#include "drv/rts-logger.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdatomic.h>
+
+atomic_int g_usp_rtslog_level = ATOMIC_VAR_INIT( RTSLOG_LOG_LEVEL_INFO );
+
+
+void rtslog_print(int level, const char * fmt, ...)
+{
+    va_list args;
+
+    if(level < g_usp_rtslog_level) return;
+
+    va_start(args, fmt);
+
+    vprintf(fmt, args);
+
+    va_end(args);
+
+}
+
+int rtslog_set_log_level(int new_level)
+{
+    if(new_level < RTSLOG_LOG_LEVEL_DEBUG || new_level > RTSLOG_LOG_LEVEL_ERROR) return 0;
+
+    atomic_store(&g_usp_rtslog_level, new_level);
+    return 1;
+
+}
+
+int rtslog_get_log_level( void )
+{
+    return atomic_load(&g_usp_rtslog_level);
+}
+
+
+int rtslog_get_num_dropped_space ( void )
+{
+    return 0;
+}
+
+int rtslog_get_num_ready_to_print( void )
+{
+    return 0;
+}
+
diff --git a/src/drv/shmem.c b/src/drv/shmem.c
index a77c05336962fb87674f76c35b751758219a2d50..597618a3d856d9abd469592acae5e019decc262e 100644
--- a/src/drv/shmem.c
+++ b/src/drv/shmem.c
@@ -12,7 +12,7 @@
 #include <unistd.h>
 
 #include "drv/shmem.h"
-#include "mbuf.h"
+#include "../drv/mbuf/mbuf.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -156,7 +156,7 @@ shmem_open_mbuf( const char* sys_name, size_t size_mb )
 
     if ( buffer_len < (int)req_size )
     {
-        fprintf( stderr, "Buffer length was less than the requested size\n" );
+        fprintf( stderr, "Returned buffer length (%d) was less than the requested size (%d)\n", buffer_len, req_size );
         goto cleanup;
     }
     intl->req_size_ = req_size;
@@ -296,7 +296,11 @@ shmem_open( const char* sys_name, size_t size_mb )
         return shmem_open_posix( sys_name + strlen( SHMEM_POSIX_PREFIX ),
                                  size_mb );
     }
+#if DEFAULT_TO_SHMEM_BUFFERS
+    return shmem_open_posix( sys_name, size_mb );
+#else //We default to mbuf buffers for now
     return shmem_open_mbuf( sys_name, size_mb );
+#endif
 }
 
 void
@@ -344,4 +348,4 @@ shmem_wrap_memory_arbitrary( volatile void* data,
 
 #ifdef __cplusplus
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/src/epics/edcu/CMakeLists.txt b/src/epics/edcu/CMakeLists.txt
index 3863c819c1a3ff2a4b02ca46de1e712e230f3885..7ceb0f333a9b5a47a49aaae9034cba5485f5931a 100644
--- a/src/epics/edcu/CMakeLists.txt
+++ b/src/epics/edcu/CMakeLists.txt
@@ -1,12 +1,7 @@
 if (Boost_FOUND)
 
     add_executable(standalone_edc
-            standalone_edcu.cc
-            ${CMAKE_CURRENT_SOURCE_DIR}/../../drv/rfm.c)
-    #target_compile_options(standalone_edc PRIVATE -fsanitize=address)
-    #target_link_libraries(standalone_edc PRIVATE asan)
-    #target_compile_options(standalone_edc PRIVATE
-    #        -fstack-protector -fstack-protector-strong)
+            standalone_edcu.cc)
     target_include_directories(standalone_edc PUBLIC
             "${CMAKE_CURRENT_SOURCE_DIR}/../../include"
             "${CMAKE_CURRENT_SOURCE_DIR}/../../include/drv"
@@ -18,7 +13,8 @@ if (Boost_FOUND)
             pv::simple_pv
             ${Boost_LIBRARIES}
             ${CMAKE_THREAD_LIBS_INIT}
-            driver::gpsclock)
+            driver::gpsclock
+            driver::shmem)
     target_requires_cpp11(standalone_edc PUBLIC)
 
     configure_file(test/epics_test.py ${CMAKE_CURRENT_BINARY_DIR}/epics_test.py COPYONLY)
@@ -33,4 +29,4 @@ if (Boost_FOUND)
 
 else(Boost_FOUND)
     message(WARNING "The standalone_edc will not be build as boost was not found")
-endif (Boost_FOUND)
\ No newline at end of file
+endif (Boost_FOUND)
diff --git a/src/epics/edcu/standalone_edcu.cc b/src/epics/edcu/standalone_edcu.cc
index f453d9cba9644ca458672d399a613d6672aa99f3..d040034169cd4eee290c1df73b4b99e1c070dced 100644
--- a/src/epics/edcu/standalone_edcu.cc
+++ b/src/epics/edcu/standalone_edcu.cc
@@ -47,11 +47,10 @@ of this distribution.
 #include <rapidjson/writer.h>
 #include <rapidjson/stringbuffer.h>
 
-extern "C" {
-#include "findSharedMemory.h"
+#include "drv/shmem.h"
 #include "crc.h"
 #include "param.h"
-}
+
 #include "cadef.h"
 #include "fb.h"
 #include "../../drv/gpstime/gpstime.h"
@@ -309,10 +308,6 @@ int gpstime_index = -1;
 int internal_channel_count = 0;
 
 daqd_c                           daqd_edcu1;
-static struct rmIpcStr*          dipc;
-static struct rmIpcStr*          sipc;
-static char*                     shmDataPtr;
-static struct cdsDaqNetGdsTpNum* shmTpTable;
 static const int                 buf_size = DAQ_DCU_BLOCK_SIZE;
 static const int                 header_size =
     sizeof( struct rmIpcStr ) + sizeof( struct cdsDaqNetGdsTpNum );
@@ -339,7 +334,12 @@ public:
     {
         if ( sync_source != nullptr && strcmp( sync_source, "-" ) != 0 )
         {
-            auto sync_addr = (void*)findSharedMemory( (char*)sync_source );
+            sipc_shm_ptr_ = std::unique_ptr< shmem::shmem >
+                            (
+                              new shmem::shmem(sync_source, DEFAULT_SHMEM_ALLOC_SIZE_MB)
+                            );
+            auto sync_addr = sipc_shm_ptr_->mapping<char>();
+
             sipc_ = (volatile struct rmIpcStr*)( (char*)sync_addr +
                                                  CDS_DAQ_NET_IPC_OFFSET );
         }
@@ -389,6 +389,7 @@ public:
 private:
     int                               cycle_{ 0 };
     std::unique_ptr< GPS::gps_clock > gps_clock_{ nullptr };
+    std::unique_ptr< shmem::shmem >  sipc_shm_ptr_;
     volatile struct rmIpcStr*         sipc_{ nullptr };
 };
 
@@ -1104,7 +1105,7 @@ copyDaqData( char* daqData )
 
 // **************************************************************************
 void
-edcuWriteData( int daqBlockNum, unsigned long cycle_gps_time, int dcuId )
+edcuWriteData( int daqBlockNum, unsigned long cycle_gps_time, int dcuId, shmem::shmem & daq_shmem)
 // **************************************************************************
 {
     char* daqData;
@@ -1119,10 +1120,19 @@ edcuWriteData( int daqBlockNum, unsigned long cycle_gps_time, int dcuId )
     edcuLoadSpecial( gpstime_index, static_cast< int >( daqd_edcu1.gpsTime ) );
 
     buf_size = DAQ_DCU_BLOCK_SIZE;
-    daqData = (char*)( shmDataPtr + ( buf_size * daqBlockNum ) );
+    daqData = (char*)( (daq_shmem.mapping<char>() + CDS_DAQ_NET_DATA_OFFSET)
+                       + ( buf_size * daqBlockNum )
+                     );
+
 
     unsigned int data_size = copyDaqData( daqData );
-    ;
+
+	struct rmIpcStr* dipc = (struct rmIpcStr*)( daq_shmem.mapping<char>() + 
+												CDS_DAQ_NET_IPC_OFFSET ); 
+
+	struct cdsDaqNetGdsTpNum* shmTpTable = (struct cdsDaqNetGdsTpNum*)( daq_shmem.mapping<char>() +
+                                              CDS_DAQ_NET_GDS_TP_TABLE_OFFSET );
+
 
     dipc->dcuId = dcuId;
     dipc->crc = daqFileCrc;
@@ -1137,37 +1147,6 @@ edcuWriteData( int daqBlockNum, unsigned long cycle_gps_time, int dcuId )
     dipc->cycle = daqBlockNum; // Triggers sending of data by mx_stream.
 }
 
-// **************************************************************************
-EdcuClock
-edcuInitialize( const std::string& mbuf_name,
-                const char*        sync_source,
-                int                delay_ms )
-// **************************************************************************
-{
-    void* sync_addr = nullptr;
-    sipc = nullptr;
-
-    const std::string   daq( "_daq" );
-    std::vector< char > shmem_fname;
-    shmem_fname.reserve( mbuf_name.size( ) + daq.size( ) + 1 );
-    std::copy( mbuf_name.begin( ),
-               mbuf_name.end( ),
-               std::back_inserter( shmem_fname ) );
-    std::copy( daq.begin( ), daq.end( ), std::back_inserter( shmem_fname ) );
-    shmem_fname.emplace_back( '\0' );
-
-    // Find start of DAQ shared memory
-    void* dcu_addr = (void*)findSharedMemory( shmem_fname.data( ) );
-
-    // Find the IPC area to communicate with mxstream
-    dipc = (struct rmIpcStr*)( (char*)dcu_addr + CDS_DAQ_NET_IPC_OFFSET );
-    // Find the DAQ data area.
-    shmDataPtr = (char*)( (char*)dcu_addr + CDS_DAQ_NET_DATA_OFFSET );
-    shmTpTable = (struct cdsDaqNetGdsTpNum*)( (char*)dcu_addr +
-                                              CDS_DAQ_NET_GDS_TP_TABLE_OFFSET );
-
-    return EdcuClock( sync_source, delay_ms );
-}
 
 std::pair< std::string, int >
 parse_address( const std::string& str )
@@ -1321,7 +1300,14 @@ main( int argc, char* argv[] )
     // EDCU STUFF
     // ********************************************************************************************************
 
-    auto clock = edcuInitialize( daqsharedmemname, sync_source, delay_ms );
+    std::string model_name(sync_source);
+    std::transform(model_name.begin(), model_name.end(), model_name.begin(), ::tolower);
+	EdcuClock clock( model_name.c_str(), delay_ms );
+    std::string shmmem_name(daqsharedmemname);
+    std::transform(shmmem_name.begin(), shmmem_name.end(), shmmem_name.begin(), ::tolower);
+	shmem::shmem daq_shmem = shmem::shmem(shmmem_name + "_daq", DEFAULT_SHMEM_ALLOC_SIZE_MB);
+
+
     edcuCreateChanList( daqd_edcu1, daqFile, &daqFileCrc, internal_channels );
     std::cout << "The edc dcuid = " << daqd_edcu1.dcuid << "\n";
 
@@ -1386,8 +1372,10 @@ main( int argc, char* argv[] )
         daqd_edcu1.gpsTime = now.sec;
         daqd_edcu1.epicsSync = clock.cycle( );
 
-        edcuWriteData(
-            daqd_edcu1.epicsSync, daqd_edcu1.gpsTime, daqd_edcu1.dcuid );
+        edcuWriteData(daqd_edcu1.epicsSync, 
+                      daqd_edcu1.gpsTime, 
+                      daqd_edcu1.dcuid, 
+                      daq_shmem );
 
         transmit_time = transmit_time + time_step;
 
diff --git a/src/epics/seq/sdf_monitor.c b/src/epics/seq/sdf_monitor.c
index cab7c70b588da56043a098d4ebe373d13825ea39..ea52db5e765b92e00e9043313d1ccef2b516ee53 100644
--- a/src/epics/seq/sdf_monitor.c
+++ b/src/epics/seq/sdf_monitor.c
@@ -1,6 +1,6 @@
-///	@file /src/epics/seq/sdf_monitor.c
-///	@brief Contains required 'main' function to startup EPICS sequencers, along with supporting routines. 
-///<		This code is taken from EPICS example included in the EPICS distribution and modified for LIGO use.
+/// @file /src/epics/seq/sdf_monitor.c
+/// @brief Contains required 'main' function to startup EPICS sequencers, along with supporting routines. 
+///<        This code is taken from EPICS example included in the EPICS distribution and modified for LIGO use.
 
 /********************COPYRIGHT NOTIFICATION**********************************
 This software was developed under a United States Government license
@@ -39,45 +39,46 @@ of this distribution.
 
 #include <daqmap.h>
 #include <param.h>
-// #include "fm10Gen.h"
-#include "findSharedMemory.h"
+#include "drv/shmem.h"
 #include "cadef.h"
 #include "fb.h"
 #include "../../drv/gpstime/gpstime.h"
 #include "util/user/check_file_crc.h"
 
-#define GSDF_MAX_CHANS	30000
-// Gloabl variables		****************************************************************************************
-char timechannel[256];		///< Name of the GPS time channel for timestamping.
-char reloadtimechannel[256];	///< Name of EPICS channel which contains the BURT reload requests.
+#define GSDF_MAX_CHANS  30000
+// Gloabl variables     ****************************************************************************************
+char timechannel[256];      ///< Name of the GPS time channel for timestamping.
+char reloadtimechannel[256];    ///< Name of EPICS channel which contains the BURT reload requests.
 struct timespec t;
 char logfilename[128];
 char logfiledir[128];
 char gsdflogfilename[128];
 char statelogfilename[128];
 unsigned char naughtyList[GSDF_MAX_CHANS][64];
+shmem_handle g_dcu_shm_handle = NULL;
 
-// Function prototypes		****************************************************************************************
+
+// Function prototypes      ****************************************************************************************
 void getSdfTime(char *);
 void logFileEntry(char *);
 
 unsigned long daqFileCrc;
 typedef struct gsdf_c {
-	int num_chans;
-	int con_chans;
-	int val_events;
-	int con_events;
-	double channel_value[GSDF_MAX_CHANS];
-	char channel_name[GSDF_MAX_CHANS][64];
-	char channel_string[GSDF_MAX_CHANS][64];
-	int channel_status[GSDF_MAX_CHANS];
-	int channel_type[GSDF_MAX_CHANS];
-	long gpsTime;
-	long epicsSync;
+    int num_chans;
+    int con_chans;
+    int val_events;
+    int con_events;
+    double channel_value[GSDF_MAX_CHANS];
+    char channel_name[GSDF_MAX_CHANS][64];
+    char channel_string[GSDF_MAX_CHANS][64];
+    int channel_status[GSDF_MAX_CHANS];
+    int channel_type[GSDF_MAX_CHANS];
+    long gpsTime;
+    long epicsSync;
 } gsdf_c;
 
-#define MY_DBL_TYPE	0
-#define MY_STR_TYPE	1
+#define MY_DBL_TYPE 0
+#define MY_STR_TYPE 1
 
 gsdf_c gsdf;
 static struct rmIpcStr *dipc;
@@ -129,11 +130,11 @@ void waitGpsTrigger(unsigned long gpssec, int cycle)
 {
 unsigned long gpsSec, gpsuSec;
 int gpsx;
-	do{
-		usleep(1000);
-		gpsSec = symm_gps_time(&gpsuSec, &gpsx);
-		gpsuSec /= 1000;
-	}while(gpsSec < gpssec || gpsuSec < timemarks[cycle]); 
+    do{
+        usleep(1000);
+        gpsSec = symm_gps_time(&gpsuSec, &gpsx);
+        gpsuSec /= 1000;
+    }while(gpsSec < gpssec || gpsuSec < timemarks[cycle]); 
 }
 
 // **************************************************************************
@@ -150,28 +151,28 @@ int symm_gps_ok() {
 unsigned long symm_initialize()
 // **************************************************************************
 {
-	symmetricom_fd =  open ("/dev/gpstime", O_RDWR | O_SYNC);
-	if (symmetricom_fd < 0) {
-	       perror("/dev/gpstime");
-	       exit(1);
-	}
-	unsigned long gpsSec, gpsuSec;
-	int gpsx;
-	int gpssync;
-	gpssync =  symm_gps_ok();
-	gpsSec = symm_gps_time(&gpsuSec, &gpsx);
-	printf("GPS SYNC = %d %d\n",gpssync,gpsx);
-	printf("GPS SEC = %ld  USEC = %ld  OTHER = %d\n",gpsSec,gpsuSec,gpsx);
-	// Set system to start 2 sec from now.
-	gpsSec += 2;
-	return(gpsSec);
+    symmetricom_fd =  open ("/dev/gpstime", O_RDWR | O_SYNC);
+    if (symmetricom_fd < 0) {
+           perror("/dev/gpstime");
+           exit(1);
+    }
+    unsigned long gpsSec, gpsuSec;
+    int gpsx;
+    int gpssync;
+    gpssync =  symm_gps_ok();
+    gpsSec = symm_gps_time(&gpsuSec, &gpsx);
+    printf("GPS SYNC = %d %d\n",gpssync,gpsx);
+    printf("GPS SEC = %ld  USEC = %ld  OTHER = %d\n",gpsSec,gpsuSec,gpsx);
+    // Set system to start 2 sec from now.
+    gpsSec += 2;
+    return(gpsSec);
 }
 
 // **************************************************************************
 void connectCallback(struct connection_handler_args args) {
 // **************************************************************************
         unsigned long chnum = (unsigned long)ca_puser(args.chid);
-	gsdf.channel_status[chnum] = args.op == CA_OP_CONN_UP? 0: 0xbad;
+    gsdf.channel_status[chnum] = args.op == CA_OP_CONN_UP? 0: 0xbad;
         if (args.op == CA_OP_CONN_UP) gsdf.con_chans++; else gsdf.con_chans--;
         gsdf.con_events++;
 }
@@ -184,29 +185,29 @@ char timestring[256];
 FILE *statelog;
 char state[64];
 char newfile[256];
- 	gsdf.val_events++;
+    gsdf.val_events++;
         if (args.status != ECA_NORMAL) {
-        	return;
+            return;
         }
         if (args.type == DBR_FLOAT) {
-        	float val = *((float *)args.dbr);
+            float val = *((float *)args.dbr);
                 gsdf.channel_value[(unsigned long)args.usr] = val;
         } else if (args.type == DBR_DOUBLE) {
-        	double val1 = *((double *)args.dbr);
+            double val1 = *((double *)args.dbr);
                 gsdf.channel_value[(unsigned long)args.usr] = val1;
-		// printf("Channel %s changed to %lf\n",gsdf.channel_name[(unsigned long)args.usr],val1);
+        // printf("Channel %s changed to %lf\n",gsdf.channel_name[(unsigned long)args.usr],val1);
         }else{
-		strcpy(gsdf.channel_string[(unsigned long)args.usr],(char *)args.dbr);
-		getSdfTime2(timestring, 256);
-		printf("Time is %s\n",timestring);
-		printf("Channel %s has value %s\n",gsdf.channel_name[(unsigned long)args.usr],gsdf.channel_string[(unsigned long)args.usr]);
-		statelog = fopen(statelogfilename,"a");
-		fprintf(statelog,"%s %s\n",gsdf.channel_string[(unsigned long)args.usr],timestring);
-		fclose(statelog);
-		sprintf(newfile,"%sdata/%s",logfiledir,timestring);
-		printf("Ready to write %s\n",newfile);
-		gsdfWriteData(newfile);
-	}
+        strcpy(gsdf.channel_string[(unsigned long)args.usr],(char *)args.dbr);
+        getSdfTime2(timestring, 256);
+        printf("Time is %s\n",timestring);
+        printf("Channel %s has value %s\n",gsdf.channel_name[(unsigned long)args.usr],gsdf.channel_string[(unsigned long)args.usr]);
+        statelog = fopen(statelogfilename,"a");
+        fprintf(statelog,"%s %s\n",gsdf.channel_string[(unsigned long)args.usr],timestring);
+        fclose(statelog);
+        sprintf(newfile,"%sdata/%s",logfiledir,timestring);
+        printf("Ready to write %s\n",newfile);
+        gsdfWriteData(newfile);
+    }
 }
 
 // **************************************************************************
@@ -230,29 +231,29 @@ dbAddr daddr;
 
 
 
-	for(ii=0;ii<40;ii++)
+    for(ii=0;ii<40;ii++)
         {
-	 sprintf(s, "%s_%s_STAT%d", pref,"SDF_SP", ii);
-	 status = dbNameToAddr(s,&saddr);
-	 status = dbPutField(&saddr,DBR_UCHAR,clearString,16);
+     sprintf(s, "%s_%s_STAT%d", pref,"SDF_SP", ii);
+     status = dbNameToAddr(s,&saddr);
+     status = dbPutField(&saddr,DBR_UCHAR,clearString,16);
 
-	 sprintf(s1, "%s_%s_STAT%d_BURT", pref,"SDF_SP", ii);
-	 status = dbNameToAddr(s1,&baddr);
-	 status = dbPutField(&baddr,DBR_UCHAR,clearString,flength);
+     sprintf(s1, "%s_%s_STAT%d_BURT", pref,"SDF_SP", ii);
+     status = dbNameToAddr(s1,&baddr);
+     status = dbPutField(&baddr,DBR_UCHAR,clearString,flength);
 
-	 sprintf(s2, "%s_%s_STAT%d_LIVE", pref,"SDF_SP", ii);
-	 status = dbNameToAddr(s2,&maddr);
-	 status = dbPutField(&maddr,DBR_UCHAR,clearString,flength);
+     sprintf(s2, "%s_%s_STAT%d_LIVE", pref,"SDF_SP", ii);
+     status = dbNameToAddr(s2,&maddr);
+     status = dbPutField(&maddr,DBR_UCHAR,clearString,flength);
 
-	 sprintf(s3, "%s_%s_STAT%d_TIME", pref,"SDF_SP", ii);
-	 status = dbNameToAddr(s3,&taddr);
-	 status = dbPutField(&taddr,DBR_UCHAR,clearString,flength);
+     sprintf(s3, "%s_%s_STAT%d_TIME", pref,"SDF_SP", ii);
+     status = dbNameToAddr(s3,&taddr);
+     status = dbPutField(&taddr,DBR_UCHAR,clearString,flength);
 
-	  sprintf(s4, "%s_%s_STAT%d_DIFF", pref,"SDF_SP", ii);
-	  status = dbNameToAddr(s4,&daddr);
-	  status = dbPutField(&daddr,DBR_UCHAR,clearString,flength);
+      sprintf(s4, "%s_%s_STAT%d_DIFF", pref,"SDF_SP", ii);
+      status = dbNameToAddr(s4,&daddr);
+      status = dbPutField(&daddr,DBR_UCHAR,clearString,flength);
 
-	 }
+     }
 
 
 }
@@ -264,15 +265,15 @@ int gsdfFindUnconnChannels()
 int ii;
 int dcc = 0;
 
-	for (ii=0;ii<gsdf.num_chans;ii++)
-	{
-		if(gsdf.channel_status[ii] != 0)
-		{
-			sprintf(naughtyList[dcc],"%s",gsdf.channel_name[ii]);
-			dcc ++;
-		}
-	}
-	return(dcc);
+    for (ii=0;ii<gsdf.num_chans;ii++)
+    {
+        if(gsdf.channel_status[ii] != 0)
+        {
+            sprintf(naughtyList[dcc],"%s",gsdf.channel_name[ii]);
+            dcc ++;
+        }
+    }
+    return(dcc);
 }
 // **************************************************************************
 int gsdfReportUnconnChannels(char *pref, int dc, int offset)
@@ -294,53 +295,53 @@ int lineNum = 0;
 int erucError = 0;
 
 
-	myindex = offset * 40;
-	if(myindex > dc) {
-		myindex = 0;
-		erucError = -1;
-	}
-	rc = myindex + 40;
-	if(rc > dc) rc = dc;
-	// printf("Naught =  %d to %d\n",myindex,rc);
-	// printf("In error listing \n");
-	for (ii=myindex;ii<rc;ii++)
-	{
-		sprintf(s, "%s_%s_STAT%d", pref,"SDF_SP", (ii - myindex));
-		status = dbNameToAddr(s,&saddr);
-		if(status) 
-		{
-			printf("Can't connect to %s\n",s);
-		} else {
-			sprintf(tmpstr,"%s",naughtyList[ii]);
-			status = dbPutField(&saddr,DBR_UCHAR,tmpstr,flength);
-			numDisp ++;
-		}
-		sprintf(sl, "%s_SDF_LINE_%d", pref, (ii - myindex));
-		status = dbNameToAddr(sl,&laddr);
-		if(status) 
-		{
-			printf("Can't connect to %s\n",s);
-		} else {
-			lineNum = ii + 1;
-			status = dbPutField(&laddr,DBR_LONG,&lineNum,1);
-		}
-	}
-	// Clear out remaining reporting channels.
-	sprintf(tmpstr,"%s","  ");
-	for (ii=numDisp;ii<40;ii++) {
-		sprintf(s, "%s_%s_STAT%d", pref,"SDF_SP", ii);
-		status = dbNameToAddr(s,&saddr);
-		status = dbPutField(&saddr,DBR_UCHAR,tmpstr,flength);
-		sprintf(sl, "%s_SDF_LINE_%d", pref, (ii - myindex));
-		status = dbNameToAddr(sl,&laddr);
-		lineNum = ii + 1;
-		status = dbPutField(&laddr,DBR_LONG,&lineNum,1);
-	}
-	 char speStat[256]; sprintf(speStat, "%s_%s", pref, "SDF_TABLE_ENTRIES");             // Setpoint diff counter
-	 status = dbNameToAddr(speStat,&sperroraddr);                    // Get Address
-	 status = dbPutField(&sperroraddr,DBR_LONG,&dc,1);          // Init to zero.
-
-	return(erucError);
+    myindex = offset * 40;
+    if(myindex > dc) {
+        myindex = 0;
+        erucError = -1;
+    }
+    rc = myindex + 40;
+    if(rc > dc) rc = dc;
+    // printf("Naught =  %d to %d\n",myindex,rc);
+    // printf("In error listing \n");
+    for (ii=myindex;ii<rc;ii++)
+    {
+        sprintf(s, "%s_%s_STAT%d", pref,"SDF_SP", (ii - myindex));
+        status = dbNameToAddr(s,&saddr);
+        if(status) 
+        {
+            printf("Can't connect to %s\n",s);
+        } else {
+            sprintf(tmpstr,"%s",naughtyList[ii]);
+            status = dbPutField(&saddr,DBR_UCHAR,tmpstr,flength);
+            numDisp ++;
+        }
+        sprintf(sl, "%s_SDF_LINE_%d", pref, (ii - myindex));
+        status = dbNameToAddr(sl,&laddr);
+        if(status) 
+        {
+            printf("Can't connect to %s\n",s);
+        } else {
+            lineNum = ii + 1;
+            status = dbPutField(&laddr,DBR_LONG,&lineNum,1);
+        }
+    }
+    // Clear out remaining reporting channels.
+    sprintf(tmpstr,"%s","  ");
+    for (ii=numDisp;ii<40;ii++) {
+        sprintf(s, "%s_%s_STAT%d", pref,"SDF_SP", ii);
+        status = dbNameToAddr(s,&saddr);
+        status = dbPutField(&saddr,DBR_UCHAR,tmpstr,flength);
+        sprintf(sl, "%s_SDF_LINE_%d", pref, (ii - myindex));
+        status = dbNameToAddr(sl,&laddr);
+        lineNum = ii + 1;
+        status = dbPutField(&laddr,DBR_LONG,&lineNum,1);
+    }
+     char speStat[256]; sprintf(speStat, "%s_%s", pref, "SDF_TABLE_ENTRIES");             // Setpoint diff counter
+     status = dbNameToAddr(speStat,&sperroraddr);                    // Get Address
+     status = dbPutField(&sperroraddr,DBR_LONG,&dc,1);          // Init to zero.
+
+    return(erucError);
 }
 
 // **************************************************************************
@@ -355,61 +356,61 @@ char errMsg[64];
 char line[128];
 char *newname;
 
-	// sprintf(daqfile, "%s%s", fdir, "EDCU.ini");
-	gsdf.num_chans = 0;
-	daqfileptr = fopen(daqfilename,"r");
-	if(daqfileptr == NULL) {
-		sprintf(errMsg,"DAQ FILE ERROR: FILE %s DOES NOT EXIST\n",daqfilename);
-	        logFileEntry(errMsg);
+    // sprintf(daqfile, "%s%s", fdir, "EDCU.ini");
+    gsdf.num_chans = 0;
+    daqfileptr = fopen(daqfilename,"r");
+    if(daqfileptr == NULL) {
+        sprintf(errMsg,"DAQ FILE ERROR: FILE %s DOES NOT EXIST\n",daqfilename);
+            logFileEntry(errMsg);
+        }
+    gsdflog = fopen(gsdflogfilename,"w");
+    if(daqfileptr == NULL) {
+        sprintf(errMsg,"DAQ FILE ERROR: FILE %s DOES NOT EXIST\n",gsdflogfilename);
+            logFileEntry(errMsg);
+        }
+    while(fgets(line,sizeof line,daqfileptr) != NULL) {
+        fprintf(gsdflog,"%s",line);
+        status = strlen(line);
+        if(strncmp(line,"[",1) == 0 && status > 0) {
+            if(strstr(line,"string") != NULL) {
+                printf("Found string type %s \n",line);
+                gsdf.channel_type[gsdf.num_chans] = MY_STR_TYPE;
+            } else {
+                gsdf.channel_type[gsdf.num_chans] = MY_DBL_TYPE;
+            }
+            newname = strtok(line,"]");
+            // printf("status = %d New name = %s and %s\n",status,line,newname);
+            newname = strtok(line,"[");
+            // printf("status = %d New name = %s and %s\n",status,line,newname);
+            if(strcmp(newname,"default") == 0) {
+                printf("DEFAULT channel = %s\n", newname);
+            } else {
+                // printf("NEW channel = %s\n", newname);
+                sprintf(gsdf.channel_name[gsdf.num_chans],"%s",newname);
+                gsdf.num_chans ++;
+            }
         }
-	gsdflog = fopen(gsdflogfilename,"w");
-	if(daqfileptr == NULL) {
-		sprintf(errMsg,"DAQ FILE ERROR: FILE %s DOES NOT EXIST\n",gsdflogfilename);
-	        logFileEntry(errMsg);
+    }
+    fclose(daqfileptr);
+    fclose(gsdflog);
+
+    xferInfo.crcLength = 4 * gsdf.num_chans;
+    printf("CRC data length = %d\n",xferInfo.crcLength);
+
+         chid chid1;
+    ca_context_create(ca_enable_preemptive_callback);
+        for (i = 0; i < gsdf.num_chans; i++) {
+         status = ca_create_channel(gsdf.channel_name[i], connectCallback, (void *)i, 0, &chid1);
+         if(gsdf.channel_type[i] == MY_STR_TYPE) {
+        printf("Found the string channel = %s\n",gsdf.channel_name[i]);
+            status = ca_create_subscription(DBR_STRING, 0, chid1, DBE_VALUE,
+                 subscriptionHandler, (void *)i, 0);
+         } else {
+            status = ca_create_subscription(DBR_DOUBLE, 0, chid1, DBE_VALUE,
+                 subscriptionHandler, (void *)i, 0);
         }
-	while(fgets(line,sizeof line,daqfileptr) != NULL) {
-		fprintf(gsdflog,"%s",line);
-		status = strlen(line);
-		if(strncmp(line,"[",1) == 0 && status > 0) {
-			if(strstr(line,"string") != NULL) {
-				printf("Found string type %s \n",line);
-				gsdf.channel_type[gsdf.num_chans] = MY_STR_TYPE;
-			} else {
-				gsdf.channel_type[gsdf.num_chans] = MY_DBL_TYPE;
-			}
-			newname = strtok(line,"]");
-			// printf("status = %d New name = %s and %s\n",status,line,newname);
-			newname = strtok(line,"[");
-			// printf("status = %d New name = %s and %s\n",status,line,newname);
-			if(strcmp(newname,"default") == 0) {
-				printf("DEFAULT channel = %s\n", newname);
-			} else {
-				// printf("NEW channel = %s\n", newname);
-				sprintf(gsdf.channel_name[gsdf.num_chans],"%s",newname);
-				gsdf.num_chans ++;
-			}
-		}
-	}
-	fclose(daqfileptr);
-	fclose(gsdflog);
-
-	xferInfo.crcLength = 4 * gsdf.num_chans;
-	printf("CRC data length = %d\n",xferInfo.crcLength);
-
-	     chid chid1;
-	ca_context_create(ca_enable_preemptive_callback);
-     	for (i = 0; i < gsdf.num_chans; i++) {
-	     status = ca_create_channel(gsdf.channel_name[i], connectCallback, (void *)i, 0, &chid1);
-	     if(gsdf.channel_type[i] == MY_STR_TYPE) {
-		printf("Found the string channel = %s\n",gsdf.channel_name[i]);
-	     	status = ca_create_subscription(DBR_STRING, 0, chid1, DBE_VALUE,
-			     subscriptionHandler, (void *)i, 0);
-	     } else {
-	     	status = ca_create_subscription(DBR_DOUBLE, 0, chid1, DBE_VALUE,
-			     subscriptionHandler, (void *)i, 0);
-		}
-	}
-	timeIndex = 0;
+    }
+    timeIndex = 0;
 }
 
 // **************************************************************************
@@ -419,15 +420,15 @@ void gsdfWriteData(char *filename)
 int ii;
 FILE *log;
 
-		
-	log = fopen(filename,"w");
-	for(ii=0;ii<gsdf.num_chans;ii++) {
-		if(gsdf.channel_type[ii] == MY_STR_TYPE)
-			fprintf(log,"%s %s STRING\n",gsdf.channel_name[ii],gsdf.channel_string[ii]);
-		else
-			fprintf(log,"%s %.15e DOUBLE\n",gsdf.channel_name[ii],gsdf.channel_value[ii]);
-	}
-	fclose(log);
+        
+    log = fopen(filename,"w");
+    for(ii=0;ii<gsdf.num_chans;ii++) {
+        if(gsdf.channel_type[ii] == MY_STR_TYPE)
+            fprintf(log,"%s %s STRING\n",gsdf.channel_name[ii],gsdf.channel_string[ii]);
+        else
+            fprintf(log,"%s %.15e DOUBLE\n",gsdf.channel_name[ii],gsdf.channel_value[ii]);
+    }
+    fclose(log);
 }
 
 // **************************************************************************
@@ -435,218 +436,230 @@ void gsdfInitialize(char *shmem_fname)
 // **************************************************************************
 {
 
-	// Find start of DAQ shared memory
-	void *dcu_addr = findSharedMemory(shmem_fname);
-	// Find the IPC area to communicate with mxstream
-	dipc = (struct rmIpcStr *)((char *)dcu_addr + CDS_DAQ_NET_IPC_OFFSET);
-	// Find the DAQ data area.
-        shmDataPtr = (char *)((char *)dcu_addr + CDS_DAQ_NET_DATA_OFFSET);
+    // Find start of DAQ shared memory
+    g_dcu_shm_handle = shmem_open(shmem_fname, DEFAULT_SHMEM_ALLOC_SIZE_MB); //<model>_daq
+    volatile void * dcu_addr = shmem_mapping(g_dcu_shm_handle);
+
+    // Find the IPC area to communicate with mxstream
+    dipc = (struct rmIpcStr *)((char *)dcu_addr + CDS_DAQ_NET_IPC_OFFSET);
+    // Find the DAQ data area.
+    shmDataPtr = (char *)((char *)dcu_addr + CDS_DAQ_NET_DATA_OFFSET);
+}
+
+void gsdfDeinitialize()
+{
+    shmem_close(g_dcu_shm_handle);
 }
 
 
 /// Routine for reading GPS time from model EPICS record.
-///	@param[out] timestring 	Pointer to char string in which GPS time is to be written.
+/// @param[out] timestring  Pointer to char string in which GPS time is to be written.
 void getSdfTime(char *timestring)
 {
 
-	dbAddr paddr;
-	long ropts = 0;
-	long nvals = 1;
-	long status;
+    dbAddr paddr;
+    long ropts = 0;
+    long nvals = 1;
+    long status;
 
-	status = dbNameToAddr(timechannel,&paddr);
-	status = dbGetField(&paddr,DBR_STRING,timestring,&ropts,&nvals,NULL);
+    status = dbNameToAddr(timechannel,&paddr);
+    status = dbGetField(&paddr,DBR_STRING,timestring,&ropts,&nvals,NULL);
 }
 
 /// Routine for logging messages to ioc.log file.
-/// 	@param[in] message Ptr to string containing message to be logged.
+///     @param[in] message Ptr to string containing message to be logged.
 void logFileEntry(char *message)
 {
-	FILE *log;
-	char timestring[256];
-	long status;
-	dbAddr paddr;
-
-	getSdfTime(timestring);
-	log = fopen(logfilename,"a");
-	if(log == NULL) {
-		status = dbNameToAddr(reloadtimechannel,&paddr);
-		status = dbPutField(&paddr,DBR_STRING,"ERR - NO LOG FILE FOUND",1);
-	} else {
-		fprintf(log,"%s\n%s\n",timestring,message);
-		fprintf(log,"***************************************************\n");
-		fclose(log);
-	}
+    FILE *log;
+    char timestring[256];
+    long status;
+    dbAddr paddr;
+
+    getSdfTime(timestring);
+    log = fopen(logfilename,"a");
+    if(log == NULL) {
+        status = dbNameToAddr(reloadtimechannel,&paddr);
+        status = dbPutField(&paddr,DBR_STRING,"ERR - NO LOG FILE FOUND",1);
+    } else {
+        fprintf(log,"%s\n%s\n",timestring,message);
+        fprintf(log,"***************************************************\n");
+        fclose(log);
+    }
 
 }
 
 /// Called on EPICS startup; This is generic EPICS provided function, modified for LIGO use.
 int main(int argc,char *argv[])
 {
-	// Addresses for SDF EPICS records.
-	// Initialize request for file load on startup.
-	long status;
-	int request;
-	int daqTrigger;
-	long ropts = 0;
-	long nvals = 1;
-	int rdstatus = 0;
-	char timestring[128];
-	int ii;
-	int fivesectimer = 0;
-	long coeffFileCrc;
-	char modfilemsg[] = "Modified File Detected ";
-	struct stat st = {0};
-	char filemsg[128];
-	char logmsg[256];
-	unsigned int pageNum = 0;
-	unsigned int dataDump = 0;
+    // Addresses for SDF EPICS records.
+    // Initialize request for file load on startup.
+    long status;
+    int request;
+    int daqTrigger;
+    long ropts = 0;
+    long nvals = 1;
+    int rdstatus = 0;
+    char timestring[128];
+    int ii;
+    int fivesectimer = 0;
+    long coeffFileCrc;
+    char modfilemsg[] = "Modified File Detected ";
+    struct stat st = {0};
+    char filemsg[128];
+    char logmsg[256];
+    unsigned int pageNum = 0;
+    unsigned int dataDump = 0;
 
 printf("Entering main\n");
     if(argc>=2) {
         iocsh(argv[1]);
-	printf("Executing post script commands\n");
-	// Get environment variables from startup command to formulate EPICS record names.
-	char *pref = getenv("PREFIX");
-	char *modelname =  getenv("SDF_MODEL");
-	char daqsharedmemname[64];
-	sprintf(daqsharedmemname, "%s%s", modelname, "_daq");
-	char *targetdir =  getenv("TARGET_DIR");
-	char *daqFile =  getenv("DAQ_FILE");
-	char *daqDir =  getenv("DAQ_DIR");
-	char *coeffFile =  getenv("COEFF_FILE");
-	char *logdir = getenv("LOG_DIR");
-	if(stat(logdir, &st) == -1) mkdir(logdir,0777);
-	// strcat(sdf,"_safe");
-	printf("My prefix is %s\n",pref);
-	sprintf(logfilename, "%s%s", logdir, "/ioc.log");
-	sprintf(logfiledir,"%s%s",logdir,"/");
-	printf("LOG FILE = %s\n",logfilename);
+    printf("Executing post script commands\n");
+    // Get environment variables from startup command to formulate EPICS record names.
+    char *pref = getenv("PREFIX");
+    char *modelname =  getenv("SDF_MODEL");
+    char daqsharedmemname[64];
+    sprintf(daqsharedmemname, "%s%s", modelname, "_daq");
+    char *targetdir =  getenv("TARGET_DIR");
+    char *daqFile =  getenv("DAQ_FILE");
+    char *daqDir =  getenv("DAQ_DIR");
+    char *coeffFile =  getenv("COEFF_FILE");
+    char *logdir = getenv("LOG_DIR");
+    if(stat(logdir, &st) == -1) mkdir(logdir,0777);
+    // strcat(sdf,"_safe");
+    printf("My prefix is %s\n",pref);
+    sprintf(logfilename, "%s%s", logdir, "/ioc.log");
+    sprintf(logfiledir,"%s%s",logdir,"/");
+    printf("LOG FILE = %s\n",logfilename);
 sleep(2);
-	// **********************************************
-	//
-	dbAddr eccaddr;
-	char eccname[256]; sprintf(eccname, "%s_%s", pref, "GSDF_CHAN_CONN");			// Number of setting channels in EPICS db
-	status = dbNameToAddr(eccname,&eccaddr);
-
-	dbAddr chcntaddr;
-	// char chcntname[256]; sprintf(chcntname, "%s", "X1:DAQ-FEC_54_EPICS_CHAN_CNT");	// Request to monitor all channels.
-	char chcntname[256]; sprintf(chcntname, "%s_%s", pref, "GSDF_CHAN_CNT");	// Request to monitor all channels.
-	status = dbNameToAddr(chcntname,&chcntaddr);		// Get Address.
-
-	dbAddr chnotfoundaddr;
-	char cnfname[256]; sprintf(cnfname, "%s_%s", pref, "GSDF_CHAN_NOCON");		// Number of channels not found.
-	status = dbNameToAddr(cnfname,&chnotfoundaddr);
-
-	dbAddr daqbyteaddr;
-	char daqbytename[256]; sprintf(daqbytename, "%s_%s", pref, "DAQ_BYTE_COUNT");	// Request to monitor all channels.
-	status = dbNameToAddr(daqbytename,&daqbyteaddr);		// Get Address.
-
-	dbAddr daqmsgaddr;
-	char moddaqfilemsg[256]; sprintf(moddaqfilemsg, "%s_%s", pref, "MSGDAQ");	// Record to write if DAQ file changed.
-	status = dbNameToAddr(moddaqfilemsg,&daqmsgaddr);
-
-	sprintf(timechannel,"%s_%s", pref, "TIME_STRING");
-	// printf("timechannel = %s\n",timechannel);
-	
-	dbAddr reloadtimeaddr;
-	sprintf(reloadtimechannel,"%s_%s", pref, "MSGDAQ");			// Time of last BURT reload
-	status = dbNameToAddr(reloadtimechannel,&reloadtimeaddr);
-
-	getSdfTime(timestring);
-	status = dbPutField(&reloadtimeaddr,DBR_STRING,timestring,1);
-
-	dbAddr gpstimedisplayaddr;
-	char gpstimedisplayname[256]; sprintf(gpstimedisplayname, "%s_%s", pref, "TIME_DIAG");	// SDF Save command.
-	status = dbNameToAddr(gpstimedisplayname,&gpstimedisplayaddr);		// Get Address.
-
-	dbAddr pagereqaddr;
-	char pagereqname[256]; sprintf(pagereqname, "%s_%s", pref, "SDF_PAGE");	// SDF Save command.
-	status = dbNameToAddr(pagereqname,&pagereqaddr);		// Get Address.
-
-	dbAddr datadumpaddr;
-	char datadumpname[256]; sprintf(datadumpname, "%s_%s", pref, "GSDF_DUMP_DATA");	// SDF Save command.
-	status = dbNameToAddr(datadumpname,&datadumpaddr);		// Get Address.
+    // **********************************************
+    //
+    dbAddr eccaddr;
+    char eccname[256]; sprintf(eccname, "%s_%s", pref, "GSDF_CHAN_CONN");           // Number of setting channels in EPICS db
+    status = dbNameToAddr(eccname,&eccaddr);
+
+    dbAddr chcntaddr;
+    // char chcntname[256]; sprintf(chcntname, "%s", "X1:DAQ-FEC_54_EPICS_CHAN_CNT");   // Request to monitor all channels.
+    char chcntname[256]; sprintf(chcntname, "%s_%s", pref, "GSDF_CHAN_CNT");    // Request to monitor all channels.
+    status = dbNameToAddr(chcntname,&chcntaddr);        // Get Address.
+
+    dbAddr chnotfoundaddr;
+    char cnfname[256]; sprintf(cnfname, "%s_%s", pref, "GSDF_CHAN_NOCON");      // Number of channels not found.
+    status = dbNameToAddr(cnfname,&chnotfoundaddr);
+
+    dbAddr daqbyteaddr;
+    char daqbytename[256]; sprintf(daqbytename, "%s_%s", pref, "DAQ_BYTE_COUNT");   // Request to monitor all channels.
+    status = dbNameToAddr(daqbytename,&daqbyteaddr);        // Get Address.
+
+    dbAddr daqmsgaddr;
+    char moddaqfilemsg[256]; sprintf(moddaqfilemsg, "%s_%s", pref, "MSGDAQ");   // Record to write if DAQ file changed.
+    status = dbNameToAddr(moddaqfilemsg,&daqmsgaddr);
+
+    sprintf(timechannel,"%s_%s", pref, "TIME_STRING");
+    // printf("timechannel = %s\n",timechannel);
+    
+    dbAddr reloadtimeaddr;
+    sprintf(reloadtimechannel,"%s_%s", pref, "MSGDAQ");         // Time of last BURT reload
+    status = dbNameToAddr(reloadtimechannel,&reloadtimeaddr);
+
+    getSdfTime(timestring);
+    status = dbPutField(&reloadtimeaddr,DBR_STRING,timestring,1);
+
+    dbAddr gpstimedisplayaddr;
+    char gpstimedisplayname[256]; sprintf(gpstimedisplayname, "%s_%s", pref, "TIME_DIAG");  // SDF Save command.
+    status = dbNameToAddr(gpstimedisplayname,&gpstimedisplayaddr);      // Get Address.
+
+    dbAddr pagereqaddr;
+    char pagereqname[256]; sprintf(pagereqname, "%s_%s", pref, "SDF_PAGE"); // SDF Save command.
+    status = dbNameToAddr(pagereqname,&pagereqaddr);        // Get Address.
+
+    dbAddr datadumpaddr;
+    char datadumpname[256]; sprintf(datadumpname, "%s_%s", pref, "GSDF_DUMP_DATA"); // SDF Save command.
+    status = dbNameToAddr(datadumpname,&datadumpaddr);      // Get Address.
 
 // EDCU STUFF ********************************************************************************************************
-	
-	sprintf(gsdflogfilename, "%s%s", logdir, "/gsdf.log");
-	sprintf(statelogfilename, "%s%s", logdir, "/state.log");
-printf("Going to initialize\n");
-	gsdfInitialize(daqsharedmemname);
-	gsdfCreateChanList(daqFile);
-	status = dbPutField(&chcntaddr,DBR_LONG,&gsdf.num_chans,1);
-	int datarate = gsdf.num_chans * 4 / 1000;
-	status = dbPutField(&daqbyteaddr,DBR_LONG,&datarate,1);
+    
+    sprintf(gsdflogfilename, "%s%s", logdir, "/gsdf.log");
+    sprintf(statelogfilename, "%s%s", logdir, "/state.log");
+    printf("Going to initialize\n");
+    gsdfInitialize(daqsharedmemname);
+    gsdfCreateChanList(daqFile);
+    status = dbPutField(&chcntaddr,DBR_LONG,&gsdf.num_chans,1);
+    int datarate = gsdf.num_chans * 4 / 1000;
+    status = dbPutField(&daqbyteaddr,DBR_LONG,&datarate,1);
 
 // Start SPECT
-	gsdf.gpsTime = symm_initialize();
-	gsdf.epicsSync = 0;
+    gsdf.gpsTime = symm_initialize();
+    gsdf.epicsSync = 0;
 
 // End SPECT
-	for (ii=0;ii<GSDF_MAX_CHANS;ii++) gsdf.channel_status[ii] = 0xbad;
-
-	int dropout = 0;
-	int numDC = 0;
-	int cycle = 0;
-	int numReport = 0;
-
-	// Initialize DAQ and COEFF file CRC checksums for later compares.
-	daqFileCrc = checkFileCrc(daqFile);
-	printf("DAQ file CRC = %u \n",daqFileCrc);  
-	coeffFileCrc = checkFileCrc(coeffFile);
-	sprintf(logmsg,"%s\n%s = %u\n%s = %d","GSDF code restart","File CRC",daqFileCrc,"Chan Cnt",gsdf.num_chans);
-	logFileEntry(logmsg);
-	gsdfClearSdf(pref);
-	// Start Infinite Loop 		*******************************************************************************
-	for(;;) {
-		dropout = 0;
-		waitGpsTrigger(gsdf.gpsTime, gsdf.epicsSync);
-		// printf("GSDF %ld - %d\n",gsdf.gpsTime,gsdf.epicsSync);
-		status = dbPutField(&gpstimedisplayaddr,DBR_LONG,&gsdf.gpsTime,1);		// Init to zero.
-		gsdf.epicsSync = (gsdf.epicsSync + 1) % 16;
-		if (gsdf.epicsSync == 0) gsdf.gpsTime ++;
-		status = dbPutField(&daqbyteaddr,DBR_LONG,&datarate,1);
-		int conChans = gsdf.con_chans;
-		status = dbPutField(&eccaddr,DBR_LONG,&conChans,1);
-		// if((conChans != gsdf.num_chans) || (numDC != 0)) numDC = gsdfReportUnconnChannels(pref);
-		// if(conChans != gsdf.num_chans) numDC = gsdfReportUnconnChannels(pref);
-		if (gsdf.epicsSync == 0) {
-			status = dbGetField(&pagereqaddr,DBR_USHORT,&pageNum,&ropts,&nvals,NULL);
-			// printf("Page is %d\n",pageNum);
-			numDC = gsdfFindUnconnChannels();
-			numReport = gsdfReportUnconnChannels(pref,numDC,pageNum);
-			if(numReport == -1) {
-				pageNum = 0;
-				status = dbPutField(&pagereqaddr,DBR_USHORT,&pageNum,1);		// Init to zero.
-			}
-			status = dbGetField(&datadumpaddr,DBR_USHORT,&dataDump,&ropts,&nvals,NULL);
-			if(dataDump) {
-				printf("Received data request\n");
-				gsdfWriteData("/tmp/gsdfdata");
-				dataDump = 0;
-				status = dbPutField(&datadumpaddr,DBR_USHORT,&dataDump,1);		// Init to zero.
-			}
-		}
-		status = dbPutField(&chnotfoundaddr,DBR_LONG,&numDC,1);
+    for (ii=0;ii<GSDF_MAX_CHANS;ii++) gsdf.channel_status[ii] = 0xbad;
+
+    int dropout = 0;
+    int numDC = 0;
+    int cycle = 0;
+    int numReport = 0;
+
+    // Initialize DAQ and COEFF file CRC checksums for later compares.
+    daqFileCrc = checkFileCrc(daqFile);
+    printf("DAQ file CRC = %u \n",daqFileCrc);  
+    coeffFileCrc = checkFileCrc(coeffFile);
+    sprintf(logmsg,"%s\n%s = %u\n%s = %d","GSDF code restart","File CRC",daqFileCrc,"Chan Cnt",gsdf.num_chans);
+    logFileEntry(logmsg);
+    gsdfClearSdf(pref);
+    // Start Infinite Loop      *******************************************************************************
+    for(;;) {
+        dropout = 0;
+        waitGpsTrigger(gsdf.gpsTime, gsdf.epicsSync);
+        // printf("GSDF %ld - %d\n",gsdf.gpsTime,gsdf.epicsSync);
+        status = dbPutField(&gpstimedisplayaddr,DBR_LONG,&gsdf.gpsTime,1);      // Init to zero.
+        gsdf.epicsSync = (gsdf.epicsSync + 1) % 16;
+        if (gsdf.epicsSync == 0) gsdf.gpsTime ++;
+        status = dbPutField(&daqbyteaddr,DBR_LONG,&datarate,1);
+        int conChans = gsdf.con_chans;
+        status = dbPutField(&eccaddr,DBR_LONG,&conChans,1);
+        // if((conChans != gsdf.num_chans) || (numDC != 0)) numDC = gsdfReportUnconnChannels(pref);
+        // if(conChans != gsdf.num_chans) numDC = gsdfReportUnconnChannels(pref);
+        if (gsdf.epicsSync == 0) {
+            status = dbGetField(&pagereqaddr,DBR_USHORT,&pageNum,&ropts,&nvals,NULL);
+            // printf("Page is %d\n",pageNum);
+            numDC = gsdfFindUnconnChannels();
+            numReport = gsdfReportUnconnChannels(pref,numDC,pageNum);
+            if(numReport == -1) {
+                pageNum = 0;
+                status = dbPutField(&pagereqaddr,DBR_USHORT,&pageNum,1);        // Init to zero.
+            }
+            status = dbGetField(&datadumpaddr,DBR_USHORT,&dataDump,&ropts,&nvals,NULL);
+            if(dataDump) {
+                printf("Received data request\n");
+                gsdfWriteData("/tmp/gsdfdata");
+                dataDump = 0;
+                status = dbPutField(&datadumpaddr,DBR_USHORT,&dataDump,1);      // Init to zero.
+            }
+        }
+        status = dbPutField(&chnotfoundaddr,DBR_LONG,&numDC,1);
 
         // printf("GSDF C1 = %f status = %d\n",gsdf.channel_value[2],gsdf.channel_status[2]);
-	// printf("Channels CONN = %d   NO_CONN = %d TIME = %ld SYNC = %ld \n",gsdf.con_chans,(gsdf.num_chans - gsdf.con_chans),gsdf.gpsTime, gsdf.epicsSync);
+    // printf("Channels CONN = %d   NO_CONN = %d TIME = %ld SYNC = %ld \n",gsdf.con_chans,(gsdf.num_chans - gsdf.con_chans),gsdf.gpsTime, gsdf.epicsSync);
         //printf("GSDF C2 = %f\n",gsdf.channel_value[1]);
-		fivesectimer = (fivesectimer + 1) % 50;		// Increment 5 second timer for triggering CRC checks.
-		// Check file CRCs every 5 seconds.
-		// DAQ and COEFF file checking was moved from skeleton.st to here RCG V2.9.
-		if(!fivesectimer) {
-			status = checkFileCrc(daqFile);
-			if(status != daqFileCrc) {
-				daqFileCrc = status;
-				status = dbPutField(&daqmsgaddr,DBR_STRING,modfilemsg,1);
-				logFileEntry("Detected Change to DAQ Config file.");
-			}
-		}
-	}
-	sleep(0xfffffff);
-    } else
-    	iocsh(NULL);
+        fivesectimer = (fivesectimer + 1) % 50;     // Increment 5 second timer for triggering CRC checks.
+        // Check file CRCs every 5 seconds.
+        // DAQ and COEFF file checking was moved from skeleton.st to here RCG V2.9.
+        if(!fivesectimer) {
+            status = checkFileCrc(daqFile);
+            if(status != daqFileCrc) {
+                daqFileCrc = status;
+                status = dbPutField(&daqmsgaddr,DBR_STRING,modfilemsg,1);
+                logFileEntry("Detected Change to DAQ Config file.");
+            }
+        }
+    }
+    sleep(0xfffffff);
+    } else {
+        iocsh(NULL);
+    }
+
+    //This is not going to get called because we don't have a clean way to exit
+    gsdfDeinitialize(); //Clean up shared memory
+
     return(0);
 }
diff --git a/src/epics/simLink/CDS_PARTS.mdl b/src/epics/simLink/CDS_PARTS.mdl
index 7047ff25b22590db7e3003e4e9e378a0d5070004..3f3c010ac0c13b15b772b7f821384dfd4d38feb6 100644
--- a/src/epics/simLink/CDS_PARTS.mdl
+++ b/src/epics/simLink/CDS_PARTS.mdl
@@ -2,10 +2,10 @@ Library {
   Name			  "CDS_PARTS"
   Version		  9.3
   SavedCharacterEncoding  "UTF-8"
+  LogicAnalyzerPlugin	  "on"
+  WebScopes_FoundationPlugin "on"
   DiagnosticSuppressor	  "on"
   SLCCPlugin		  "on"
-  WebScopes_FoundationPlugin "on"
-  LogicAnalyzerPlugin	  "on"
   NotesPlugin		  "on"
   LibraryType		  "BlockLibrary"
   EnableAccessToBaseWorkspace on
@@ -24,7 +24,7 @@ Library {
       $ObjectID		      2
       $ClassName	      "Simulink.WindowInfo"
       IsActive		      [1]
-      Location		      [729.0, 64.0, 1036.0, 877.0]
+      Location		      [2110.0, 146.0, 1036.0, 877.0]
       Object {
 	$PropName		"ModelBrowserInfo"
 	$ObjectID		3
@@ -48,10 +48,10 @@ Library {
 	$ClassName		"Simulink.EditorInfo"
 	IsActive		[1]
 	ViewObjType		"SimulinkSubsys"
-	LoadSaveID		"150"
-	Extents			[735.0, 687.0]
-	ZoomFactor		[1.5]
-	Offset			[-17.569047619048717, 227.907229427522]
+	LoadSaveID		"322"
+	Extents			[747.0, 703.0]
+	ZoomFactor		[1.25]
+	Offset			[-149.32091882185546, 229.24999999999994]
       }
       Object {
 	$PropName		"DockComponentsInfo"
@@ -68,15 +68,15 @@ Library {
 	Height			[480]
 	Minimized		"Unset"
       }
-      WindowState	      "AAAA/wAAAAD9AAAAAgAAAAAAAAD1AAAC8PwCAAAAA/sAAAAWAEQAbwBjAGsAVwBpAGQAZwBlAHQAMwEAAAAxAAAB+AAAA"
+      WindowState	      "AAAA/wAAAAD9AAAAAgAAAAAAAAD1AAAC+fwCAAAAA/sAAAAWAEQAbwBjAGsAVwBpAGQAZwBlAHQAMwEAAAAxAAAB+AAAA"
       "AAAAAAA+wAAABYARABvAGMAawBXAGkAZABnAGUAdAA0AAAAAAD/////AAAAAAAAAAD7AAAAUgBHAEwAVQBFADIAIAB0AHIAZQBlACAAYwBvAG0Ac"
-      "ABvAG4AZQBuAHQALwBHAEwAVQBFADIAIAB0AHIAZQBlACAAYwBvAG0AcABvAG4AZQBuAHQBAAAAQAAAAvAAAACAAP///wAAAAEAAAAAAAAAAPwCA"
+      "ABvAG4AZQBuAHQALwBHAEwAVQBFADIAIAB0AHIAZQBlACAAYwBvAG0AcABvAG4AZQBuAHQBAAAAOQAAAvkAAABiAP///wAAAAEAAAAAAAAAAPwCA"
       "AAAAfsAAABUAEcATABVAEUAMgA6AFAAcgBvAHAAZQByAHQAeQBJAG4AcwBwAGUAYwB0AG8AcgAvAFAAcgBvAHAAZQByAHQAeQAgAEkAbgBzAHAAZ"
-      "QBjAHQAbwByAAAAAAD/////AAABrAD///8AAAMFAAAC8AAAAAEAAAACAAAAAQAAAAL8AAAAAQAAAAIAAAAP/////wAAAAAA/////wAAAAAAAAAA/"
+      "QBjAHQAbwByAAAAAAD/////AAABrAD///8AAAMRAAAC+QAAAAEAAAACAAAAAQAAAAL8AAAAAQAAAAIAAAAP/////wAAAAAA/////wAAAAAAAAAA/"
       "////wEAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/"
-      "////wEAAACK/////wAAAAAAAAAA/////wEAAADy/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/"
-      "////wAAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/////wEAAAFK/////wAAAAAAAAAA/"
-      "////wEAAAGB/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA"
+      "////wEAAACA/////wAAAAAAAAAA/////wEAAADo/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/"
+      "////wAAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA/////wEAAAE7/////wAAAAAAAAAA/"
+      "////wAAAAAA/////wAAAAAAAAAA/////wAAAAAA/////wAAAAAAAAAA"
     }
   }
   HideAutomaticNames	  on
@@ -86,9 +86,9 @@ Library {
   ModifiedByFormat	  "%<Auto>"
   LastModifiedBy	  "ezekiel.dohmen"
   ModifiedDateFormat	  "%<Auto>"
-  LastModifiedDate	  "Tue Apr 12 10:14:15 2022"
-  RTWModifiedTimeStamp	  571659248
-  ModelVersionFormat	  "1.%<AutoIncrement:404>"
+  LastModifiedDate	  "Tue May 31 15:00:36 2022"
+  RTWModifiedTimeStamp	  575910028
+  ModelVersionFormat	  "1.%<AutoIncrement:405>"
   SampleTimeColors	  off
   SampleTimeAnnotations	  off
   LibraryLinkDisplay	  "all"
@@ -1035,6 +1035,25 @@ Library {
     Block {
       BlockType		      Ground
     }
+    Block {
+      BlockType		      Inport
+      Port		      "1"
+      OutputFunctionCall      off
+      OutMin		      "[]"
+      OutMax		      "[]"
+      OutDataTypeStr	      "Inherit: auto"
+      LockScale		      off
+      BusOutputAsStruct	      off
+      Unit		      "inherit"
+      PortDimensions	      "-1"
+      VarSizeSig	      "Inherit"
+      SampleTime	      "-1"
+      SignalType	      "auto"
+      SamplingMode	      "auto"
+      LatchByDelayingOutsideSignal off
+      LatchInputForFeedbackSignals off
+      Interpolate	      on
+    }
     Block {
       BlockType		      Logic
       Operator		      "AND"
@@ -1067,6 +1086,29 @@ Library {
       BusObject		      "BusObject"
       NonVirtualBus	      off
     }
+    Block {
+      BlockType		      Outport
+      Port		      "1"
+      OutMin		      "[]"
+      OutMax		      "[]"
+      OutDataTypeStr	      "Inherit: auto"
+      LockScale		      off
+      BusOutputAsStruct	      off
+      Unit		      "inherit"
+      PortDimensions	      "-1"
+      VarSizeSig	      "Inherit"
+      SampleTime	      "-1"
+      SignalType	      "auto"
+      SamplingMode	      "auto"
+      EnsureOutportIsVirtual  off
+      SourceOfInitialOutputValue "Dialog"
+      OutputWhenDisabled      "held"
+      InitialOutput	      "[]"
+      MustResolveToSignalObject	off
+      OutputWhenUnConnected   off
+      OutputWhenUnconnectedValue "0"
+      VectorParamsAs1DForOutWhenUnconnected off
+    }
     Block {
       BlockType		      Product
       Inputs		      "2"
@@ -1192,7 +1234,7 @@ Library {
   }
   System {
     Name		    "CDS_PARTS"
-    Location		    [729, 64, 1765, 941]
+    Location		    [2110, 146, 3146, 1023]
     Open		    off
     PortBlocksUseCompactNotation off
     SetExecutionDomain	    off
@@ -1207,9 +1249,9 @@ Library {
     TiledPaperMargins	    [0.500000, 0.500000, 0.500000, 0.500000]
     TiledPageScale	    1
     ShowPageBoundaries	    off
-    ZoomFactor		    "100"
+    ZoomFactor		    "125"
     ReportName		    "simulink-default.rpt"
-    SIDHighWatermark	    "389"
+    SIDHighWatermark	    "392"
     SimulinkSubDomain	    "Simulink"
     Block {
       BlockType		      SubSystem
@@ -5047,8 +5089,8 @@ Library {
       RequestExecContextInheritance off
       System {
 	Name			"Osc/Phase"
-	Location		[729, 64, 1765, 941]
-	Open			on
+	Location		[2078, 203, 3114, 1080]
+	Open			off
 	PortBlocksUseCompactNotation off
 	SetExecutionDomain	off
 	ExecutionDomainType	"Deduce"
@@ -5979,8 +6021,8 @@ Library {
       RequestExecContextInheritance off
       System {
 	Name			"simLinkParts"
-	Location		[694, 249, 1730, 1296]
-	Open			off
+	Location		[2110, 146, 3146, 1023]
+	Open			on
 	PortBlocksUseCompactNotation off
 	SetExecutionDomain	off
 	ExecutionDomainType	"Deduce"
@@ -5994,7 +6036,7 @@ Library {
 	TiledPaperMargins	[0.500000, 0.500000, 0.500000, 0.500000]
 	TiledPageScale		1
 	ShowPageBoundaries	off
-	ZoomFactor		"100"
+	ZoomFactor		"125"
 	SimulinkSubDomain	"Simulink"
 	Block {
 	  BlockType		  Abs
@@ -6086,13 +6128,14 @@ Library {
 	  BackgroundColor	  "yellow"
 	  ShowName		  off
 	  AttributesFormatString  "%<Description>"
-	  LibraryVersion	  "1.281"
+	  LibraryVersion	  "1.453"
 	  UserDataPersistent	  on
 	  UserData		  "DataTag58"
 	  SourceBlock		  "simulink/Model-Wide\nUtilities/DocBlock"
 	  SourceType		  "DocBlock"
 	  SourceProductName	  "Simulink"
 	  SourceProductBaseCode	  "SL"
+	  ContentPreviewEnabled	  off
 	  DocumentType		  "Text"
 	}
 	Block {
@@ -6106,13 +6149,14 @@ Library {
 	  BackgroundColor	  "yellow"
 	  ShowName		  off
 	  AttributesFormatString  "%<Description>"
-	  LibraryVersion	  "1.281"
+	  LibraryVersion	  "1.453"
 	  UserDataPersistent	  on
 	  UserData		  "DataTag59"
 	  SourceBlock		  "simulink/Model-Wide\nUtilities/DocBlock"
 	  SourceType		  "DocBlock"
 	  SourceProductName	  "Simulink"
 	  SourceProductBaseCode	  "SL"
+	  ContentPreviewEnabled	  off
 	  DocumentType		  "Text"
 	}
 	Block {
@@ -6126,15 +6170,62 @@ Library {
 	  BackgroundColor	  "yellow"
 	  ShowName		  off
 	  AttributesFormatString  "%<Description>"
-	  LibraryVersion	  "1.281"
+	  LibraryVersion	  "1.453"
 	  UserDataPersistent	  on
 	  UserData		  "DataTag60"
 	  SourceBlock		  "simulink/Model-Wide\nUtilities/DocBlock"
 	  SourceType		  "DocBlock"
 	  SourceProductName	  "Simulink"
 	  SourceProductBaseCode	  "SL"
+	  ContentPreviewEnabled	  off
 	  DocumentType		  "Text"
 	}
+	Block {
+	  BlockType		  SubSystem
+	  Name			  "ExampleSubsystem"
+	  SID			  "390"
+	  Ports			  [1, 1]
+	  Position		  [10, 674, 110, 716]
+	  ZOrder		  1
+	  RequestExecContextInheritance	off
+	  ContentPreviewEnabled	  on
+	  System {
+	    Name		    "ExampleSubsystem"
+	    Location		    [2110, 146, 3146, 1023]
+	    Open		    off
+	    PortBlocksUseCompactNotation off
+	    SetExecutionDomain	    off
+	    ExecutionDomainType	    "Deduce"
+	    ModelBrowserVisibility  on
+	    ModelBrowserWidth	    200
+	    ScreenColor		    "white"
+	    PaperOrientation	    "landscape"
+	    PaperPositionMode	    "auto"
+	    PaperType		    "usletter"
+	    PaperUnits		    "inches"
+	    TiledPaperMargins	    [0.500000, 0.500000, 0.500000, 0.500000]
+	    TiledPageScale	    1
+	    ShowPageBoundaries	    off
+	    ZoomFactor		    "100"
+	    SimulinkSubDomain	    "Simulink"
+	    Block {
+	      BlockType		      Inport
+	      Name		      "input1"
+	      SID		      "391"
+	      Position		      [110, 103, 140, 117]
+	      ZOrder		      -1
+	      IconDisplay	      "Port number"
+	    }
+	    Block {
+	      BlockType		      Outport
+	      Name		      "output1"
+	      SID		      "392"
+	      Position		      [360, 103, 390, 117]
+	      ZOrder		      -2
+	      IconDisplay	      "Port number"
+	    }
+	  }
+	}
 	Block {
 	  BlockType		  Fcn
 	  Name			  "Fcn"
@@ -6238,6 +6329,12 @@ Library {
 	  LibraryVersion	  "1.2"
 	  SourceBlock		  "cdsSqrt/Subsystem"
 	  SourceType		  "SubSystem"
+	  ShowPortLabels	  "FromPortIcon"
+	  SystemSampleTime	  "-1"
+	  GeneratePreprocessorConditionals off
+	  AllowZeroVariantControls off
+	  PropagateVariantConditions off
+	  ContentPreviewEnabled	  off
 	}
 	Block {
 	  BlockType		  Saturate
@@ -6289,6 +6386,12 @@ Library {
 	  LibraryVersion	  "1.4"
 	  SourceBlock		  "cdsBitwise/Subsystem"
 	  SourceType		  "SubSystem"
+	  ShowPortLabels	  "FromPortIcon"
+	  SystemSampleTime	  "-1"
+	  GeneratePreprocessorConditionals off
+	  AllowZeroVariantControls off
+	  PropagateVariantConditions off
+	  ContentPreviewEnabled	  off
 	}
 	Annotation {
 	  SID			  "343"
diff --git a/src/epics/util/Makefile.kernel b/src/epics/util/Makefile.kernel
index 121633eac359ddff5137bb5ba194527fb6facfb5..a949ab6b350d81bacd088ba75c65ec148621aaa7 100644
--- a/src/epics/util/Makefile.kernel
+++ b/src/epics/util/Makefile.kernel
@@ -17,6 +17,12 @@ $(shell cp -rp $(RCG_SRC)/src/fe/ $(mkfile_dir)/src/)
 $(shell cp -rp $(RCG_SRC)/src/drv/ $(mkfile_dir)/src/)
 $(shell cp -rp $(RCG_SRC)/src/shmem/ $(mkfile_dir)/src/)
 
+# We always want to take these values from the below 
+# KernelVars.mk script and not the ENV
+undefine IOP_MODEL
+undefine BUILD_WITH_DOLPHIN
+
+
 # Include the generated make variables, written by
 # the feCodeGen.pl script.
 include $(mkfile_dir)/KernelVars.mk
diff --git a/src/epics/util/Userspace_CMakeLists.cmake b/src/epics/util/Userspace_CMakeLists.cmake
index 219f6fbeb9373a9c069074ec42c70375f425e6f4..5fd1b234a4b5378dab5886c9582e5bc2f33bf0d3 100644
--- a/src/epics/util/Userspace_CMakeLists.cmake
+++ b/src/epics/util/Userspace_CMakeLists.cmake
@@ -22,6 +22,10 @@ if(${USE_STDLIB_MATH})
     list(APPEND CFLAGS "-DUSE_STDLIB_MATH=1") 
 endif()
 
+if(${DEFAULT_TO_SHMEM_BUFFERS})
+    list(APPEND CFLAGS "-DDEFAULT_TO_SHMEM_BUFFERS=1")
+endif()
+
 # Turn the ; seperated list into space seperated list and add to CFLAGS
 string(REPLACE ";" " " CFLAGS_SPACE_SEPERATED "${CFLAGS}")
 set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CFLAGS_SPACE_SEPERATED}" )
@@ -39,7 +43,7 @@ list(APPEND COMMON_SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_NAME}_core.c"
                      "${CMAKE_CURRENT_SOURCE_DIR}/src/include/drv/daqLib.c"
                      "${CMAKE_CURRENT_SOURCE_DIR}/src/fe/rcguserCommon.c"
                      "${CMAKE_CURRENT_SOURCE_DIR}/src/fe/commDataUsp.c"
-                     "${CMAKE_CURRENT_SOURCE_DIR}/src/drv/rfm.c")
+                     "${CMAKE_CURRENT_SOURCE_DIR}/src/drv/shmem.c")
 
 
 if(BUILD_USP_GPSCLOCK)
@@ -69,6 +73,8 @@ list(APPEND LIB_SRC_LIST ${COMMON_SRC_LIST} "${CMAKE_CURRENT_SOURCE_DIR}/src/fe/
 add_library(${LIB_NAME} ${LIB_SRC_LIST})
 target_include_directories(${LIB_NAME} PUBLIC ${INC_DIRS})
 
+target_link_libraries(${LIB_NAME} PUBLIC -lrt)
+
 if (${USE_STDLIB_MATH})
     target_link_libraries(${LIB_NAME} PUBLIC -lm)
 endif()
diff --git a/src/epics/util/lib/Parser3.pm b/src/epics/util/lib/Parser3.pm
index ebaa59d72baa23302d91b1d789fc98bcca74fac1..e854a32a82266819f659b224ed1d42ed40cfb472 100644
--- a/src/epics/util/lib/Parser3.pm
+++ b/src/epics/util/lib/Parser3.pm
@@ -643,7 +643,7 @@ sub node_processing {
 		return 1; # Do not call this function on leaves, we already did that
 	} elsif ($block_type eq "Reference") {
                 if ($source_block =~ /cdsIPCx/) {
-                   if ($block_name !~ /[CGHKLMSX]\d\:/) {
+                   if ($block_name !~ /[A-Z]\d\:/) {
                       die "***ERROR: Signal name of IPCx module must include IFO: $block_name\n";
                    }
                 }
diff --git a/src/epics/util/lib/createEpicsMakefile.pm b/src/epics/util/lib/createEpicsMakefile.pm
index 9d62d2ad001ac744993b33306cc451de73ef5b30..636475c861ff67556c6f46dd7a6ae3aa66a94cb5 100644
--- a/src/epics/util/lib/createEpicsMakefile.pm
+++ b/src/epics/util/lib/createEpicsMakefile.pm
@@ -30,11 +30,10 @@ my ($fileName) = @_;
 	print OUTME "SRC += $::rcg_src_dir/src/epics/seq/main.cc\n";
 	}
 	print OUTME "SRC += $::rcg_src_dir/src/epics/seq/sdf_file_loaded.c\n";
-	print OUTME "SRC += $::rcg_src_dir/src/drv/rfm.c\n";
+	print OUTME "SRC += $::rcg_src_dir/src/drv/shmem.c\n";
 	print OUTME "SRC += $::rcg_src_dir/src/drv/param.c\n";
 	print OUTME "SRC += $::rcg_src_dir/src/drv/crc.c\n";
 	print OUTME "SRC += $::rcg_src_dir/src/drv/fmReadCoeff.c\n";
-	#print OUTME "SRC += src/epics/seq/get_local_time.st\n";
 	if ($::userspacegps)
 	{
 		print OUTME "SRC += $::rcg_src_dir/src/drv/gpsclock.c\n";
@@ -46,7 +45,6 @@ my ($fileName) = @_;
 		print OUTME "\L\.st\n";
 	}
 	print OUTME "\n";
-	#print OUTME "DB += src/epics/db/local_time.db\n";
 	print OUTME "DB += \$(MODEL_EPICS_SRC_DIR)/";
 	print OUTME "$::skeleton";
 	print OUTME "1\.db\n";
diff --git a/src/epics/util/lib/createUserModuleBuildEnv.pm b/src/epics/util/lib/createUserModuleBuildEnv.pm
index eb93f690b7ef224eb0a3b690f67ea21365f47f50..64eb29d814287071bd6e3632cc8973fb51d382eb 100644
--- a/src/epics/util/lib/createUserModuleBuildEnv.pm
+++ b/src/epics/util/lib/createUserModuleBuildEnv.pm
@@ -28,7 +28,7 @@ my ($makefileDir) = @_;
         print OUTM "set(XMIT_DOLPHIN_TIME YES)\n";
     }
 
-    print OUTM "list(APPEND CFLAGS \"-O2\")\n";
+    print OUTM "list(APPEND CFLAGS \"-O2 -fPIC\")\n";
     print OUTM "list(APPEND CFLAGS \"$::servoflag\")\n";
 
     if ($::iopModel > -1) {  #************ SETUP FOR IOP ***************
diff --git a/src/epics/util/skeleton.st b/src/epics/util/skeleton.st
index 01335bebbc31f3c9fc56cfd94342ca085785aeec..8a01f1fd13903740b780b6219a15ff9f550d9e9a 100644
--- a/src/epics/util/skeleton.st
+++ b/src/epics/util/skeleton.st
@@ -35,7 +35,7 @@ program %SEQUENCER_NAME%
 %% #define FM_SUBSYS_NUM  1
 %% #include "fmReadCoeff.h"
 %% #include "feComms.h"
-%% #include "findSharedMemory.h"
+%% #include "drv/shmem.h"
 %% #include "sdf_file_loaded.h"
 %% #define FE_ERROR_CFC 0x400
 
@@ -68,6 +68,7 @@ program %SEQUENCER_NAME%
 %DECL1%
 
 #if defined(RFM_EPICS)
+%% static shmem_handle g_rfm_shm_handle = NULL; 
 %% static volatile RFM_FE_COMMS *pRfm;
 %% static volatile VME_COEF *pVmeCoeff;
 %% static volatile FILT_MOD *pFilt;
@@ -200,6 +201,9 @@ int prev_seqTrig = 0;
 %% static fmReadCoeff fmc = {
 %%  "lho", "h1", "xxx", 0, {{"", "", MAX_MODULES, fmmap0, 0}},
 %% };
+%% char system_lower[ 128 ];
+%% char *s_hold;
+
 
 %% static const double conv = 0.000152588;
 %% static const int mask[2] = {0xAAA0,0x30AA};
@@ -301,15 +305,16 @@ assign tcsEnable to "{ifo}:TCS-SERVO_EN";
 
 
 %% static DAQ_INFO_BLOCK *info;
+%% static shmem_handle  g_base_shm_handle = NULL;
 %% static volatile void *base;
 %% static DAQ_INFO_BLOCK infoTmp;
 %% static GDS_INFO_BLOCK gdsTmp;
+%% static shmem_handle g_gdsInfo_shm_handle = NULL;
 %% static GDS_INFO_BLOCK *gdsInfo;
 %% static char site[160];
 %% static char ifo[160];
 %% static char daqsys[160];
 %% static char gdssmname[64];
-%% static char gdssmname[64];
 %% static int last_gds_tp[32];
 
 %% char fName[4][256];                                                   /* MA */
@@ -360,6 +365,16 @@ assign tcsEnable to "{ifo}:TCS-SERVO_EN";
 %%   gdsInfo->totalchans = gdsTmp.totalchans;
 %% }
 
+%% static void detach_shmem() {
+#ifndef NO_DAQ_IN_SKELETON
+%%   shmem_close(g_base_shm_handle);
+#endif
+#if defined(RFM_EPICS)
+%%   shmem_close(g_rfm_shm_handle);
+%%   shmem_close(g_gdsInfo_shm_handle);
+#endif 
+%% }
+
 
 ss monitorFilt{
  
@@ -417,12 +432,18 @@ state init
 %%	}
 %%    }
 %%  }
-%% strcpy(gdssmname,fmc.system);
-%% strcat(gdssmname,"_gds");
+
+%% //Convert the system (model) name to a lower case version
+%% strcpy(system_lower, fmc.system);
+%% for(s_hold = system_lower; *s_hold; s_hold++) *s_hold=tolower(*s_hold);
+%% strcpy(gdssmname, system_lower);
+%% strcat(gdssmname, "_gds");
+
 
 #if defined(RFM_EPICS)
 %%  printf("Init Sequencer %s; system %d fmcsystem = %s\n", fmc.subSys[0].name, sysnum,fmc.system);
-%%  pRfm = (RFM_FE_COMMS *) findSharedMemory(fmc.system);
+%%  g_rfm_shm_handle = shmem_open(system_lower, DEFAULT_SHMEM_ALLOC_SIZE_MB);
+%%  pRfm = (RFM_FE_COMMS *) shmem_mapping(g_rfm_shm_handle);
 %%  pFilt = (FILT_MOD *)(&pRfm->%EPICS_FILT_VAR%);
 %%  pVmeCoeff = (VME_COEF*)(&pRfm->%EPICS_COEFF_VAR%);
 %%  pEpics = (%EPICS_TYPE%*)(&pRfm->%EPICS_EPICS_VAR%);
@@ -433,10 +454,13 @@ state init
 %%  printf("%s pVmeCoeff size is 0x%lx\n", fmc.subSys[0].name, sizeof(*pVmeCoeff));
 %%  printf("%s pEpics is at 0x%lx\n", fmc.subSys[0].name, ((unsigned long)pEpics-(unsigned long)pRfm));
 %%  printf("%s pEpics is at 0x%lx\n", fmc.subSys[0].name, ((unsigned long)pRfm));
-%%  gdsInfo = (GDS_INFO_BLOCK *) findSharedMemory(gdssmname);
+%%  g_gdsInfo_shm_handle = shmem_open(gdssmname, DEFAULT_SHMEM_ALLOC_SIZE_MB); 
+%%  gdsInfo = (GDS_INFO_BLOCK *) shmem_mapping(g_gdsInfo_shm_handle);
 %%  printf("%s gdsinfo is at 0x%lx\n", gdssmname, (unsigned long)gdsInfo);
 #endif
 
+atexit(detach_shmem);
+
 %% strcpy(fName[0], "/opt/rtcds/");                                        /* MA */
 %% strcat_lower(fName[0], fmc.site);                                     /* MA */
 %% strcat(fName[0], "/");                                          /* MA */
@@ -924,7 +948,17 @@ state daqInit
         strcpy(site, macValueGet("site"));
         strcpy(ifo, macValueGet("ifo"));
         strcpy(daqsys, macValueGet("sysfile"));
-%%      base = findSharedMemory(daqsys);
+
+%%      strcpy(system_lower, daqsys);
+%%      for(s_hold = system_lower; *s_hold; s_hold++) *s_hold=tolower(*s_hold);
+%%
+%%      g_base_shm_handle = shmem_open(system_lower, DEFAULT_SHMEM_ALLOC_SIZE_MB);
+%%      if (g_base_shm_handle == 0) {
+%%          fprintf(stderr, "shmem_open failed, buffer name %s.\n", system_lower);
+%%          exit(1);
+%%      }
+%% 
+%%      base = shmem_mapping(g_base_shm_handle);
 %%      info = (DAQ_INFO_BLOCK *)(base + DAQ_INFO_ADDRESS);
         pvPut(dcuId);
 %%      rfm_assign(pEpics->epicsInput.dcuId, dcuId);
diff --git a/src/fe/controllerApp.c b/src/fe/controllerApp.c
index 782a483b00d7a924f02e2f0760bf9040a3ff7106..b18a103b44bb1faf8be7698081968bdd40a0c82d 100644
--- a/src/fe/controllerApp.c
+++ b/src/fe/controllerApp.c
@@ -36,7 +36,7 @@
 #include "modelRateInfo.h"
 #include "fm10Gen.h"
 #include "util/printl.h"
-
+#include "util/kernel/exit_signaling.h"
 #include "../fe/timing_common.h" //captureEocTiming
 #include "../fe/timing_kernel.h"
 
@@ -204,6 +204,8 @@ fe_start_controller( void )
     if ( initVars( pDsp[ 0 ], pDsp[ 0 ], dspCoeff, MAX_MODULES, pCoeff[ 0 ] ) )
     {
         pLocalEpics->epicsOutput.fe_status = FILT_INIT_ERROR;
+        wait_for_exit_signal();
+        atomic_set(&g_atom_has_exited, 1);
         return;
     }
 
@@ -243,6 +245,8 @@ fe_start_controller( void )
     {
         pLocalEpics->epicsOutput.fe_status = DAQ_INIT_ERROR;
         vmeDone = 1;
+        wait_for_exit_signal();
+        atomic_set(&g_atom_has_exited, 1);
         return;
     }
 #endif
@@ -287,6 +291,8 @@ fe_start_controller( void )
     if ( status )
     {
         pLocalEpics->epicsOutput.fe_status = DAC_INIT_ERROR;
+        wait_for_exit_signal();
+        atomic_set(&g_atom_has_exited, 1);
         return;
     }
 
@@ -385,6 +391,8 @@ fe_start_controller( void )
                 pLocalEpics->epicsOutput.diagWord |= ADC_TIMEOUT_ERR;
                 pLocalEpics->epicsOutput.fe_status = ADC_TO_ERROR;
                 deallocate_dac_channels( );
+                wait_for_exit_signal();
+                atomic_set(&g_atom_has_exited, 1);
                 return;
             }
 
@@ -497,7 +505,7 @@ fe_start_controller( void )
         // *****************************************************************
         /// \> Check if code exit is requested
         if ( cycleNum == MAX_MODULES )
-            vmeDone = stop_working_threads |
+            vmeDone =  atomic_read(&g_atom_should_exit) |
                 checkEpicsReset( cycleNum, (struct CDS_EPICS*)pLocalEpics );
         // *****************************************************************
 
@@ -673,5 +681,6 @@ fe_start_controller( void )
     deallocate_dac_channels( );
 
     /* System reset command received */
+    atomic_set(&g_atom_has_exited, 1);
     return;
 }
diff --git a/src/fe/controllerIop.c b/src/fe/controllerIop.c
index 259f7b166fb42abb8467d2954b61ae28c140c802..942d28f4343f0391de0067ab773a1b3c1a93d463 100644
--- a/src/fe/controllerIop.c
+++ b/src/fe/controllerIop.c
@@ -37,6 +37,7 @@
 #include "fm10Gen_types.h"
 #include "controller.h"
 #include "modelRateInfo.h"
+#include "util/kernel/exit_signaling.h"
 #include "drv/daqLib.h"
 #include "../fe/timing_kernel.h"
 #include "../fe/sync21pps.h"
@@ -256,6 +257,8 @@ fe_start_controller( void )
     {
         pLocalEpics->epicsOutput.fe_status = FILT_INIT_ERROR;
         fe_status_return = FILT_INIT_ERROR;
+        wait_for_exit_signal();
+        atomic_set(&g_atom_has_exited, 1);
         return;
     }
 
@@ -291,6 +294,8 @@ fe_start_controller( void )
         pLocalEpics->epicsOutput.fe_status = DAQ_INIT_ERROR;
         fe_status_return = DAQ_INIT_ERROR;
         vmeDone = 1;
+        wait_for_exit_signal();
+        atomic_set(&g_atom_has_exited, 1);
         return;
     }
 
@@ -619,7 +624,7 @@ fe_start_controller( void )
             pLocalEpics->epicsOutput.diagWord |= ADC_TIMEOUT_ERR;
             pLocalEpics->epicsOutput.fe_status = ADC_TO_ERROR;
             pLocalEpics->epicsOutput.epicsSync++;
-            stop_working_threads = 1;
+            atomic_set(&g_atom_should_exit, 1);
             vmeDone = 1;
             continue;
         }
@@ -631,7 +636,7 @@ fe_start_controller( void )
             feStatus |= adc_status_update( &adcinfo );
             pLocalEpics->epicsOutput.stateWord = FE_ERROR_ADC;
             pLocalEpics->epicsOutput.fe_status = CHAN_HOP_ERROR;
-            stop_working_threads = 1;
+            atomic_set(&g_atom_should_exit, 1);
             vmeDone = 1;
             pLocalEpics->epicsOutput.epicsSync++;
             continue;
@@ -884,7 +889,7 @@ fe_start_controller( void )
             // *****************************************************************
             /// \> Check if code exit is requested
             if ( cycleNum == MAX_MODULES )
-                vmeDone = stop_working_threads |
+                vmeDone = atomic_read(&g_atom_should_exit) |
                     checkEpicsReset( cycleNum, (struct CDS_EPICS*)pLocalEpics );
 
             // *****************************************************************
@@ -1249,5 +1254,6 @@ fe_start_controller( void )
     pLocalEpics->epicsOutput.cpuMeter = 0;
 
     /* System reset command received */
+    atomic_set(&g_atom_has_exited, 1);
     return;
 }
diff --git a/src/fe/map.c b/src/fe/map.c
index 790e981b447e87db33a2b57b2b320849e4c93374..9199ee32ce407c79a19f6280bcb4f1b668981f20 100644
--- a/src/fe/map.c
+++ b/src/fe/map.c
@@ -157,7 +157,7 @@ mapPciModulesVirtual( CDS_HARDWARE* pCds )
     {
         if ( pCds->cards_used[ i ].type == GSC_18AO8 )
         {
-            sprintf( fname, "%s_%d\n", "IO_DEV_", i );
+            sprintf( fname, "%s_%d", "IO_DEV_", i );
             ret = mbuf_allocate_area( fname, 8 * 4 * 65536, (volatile void **)&_device_shm );
             if ( ret != MBUF_KERNEL_CODE_OK )
             {
@@ -174,7 +174,7 @@ mapPciModulesVirtual( CDS_HARDWARE* pCds )
         }
         if ( pCds->cards_used[ i ].type == GSC_16AO16 )
         {
-            sprintf( fname, "%s_%d\n", "IO_DEV_", i );
+            sprintf( fname, "%s_%d", "IO_DEV_", i );
             ret = mbuf_allocate_area( fname, 16 * 4 * 65536, (volatile void **)&_device_shm );
             if ( ret != MBUF_KERNEL_CODE_OK )
             {
@@ -191,7 +191,7 @@ mapPciModulesVirtual( CDS_HARDWARE* pCds )
         }
         if ( pCds->cards_used[ i ].type == GSC_20AO8 )
         {
-            sprintf( fname, "%s_%d\n", "IO_DEV_", i );
+            sprintf( fname, "%s_%d", "IO_DEV_", i );
             ret = mbuf_allocate_area( fname, 8 * 4 * 65536, (volatile void **)&_device_shm );
             if ( ret != MBUF_KERNEL_CODE_OK )
             {
@@ -208,7 +208,7 @@ mapPciModulesVirtual( CDS_HARDWARE* pCds )
         }
         if ( pCds->cards_used[ i ].type == GSC_16AI64SSA )
         {
-            sprintf( fname, "%s_%d\n", "IO_DEV_", i );
+            sprintf( fname, "%s_%d", "IO_DEV_", i );
             ret = mbuf_allocate_area( fname, 32 * 4 * 128, (volatile void **)&_device_shm );
             if ( ret != MBUF_KERNEL_CODE_OK )
             {
diff --git a/src/fe/moduleLoad.c b/src/fe/moduleLoad.c
index 573c7dfca2b229f5c74fdd4a71724508f28a0bd8..58d6b4f76cc3b4b1059683cc08d2a9c90fe49c0a 100644
--- a/src/fe/moduleLoad.c
+++ b/src/fe/moduleLoad.c
@@ -8,6 +8,8 @@
 #include "verify_card_count.h"
 #include "print_io_info.h"
 #include "util/printl.h"
+#include "util/timing.h"
+#include "util/kernel/exit_signaling.h"
 #include "drv/map.h" //mapPciModules()
 #include "drv/ligoPcieTiming.h"
 #include "../fe/verify_slots.h"
@@ -29,10 +31,18 @@ extern void  fe_start_controller( void );
 //
 // File function prototypes
 //
-void rt_fe_cleanup( void );
-int rt_fe_init( void );
+static void rt_fe_cleanup( void );
+static int rt_fe_init( void );
+
+//
+// Signaling variables for proper module shutdown logic
+atomic_t g_atom_should_exit = ATOMIC_INIT(0);
+atomic_t g_atom_has_exited = ATOMIC_INIT(0);
 
 
+//
+// This symbol is used to enforce the IOP model
+// is first loaded, before any app models
 #ifdef IOP_MODEL
 int need_to_load_IOP_first;
 EXPORT_SYMBOL( need_to_load_IOP_first );
@@ -55,14 +65,13 @@ static int  fe_start_controller_kthread( void * arg )
     fe_start_controller();
     return 0;
 }
-
 #endif //NO_CPU_SHUTDOWN
 
-// MAIN routine: Code starting point
+
+// Linux Module init: Code starting point
 // ****************************************************************
 /// Startup function for initialization of kernel module.
-int
-rt_fe_init( void )
+static int __init rt_fe_init( void )
 {
     int jj, kk; /// @param ii,jj,kk default loop counters
     int cards; /// @param cards Number of PCIe cards found on bus
@@ -85,7 +94,7 @@ rt_fe_init( void )
 
 #ifndef NO_CPU_SHUTDOWN
     /// Verify requested core is free.
-    if ( is_cpu_taken_by_rcg_model( CPUID ) )
+    if ( is_cpu_occupied( CPUID ) )
     {
         printl( KERN_ALERT "Error: CPU %d already taken\n", CPUID );
         return -1;
@@ -141,7 +150,6 @@ rt_fe_init( void )
     {
         pLocalEpics->epicsOutput.fe_status = IO_CARD_MAP_ERROR;
         rt_fe_cleanup( );
-        detach_shared_memory();
         return -5;
     }
 
@@ -151,7 +159,6 @@ rt_fe_init( void )
         printl( "" SYSTEM_NAME_STRING_LOWER
                 ": ERROR: No ADC cards found - exiting\n" );
         rt_fe_cleanup( );
-        detach_shared_memory();
         return -5;
     }
 
@@ -231,7 +238,6 @@ rt_fe_init( void )
         printl( "" SYSTEM_NAME_STRING_LOWER
                 ": ERROR: Exit on incorrect card count \n" );
         rt_fe_cleanup( );
-        detach_shared_memory();
         return -5;
     }
 #endif
@@ -262,7 +268,7 @@ rt_fe_init( void )
     printl( "" SYSTEM_NAME_STRING_LOWER ": Locking CPU core %d\n", CPUID );
 
     // The code runs on the disabled CPU
-    set_fe_code_idle( fe_start_controller, CPUID );
+    set_rt_callback( fe_start_controller, CPUID );
     msleep( 100 );
     rts_isolator_exec( CPUID );
 
@@ -270,40 +276,49 @@ rt_fe_init( void )
     return 0;
 }
 
+void wait_for_module_exit(void)
+{
+    uint64_t stop_sig_time_ns = getMonotonic_ns_utin64();
+    if( is_cpu_occupied(CPUID) )
+    {
+        set_rt_callback( 0, CPUID );
+        
+        // Wait for the module to signal that it has exited
+        while (atomic_read(&g_atom_has_exited) == 0)
+        {
+            msleep( 1 );
+        }
+
+        printl("It took %lld ms for the RT code to exit.\n",
+                 (getMonotonic_ns_utin64() - stop_sig_time_ns)/1000000);
+
+        set_rt_callback( 0, CPUID );
+        msleep( 1000 );
+
+        // Bring the CPU back up
+        rts_isolator_cleanup( CPUID );
+    }
+}
+
 /// Kernel module cleanup function
-void
-rt_fe_cleanup( void )
+static void __exit rt_fe_cleanup( void )
 {
-#ifndef NO_CPU_SHUTDOWN
-    /// Unset the code callback
-    set_fe_code_idle( 0, CPUID );
-#endif
 
-    // printl("Setting stop_working_threads to 1\n");
-    // Stop the code and wait
+    // Signal the model to stop
+    atomic_set(&g_atom_should_exit, 1);
+
 #ifdef NO_CPU_SHUTDOWN
     kthread_stop( sthread );
-#endif
-    stop_working_threads = 1;
     msleep( 1000 );
+#else
+    wait_for_module_exit();
+#endif
 
 #ifdef DOLPHIN_TEST
     /// Cleanup Dolphin card connections
     finish_dolphin( );
 #endif
 
-#ifndef NO_CPU_SHUTDOWN
-
-    /// Bring the CPU core back on line
-    // Unset the code callback
-    set_fe_code_idle( 0, CPUID );
-    // printll("Will bring back CPU %d\n", CPUID);
-    msleep( 1000 );
-    // Bring the CPU back up
-    rts_isolator_cleanup( CPUID );
-    msleep( 1000 );
-#endif
-
     // Print out any error messages from FE code on exit
     print_exit_messages( fe_status_return, fe_status_return_subcode, SYSTEM_NAME_STRING_LOWER );
     detach_shared_memory( );
diff --git a/src/fe/rcguser.c b/src/fe/rcguser.c
index b25d8594a514ab72d01afb2e926a21faf5ce51b6..a803868f89896b325dcac202a5051a1c5b8e3561 100644
--- a/src/fe/rcguser.c
+++ b/src/fe/rcguser.c
@@ -37,7 +37,7 @@ extern int   fe_start_app_user( );
 int
 main( int argc, char** argv )
 {
-    int  status = 0;
+    int  status = 0, mainReturn = 0;
     int  ii, jj, kk; /// @param ii,jj,kk default loop counters
     char fname[ 128 ]; /// @param fname[128] Name of shared mem area to allocate
                        /// for DAQ data
@@ -78,7 +78,6 @@ main( int argc, char** argv )
     printl( "configured to use %d cards\n", cards );
     cdsPciModules.cards = cards;
     cdsPciModules.cards_used = cards_used;
-    // return -1;
     printl( "Initializing PCI Modules\n" );
     cdsPciModules.adcCount = 0;
     cdsPciModules.dacCount = 0;
@@ -99,7 +98,8 @@ main( int argc, char** argv )
     if ( !cdsPciModules.adcCount )
     {
         printl( "No ADC cards found - exiting\n" );
-        return -1;
+        mainReturn = -1;
+        goto cleanup;
     }
     printl( "%d PCI cards found \n", status );
     if ( status < cards )
@@ -135,7 +135,8 @@ main( int argc, char** argv )
     }
     if ( cnt == 10 )
     {
-        return -1;
+        mainReturn = -1;
+        goto cleanup;
     }
 
     pLocalEpics->epicsInput.vmeReset = 0;
@@ -147,5 +148,9 @@ main( int argc, char** argv )
     // Start the control loop software
     fe_start_app_user( );
 
-    return 0;
+    cleanup:
+    detach_shared_memory();
+
+    return mainReturn;
+
 }
diff --git a/src/fe/rcguserCommon.c b/src/fe/rcguserCommon.c
index d02fdf309b4006362cf4498079281f70a2e89e86..189d861f75fbf24c4b38b963525fb87c56c32530 100644
--- a/src/fe/rcguserCommon.c
+++ b/src/fe/rcguserCommon.c
@@ -3,11 +3,13 @@
 
 #include "print_io_info.h"
 #include "controller.h"
-#include "findSharedMemory.h"
 #include "util/printl.h"
+#include "drv/shmem.h"
 
 #include <stddef.h>
 #include <stdio.h>
+#include <string.h>
+#include <ctype.h>
 
 // **********************************************************************************************
 // Capture SIGHALT from ControlC
@@ -22,81 +24,111 @@ intHandler( int signal)
 // **********************************************************************************************
 
 int
-attach_shared_memory( char* sysname )
+attach_shared_memory( const char* sysname )
 {
 
+    char * s;
     char         shm_name[ 64 ];
+    char         sysname_lower[ 64 ];
+
+    //Build lower case version of the system (model) name
+    strcpy(sysname_lower, sysname);
+    for(s = sysname_lower; *s; s++) *s = tolower(*s);
+
 
     // epics shm used to communicate with model's EPICS process
-    sprintf( shm_name, "%s", sysname );
-    _epics_shm = (volatile char*) findSharedMemory( sysname );
-    if ( _epics_shm == NULL )
+    g_epics_shm_handle = shmem_open(sysname_lower, SHMEM_EPICS_SIZE_MB);
+    if ( g_epics_shm_handle == NULL )
     {
-        printl( "mbuf_allocate_area() failed; ret = %p\n", _epics_shm );
+        printl( "shmem_open(%s, %d) failed; ret = %d\n",
+                sysname, SHMEM_EPICS_SIZE_MB, g_epics_shm_handle );
         return -1;
     }
+    _epics_shm = shmem_mapping(g_epics_shm_handle);
     printl( "EPICSM at %p\n", _epics_shm );
 
     // testpoint config shm used to control testpoints from awgtpman
-    sprintf( shm_name, "%s%s", sysname, SHMEM_TESTPOINT_SUFFIX );
-    _tp_shm = (volatile TESTPOINT_CFG *) findSharedMemory( sysname );
-    if ( _tp_shm == NULL )
+    sprintf( shm_name, "%s%s", sysname_lower, SHMEM_TESTPOINT_SUFFIX );
+    g_tp_shm_handle = shmem_open(shm_name, SHMEM_TESTPOINT_SIZE_MB);
+    if ( g_tp_shm_handle == NULL )
     {
-        printl( "mbuf_allocate_area(tp) failed; ret = %p\n", _tp_shm );
+        printl( "shmem_open(%s, %d) failed; ret = %d\n",
+                shm_name, SHMEM_TESTPOINT_SIZE_MB, g_tp_shm_handle );
         return -1;
     }
+    _tp_shm = shmem_mapping(g_tp_shm_handle);
     printl( "TPSM at %p\n", _tp_shm );
     
     // awg data shm used to stream data from awgtpman
-    sprintf( shm_name, "%s%s", sysname, SHMEM_AWG_SUFFIX );
-    _awg_shm = (volatile AWG_DATA *) findSharedMemory( sysname );
-    if ( _awg_shm == NULL )
+    sprintf( shm_name, "%s%s", sysname_lower, SHMEM_AWG_SUFFIX );
+    g_awg_shm_handle = shmem_open(shm_name, SHMEM_AWG_SIZE_MB);
+    if ( g_awg_shm_handle == NULL )
     {
-        printl( "mbuf_allocate_area(awg) failed; ret = %p\n", _awg_shm );
+        printl( "shmem_open(%s, %d) failed; ret = %d\n", 
+                shm_name, SHMEM_AWG_SIZE_MB, g_awg_shm_handle );
         return -1;
     }
+    _awg_shm = shmem_mapping(g_awg_shm_handle);
     printl( "AWGSM at %p\n", _awg_shm );
     
     // ipc_shm used to communicate with IOP
-    _ipc_shm = (char*)findSharedMemory( "ipc" );
-    if ( _ipc_shm == NULL )
+    g_ipc_shm_handle = shmem_open( SHMEM_IOMEM_NAME, SHMEM_IOMEM_SIZE_MB);
+    if ( g_ipc_shm_handle == NULL )
     {
-        printl( "mbuf_allocate_area(ipc) failed; ret = %p\n", _ipc_shm );
+        printl( "shmem_open(%s, %d) failed; ret = %d\n",
+                SHMEM_IOMEM_NAME, SHMEM_IOMEM_SIZE_MB, g_ipc_shm_handle );
         return -1;
     }
+    _ipc_shm = shmem_mapping(g_ipc_shm_handle);
     printl( "IPC    at %p\n", _ipc_shm );
     ioMemData = (volatile IO_MEM_DATA*)( ( (char*)_ipc_shm ) + 0x4000 );
     printl("IOMEM  at %p size 0x%lx\n", ioMemData, sizeof( IO_MEM_DATA ) );
     printl( "%d PCI cards found\n", ioMemData->totalCards );
 
     // DAQ is via shared memory
-    sprintf( shm_name, "%s_daq", sysname );
-    _daq_shm = (char*) findSharedMemory( shm_name );
-    if ( _daq_shm == NULL )
+    sprintf( shm_name, "%s_daq", sysname_lower );
+    g_daq_shm_handle = shmem_open(shm_name, DEFAULT_SHMEM_ALLOC_SIZE_MB);
+    if ( g_daq_shm_handle == NULL )
     {
-        printl( "mbuf_allocate_area() failed; ret = %p\n", _daq_shm );
+        printl( "shmem_open(%s, %d) failed; ret = %d\n",
+                shm_name, DEFAULT_SHMEM_ALLOC_SIZE_MB, g_daq_shm_handle );
         return -1;
     }
+    _daq_shm = shmem_mapping(g_daq_shm_handle);
     printl( "DAQSM at %p\n", _daq_shm );
     daqPtr = (struct rmIpcStr*)_daq_shm;
 
     // shmipc is used to send SHMEM IPC data between processes on same computer
-    _shmipc_shm = (char*) findSharedMemory( "shmipc" );
-    if ( _shmipc_shm == NULL )
+    g_shmipc_shm_handle = shmem_open(SHMEM_IPCCOMMS_NAME, SHMEM_IPCCOMMS_SIZE_MB); 
+    if ( g_shmipc_shm_handle == NULL )
     {
-        printl( "mbuf_allocate_area() failed; ret = %p\n", _shmipc_shm );
+        printl( "shmem_open(%s, %d) failed; ret = %d\n",
+                SHMEM_IPCCOMMS_NAME, SHMEM_IPCCOMMS_SIZE_MB, g_shmipc_shm_handle );
         return -1;
     }
+    _shmipc_shm = shmem_mapping(g_shmipc_shm_handle);
 
     // Open new IO shared memory in support of no hardware I/O
-    _io_shm = (char*) findSharedMemory( "virtual_io_space" );
-    if ( _io_shm == NULL )
+    g_io_shm_handle = shmem_open("virtual_io_space", DEFAULT_SHMEM_ALLOC_SIZE_MB);
+    if ( g_io_shm_handle == NULL )
     {
-        printl( "mbuf_allocate_area() failed; ret = %p\n", _io_shm );
+        printl( "shmem_open(%s, %d) failed; ret = %d\n",
+                "virtual_io_space", DEFAULT_SHMEM_ALLOC_SIZE_MB, g_io_shm_handle );
         return -1;
     }
+    _io_shm = shmem_mapping(g_io_shm_handle);
     ioMemDataIop = (volatile IO_MEM_DATA_IOP*)( ( (char*)_io_shm ) );
 
     return 0;
 }
 
+void detach_shared_memory()
+{
+    shmem_close(g_epics_shm_handle);
+    shmem_close(g_tp_shm_handle);
+    shmem_close(g_awg_shm_handle);
+    shmem_close(g_ipc_shm_handle);
+    shmem_close(g_daq_shm_handle);
+    shmem_close(g_shmipc_shm_handle);
+    shmem_close(g_io_shm_handle);
+}
diff --git a/src/fe/rcguserCommon.h b/src/fe/rcguserCommon.h
index a96b62aa093bf0852db792f3893e4c914e9813d4..d4112f994c7e9e0a2c5711c621baf6014bf28e17 100644
--- a/src/fe/rcguserCommon.h
+++ b/src/fe/rcguserCommon.h
@@ -6,7 +6,8 @@ extern "C" {
 #endif
 
 void intHandler( int dummy );
-int attach_shared_memory( char* sysname );
+int attach_shared_memory( const char* sysname );
+void detach_shared_memory();
 
 #ifdef __cplusplus
 }
diff --git a/src/fe/rcguserIop.c b/src/fe/rcguserIop.c
index fa8e1345893a3fec6cd9829ae28f1109214b4897..ce6200baa466d6f5fad0a0288aa29498d9a603c5 100644
--- a/src/fe/rcguserIop.c
+++ b/src/fe/rcguserIop.c
@@ -19,7 +19,6 @@
 
 #include "rcguserCommon.h"
 #include "controllerko.h" //tdsControl, tdsCount, etc
-#include "findSharedMemory.h"
 #include "controller.h" //daqArea
 #include "feComms.h" //RFM_FE_COMMS
 #include "util/printl.h"
diff --git a/src/gds/awgtpman/testpoint.c b/src/gds/awgtpman/testpoint.c
index a0ed8977d34642753c39fb5e40c8f231a2ca626f..d046615ecd3b1c124afbe8cde6ca4e269cd54d18 100644
--- a/src/gds/awgtpman/testpoint.c
+++ b/src/gds/awgtpman/testpoint.c
@@ -10,6 +10,8 @@
 #include "dtt/gdserr.h"
 #include "dtt/gdserrmsg.h"
 #include "tconv.h"
+#include "testpoint_interface_v3.h"
+#include "testpoint.h"
 
 #if defined (_CONFIG_DYNAMIC)
 #include "confinfo.h"
@@ -43,6 +45,7 @@ static int			tp_init = 0;
 static tpNode_t		tpNode[TP_MAX_NODE];
 static int			tpNum = 0;
 
+
 /*----------------------------------------------------------------------*/
 /*                                                         		*/
 /* Internal Procedure Name: tpSetHostAddress				*/
@@ -597,8 +600,11 @@ int tpQuery (int node, int tpinterface, testpoint_t tp[], int tplen,
         return -2;
     }
 
+    int max_interface = (testAwgTpInterfaceVersion(node) > 3)
+        ? TP_MAX_INTERFACE : TP_MAX_INTERFACE_V3;
+
     /* check interface */
-    if ((tpinterface < 0) || (tpinterface >= TP_MAX_INTERFACE)) {
+    if ((tpinterface < 0) || (tpinterface >= max_interface)) {
         return -2;
     }
 
@@ -678,7 +684,77 @@ static char* cmdreply (const char* m)
 /* Procedure Returns: void						*/
 /*                                                         		*/
 /*----------------------------------------------------------------------*/
-static void queryCmd (char* buf, int node)
+static void queryCmd_v3 (char* buf, int node)
+{
+    int		i;
+    char*		p;
+    testpoint_t	tp[TP_MAX_INDEX]; /* test points */
+    int		num;	/* number of test points */
+
+    sprintf (buf, "Test points for node %i\n", node);
+    /* query lsc exc */
+    num = tpQuery (node, TP_LSC_EX_INTERFACE, tp,
+                   TP_MAX_INDEX, 0, 0);
+    p = strend (buf);
+    sprintf (p, "LSC EX:");
+    p = strend (p);
+    if (num < 0) {
+        sprintf (p, " invalid\n");
+        return;
+    }
+    for (i = 0; i < num; i++) {
+        sprintf (p, " %i", tp[i]);
+        p = strend (p);
+    }
+    sprintf (p++, "\n");
+    /* query lsc tp */
+    num = tpQuery (node, TP_LSC_TP_INTERFACE, tp,
+                   TP_MAX_INDEX, 0, 0);
+    p = strend (buf);
+    sprintf (p, "LSC TP:");
+    p = strend (p);
+    if (num < 0) {
+        sprintf (p, " invalid\n");
+        return;
+    }
+    for (i = 0; i < num; i++) {
+        sprintf (p, " %i", tp[i]);
+        p = strend (p);
+    }
+    sprintf (p++, "\n");
+    /* query asc exc */
+    num = tpQuery (node, TP_ASC_EX_INTERFACE, tp,
+                   TP_MAX_INDEX, 0, 0);
+    p = strend (buf);
+    sprintf (p, "ASC EX:");
+    p = strend (p);
+    if (num < 0) {
+        sprintf (p, " invalid\n");
+        return;
+    }
+    for (i = 0; i < num; i++) {
+        sprintf (p, " %i", tp[i]);
+        p = strend (p);
+    }
+    sprintf (p++, "\n");
+    /* query asc tp */
+    num = tpQuery (node, TP_ASC_TP_INTERFACE, tp,
+                   TP_MAX_INDEX, 0, 0);
+    p = strend (buf);
+    sprintf (p, "ASC TP:");
+    p = strend (p);
+    if (num < 0) {
+        sprintf (p, " invalid\n");
+        return;
+    }
+    for (i = 0; i < num; i++) {
+        sprintf (p, " %i", tp[i]);
+        p = strend (p);
+    }
+    sprintf (p++, "\n");
+}
+
+static void queryCmd_v4 (char* buf, int node)
 {
     int		i;
     char*		p;
@@ -718,6 +794,23 @@ static void queryCmd (char* buf, int node)
     sprintf (p++, "\n");
 }
 
+static void queryCmd (char* buf, int node)
+{
+    int interface_version = testAwgTpInterfaceVersion(node);
+    switch (interface_version)
+    {
+    case 3:
+        queryCmd_v3(buf, node);
+        break;
+    case 4:
+        queryCmd_v4(buf, node);
+        break;
+    default:
+        printf("unrecognized awgtp interface version %d\n", interface_version);
+        break;
+    }
+}
+
 
 /*----------------------------------------------------------------------*/
 /*                                                         		*/
@@ -963,3 +1056,59 @@ int keepAlive (int node)
     clnt_destroy (clnt);
     return ret;
 }
+
+
+/// Find RPC interface version used by awgtpman
+/// version 4 was introduced about RCG version 4.1.0
+/// all previous interface versions, including for RCG 4.0.1,
+/// are considered version 3.
+/// Version 4 has only two testpoint interfaces: one for excitations and one for
+/// other test points.
+/// Version 3 has 4 testpoint interfaces: the two interfaces of version 4 are
+/// divided between LSC and ASC test points.
+///
+/// \param node the node number to identify
+/// \return the version number, 0 on error
+int testAwgTpInterfaceVersion(int node)
+{
+    // memoize
+    static int node_version[ TP_MAX_NODE ];
+
+    if ( node_version[ node ] )
+    {
+        return node_version[ node ];
+    }
+
+    resultQueryTP_r result;
+    memset (&result, 0, sizeof (resultQueryTP_r));
+
+    int chk = testpoint_client( );
+
+    if (chk < 0) {
+        printf("testAwgTpInterfaceVersion: testpoint_client() failed with return code %d\n", chk);
+        return 0;
+    }
+
+    CLIENT * clnt = tpMakeHandle (node);
+    if(clnt == NULL)
+    {
+        return 0;
+    }
+
+    // Test if TP_ASC_TP_INTERFACE is accessible
+    // if so, we must be older version 3, otherwise, something newer.
+    if ((querytp_1 (tpNode[node].id, node, TP_ASC_TP_INTERFACE, 128, 0,
+                    0, &result, clnt) == RPC_SUCCESS) && (result.status >= 0)) {
+        printf("found version 3 or older test point interface\n");
+        node_version[node] = 3;
+    }
+    else
+    {
+        printf("found version 4 or newer test point interface\n");
+        node_version[node] = 4;
+    }
+
+    xdr_free ((xdrproc_t)xdr_resultQueryTP_r, (char*) &result);
+    clnt_destroy (clnt);
+    return node_version[node];
+}
\ No newline at end of file
diff --git a/src/gds/awgtpman/testpoint.h b/src/gds/awgtpman/testpoint.h
index 4fc9ae9a2b3b1b8141c603c3f245a4de60e68bff..cd7f0072120892651d09f4c6fe2321950ab5e219 100644
--- a/src/gds/awgtpman/testpoint.h
+++ b/src/gds/awgtpman/testpoint.h
@@ -200,6 +200,20 @@ int tpcmdline( const char* cmd );
 /*----------------------------------------------------------------------*/
 int keepAlive( int node );
 
+
+/// Find RPC interface version used by awgtpman
+/// version 4 was introduced about RCG version 4.1.0
+/// all previous interface versions, including for RCG 4.0.1,
+/// are considered version 3.
+/// Version 4 has only two testpoint interfaces: one for excitations and one for
+/// other test points.
+/// Version 3 has 4 testpoint interfaces: the two interfaces of version 4 are
+/// divided between LSC and ASC test points.
+///
+/// \param node the node number to identify
+/// \return the version number, 0 on error
+int testAwgTpInterfaceVersion(int node);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/gds/awgtpman/testpoint_interface_v3.h b/src/gds/awgtpman/testpoint_interface_v3.h
new file mode 100644
index 0000000000000000000000000000000000000000..bcbe1e79c34d360411968f19b763d71e6410bb10
--- /dev/null
+++ b/src/gds/awgtpman/testpoint_interface_v3.h
@@ -0,0 +1,60 @@
+//
+// Created by erik.vonreis on 5/4/22.
+//
+// defines needed for older version 3 RPC interface, stolen from
+// version 4.0.1
+//
+
+#ifndef DAQD_TRUNK_TESTPOINT_INTERFACE_V3_H
+#define DAQD_TRUNK_TESTPOINT_INTERFACE_V3_H
+
+/** Test point interface id of LSC excitation.
+
+@author DS, September 98
+    @see Testpoint Definition
+        ************************************************************************/
+#define TP_LSC_EX_INTERFACE	0
+
+/** Test point interface id of ASC excitation.
+
+    @author DS, September 98
+    @see Testpoint Definition
+************************************************************************/
+#define TP_ASC_EX_INTERFACE	1
+
+/** Test point interface id of LSC readout.
+
+    @author DS, September 98
+    @see Testpoint Definition
+************************************************************************/
+#define TP_LSC_TP_INTERFACE	2
+
+/** Test point interface id of ASC readout.
+
+    @author DS, September 98
+    @see Testpoint Definition
+************************************************************************/
+#define TP_ASC_TP_INTERFACE	3
+
+
+#define TP_MAX_INTERFACE_V3     4
+
+#define TP_ID_TO_INTERFACE_V3(A) ( \
+	((A) == 0 ? -1 :	    \
+	((A) < TP_ID_LSC_TP_OFS ? TP_LSC_EX_INTERFACE :	    \
+	((A) < TP_ID_ASC_EX_OFS ? TP_LSC_TP_INTERFACE :	    \
+	((A) < TP_ID_ASC_TP_OFS ? TP_ASC_EX_INTERFACE :	    \
+	((A) < TP_ID_DAC_OFS ? TP_ASC_TP_INTERFACE :	    \
+	((A) < TP_ID_DS340_OFS ? TP_DAC_INTERFACE :	    \
+        ((A) < TP_ID_END_OFS ? TP_DS340_INTERFACE :         \
+         -1))))))))
+
+/** Maximum number of entries in the test point index. This number must
+    be greater or equal than any of the individual test point indexes.
+
+@author DS, September 98
+    @see Testpoint Definition
+        ************************************************************************/
+#define TP_MAX_INDEX		64
+
+#endif // DAQD_TRUNK_TESTPOINT_INTERFACE_V3_H
diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt
index eb0cb1d95468c5ac881280a33ed468cbd81d314b..ddca6375f54af1428a309f9e292cfa2b5ce38b06 100644
--- a/src/include/CMakeLists.txt
+++ b/src/include/CMakeLists.txt
@@ -3,6 +3,7 @@ install(FILES
             daq_core.h
             daq_core_defs.h
             daq_data_types.h
+            portableInline.h
         DESTINATION
             include/advligorts
         )
diff --git a/src/include/controller.c b/src/include/controller.c
index e2fd98dfde268b249c62b9578ac3a6db7630c2e6..b9fb759720627f030ff47330d3ed8fc285006ce8 100644
--- a/src/include/controller.c
+++ b/src/include/controller.c
@@ -37,14 +37,31 @@ char fp[ 64 * 1024 ];
 
 
 char*          build_date = __DATE__ " " __TIME__;
+
+//
+// Pointers to shared memory blocks
+//
+shmem_handle g_epics_shm_handle;
 volatile char* _epics_shm; ///< Ptr to EPICS shared memory area
+
+shmem_handle g_tp_shm_handle;
 volatile TESTPOINT_CFG  *_tp_shm;
+
+shmem_handle g_awg_shm_handle;
 volatile AWG_DATA *_awg_shm;
+
+shmem_handle g_ipc_shm_handle;
 volatile char*          _ipc_shm; ///< Ptr to inter-process communication area
+
+shmem_handle g_daq_shm_handle;
 volatile char*          _daq_shm; ///< Ptr to frame builder comm shared mem area
-// char*          _gds_shm; ///< Ptr to frame builder comm shared mem area
+
+shmem_handle g_shmipc_shm_handle;
 volatile char*          _shmipc_shm; ///< Ptr to IOP I/O data to/from User app shared mem area
+
+shmem_handle g_io_shm_handle;
 volatile 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
diff --git a/src/include/controller.h b/src/include/controller.h
index 64ac95800d60e3c5bd676d935ca206ae7044d08a..9e5cdd32dc5abd72fd9428916dfe9e2a3a6766aa 100644
--- a/src/include/controller.h
+++ b/src/include/controller.h
@@ -5,6 +5,7 @@
 #include "fm10Gen_types.h" //FILT_MOD 
 #include "daq_core_defs.h" //DAQ_DCU_SIZE
 
+#include "drv/shmem.h"
 #include "../shmem/shmem_all.h" //TESTPOINT_CFG, AWG_DATA
 
 
@@ -274,14 +275,28 @@ extern char fp[ 64 * 1024 ];
 
 
 extern char*          build_date ;
+
 extern volatile char* _epics_shm; ///< Ptr to EPICS shared memory area
+extern shmem_handle g_epics_shm_handle;
+
 extern volatile TESTPOINT_CFG  *_tp_shm;
+extern shmem_handle g_tp_shm_handle;
+
 extern volatile AWG_DATA *_awg_shm;
+extern shmem_handle g_awg_shm_handle;
+
 extern volatile char*          _ipc_shm; ///< Ptr to inter-process communication area
+extern shmem_handle g_ipc_shm_handle;
+
 extern volatile char*          _daq_shm; ///< Ptr to frame builder comm shared mem area
-//extern  char*          _gds_shm; ///< Ptr to frame builder comm shared mem area
+extern shmem_handle g_daq_shm_handle;
+
 extern volatile char*          _shmipc_shm; ///< Ptr to IOP I/O data to/from User app shared mem area
+extern shmem_handle g_shmipc_shm_handle;
+
 extern volatile char*          _io_shm; ///< Ptr to user space I/O area
+extern shmem_handle g_io_shm_handle;
+
 extern int            daq_fd; ///< File descriptor to share memory file
 
 extern long                      daqBuffer; // Address for daq dual buffers in daqLib.c
diff --git a/src/include/drv/rts-logger.h b/src/include/drv/rts-logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c705da56cb15f9e5ae92930466640fc4e121c33
--- /dev/null
+++ b/src/include/drv/rts-logger.h
@@ -0,0 +1,136 @@
+#ifndef LIGO_RTS_LOGGER_H_INCLUDED
+#define LIGO_RTS_LOGGER_H_INCLUDED
+/**
+ *  @section kernel_space
+ *  In kernel space the functions are exported by the rts-logger module.
+ *  Real-time kernel modules only need to copy their messages into the logger
+ *  module's buffer, and then can return to their work. The logger module does 
+ *  the interruptible work of calling prink, handling the high latancy/jittery 
+ *  portion of printing messages on a non-isolated core.
+ *
+ *  @section user_space
+ *  In user space these are defined in rts-logger/userspace/usp-rts-logger.c
+ *  We want to provide the same logging interface to user space that kernel space
+ *  gets, so we define these functions in user space. The user space implementation
+ *  is very simple, calling printf with the message. It is important to note that 
+ *  this implementation is slower than kernel space, because the user space version
+ *  actually calls printf in the model's thread.
+ *
+ */
+
+#ifndef RTS_LOG_PREFIX
+
+#if defined(FE_HEADER)
+#include FE_HEADER //SYSTEM_NAME_STRING_LOWER
+#define RTS_LOG_PREFIX SYSTEM_NAME_STRING_LOWER
+#endif
+
+#else
+#define RTS_LOG_PREFIX "undefined"
+#endif //ifndef RTS_LOG_PREFIX
+
+enum RTSLOG_LOG_LEVEL
+{
+    RTSLOG_LOG_LEVEL_DEBUG = 0,
+    RTSLOG_LOG_LEVEL_INFO = 1, //Default log level
+    RTSLOG_LOG_LEVEL_WARN = 2,
+    RTSLOG_LOG_LEVEL_ERROR = 3,
+    RTSLOG_LOG_LEVEL_RAW = 5
+};
+
+//
+// Start user functions
+//
+
+/**
+ * @usage This is the main interface that should be used to log messages
+ *        from front end code infrastructure. The default log level is INFO,
+ *        so you must set the logger level to DEBUG before you will see debug
+ *        level messages. 
+ *
+ * These macros can be used just like prink or printf:
+ *
+ * RTSLOG_INFO("A string: %s and an int: %d\n", "Hello", 5);
+ *
+ */
+#define RTSLOG_RAW(fmt, ...) rtslog_print(RTSLOG_LOG_LEVEL_RAW, fmt, ##__VA_ARGS__)
+#define RTSLOG_DEBUG(fmt, ...) rtslog_print (RTSLOG_LOG_LEVEL_DEBUG, RTS_LOG_PREFIX ": DEBUG - " fmt, ##__VA_ARGS__)
+#define RTSLOG_INFO(fmt, ...) rtslog_print (RTSLOG_LOG_LEVEL_INFO, RTS_LOG_PREFIX ": INFO - " fmt, ##__VA_ARGS__)
+#define RTSLOG_WARN(fmt, ...) rtslog_print (RTSLOG_LOG_LEVEL_WARN, RTS_LOG_PREFIX ": WARN - " fmt, ##__VA_ARGS__)
+#define RTSLOG_ERROR(fmt, ...) rtslog_print (RTSLOG_LOG_LEVEL_ERROR, RTS_LOG_PREFIX ": ERROR - " fmt, ##__VA_ARGS__)
+
+
+//
+// Debugging/Stats functions
+//
+
+/**
+* @brief Requests the new log level be set in the logger.
+* 
+* When the kernel module version is being used the sysfs interface
+* can be used to set this value. 
+*
+* cat /sys/kernel/rts_logger/debug_level
+*
+* @param new_level  The new log level to set (a RTSLOG_LOG_LEVEL)
+*
+* @return 1 if the log level was set, 0 if the log level was invalid        
+*/
+int rtslog_set_log_level(int new_level);
+
+/**
+* @brief Requests the new log level be set in the logger
+*
+* @return The level set (a RTSLOG_LOG_LEVEL)
+*/
+int rtslog_get_log_level( void );
+
+/**
+* @brief Requests number of messages that have been dropped
+*        due to a full buffer. This should't happen, but can
+*        if too many modules are spamming messages faster than
+*        they can be printed. This is an accumulative count 
+*        from module insertion (kernel space), or process creation (usermode)
+*
+* @return The number of messages that have been dropped 
+*/
+int rtslog_get_num_dropped_space ( void );
+
+/**
+* @brief Requests number of messages that are currently 
+*        queued, waiting for printing.
+*
+* @return The number of messages that are queued for print
+*/
+int rtslog_get_num_ready_to_print( void );
+
+
+
+
+
+
+
+
+
+
+
+//
+// Internal functions
+//
+
+/**
+* @brief Don't call this function directly, use the macros above
+*
+* Passes the message to the logger for logging
+*
+* @param level The log level of this message
+* @param fmt   The format string of the message
+* @param ...   Arguments for the format string
+*
+* @return none
+*/
+
+void rtslog_print(int level, const char * fmt, ...);
+
+
+#endif //LIGO_RTS_LOGGER_H_INCLUDED
diff --git a/src/include/drv/shmem.h b/src/include/drv/shmem.h
index c0d4da4497368d08910a3d1a92a31ad3a9b4807a..fd2d2fa96a52520582195c4d25fcf7212065e25f 100644
--- a/src/include/drv/shmem.h
+++ b/src/include/drv/shmem.h
@@ -8,8 +8,10 @@
 extern "C" {
 #endif
 
-extern volatile void* findSharedMemory( char* sys_name );
-extern volatile void* findSharedMemorySize( char* sys_name, int size );
+#include <stddef.h>
+
+#define DEFAULT_SHMEM_ALLOC_SIZE_MB 64
+
 
 extern int shmem_format_name( char* dest, const char* src, size_t n );
 // extern volatile void* shmem_open_segment(const char *sys_name, size_t
diff --git a/src/include/fe.h b/src/include/fe.h
index a6df4d44d10d338684b1955e2d8396f74fd3588e..82a67cbc808ed9cd3c961b7bac7f82ffec787ce4 100644
--- a/src/include/fe.h
+++ b/src/include/fe.h
@@ -5,8 +5,11 @@
 #include "controllerko.h" //CDIO* Globals and tdsControl/tdsCount
 
 #include "modelRateInfo.h" ////CYCLE_PER_SECOND, FE_RATE
+#include "qnorm.h"
 #include "util/inlineMath.h"
 #include "util/timing.h"
+#include "util/random_bytes.h"
+#include "util/prng_xoroshiroPP.h"
 #include "fm10Gen.h"
 #include "tRamp.h"
 #include "isnan.h"
diff --git a/src/include/findSharedMemory.h b/src/include/findSharedMemory.h
deleted file mode 100644
index b03777685fc9dd1238d1d35b7988d931fa0c3a71..0000000000000000000000000000000000000000
--- a/src/include/findSharedMemory.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef LIGO_FINDSHAREDMEMORY_H 
-#define LIGO_FINDSHAREDMEMORY_H
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-volatile void* findSharedMemory( char* );
-volatile void* findSharedMemorySize( char*, int size_mb );
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
diff --git a/src/include/qnorm.h b/src/include/qnorm.h
index a3700d1ce30d699cd9ec38e7d076b62b7f698f44..97e0f5528f5a5a44e896bf08b1bb745a1d44b824 100644
--- a/src/include/qnorm.h
+++ b/src/include/qnorm.h
@@ -106,7 +106,7 @@
 #ifndef LIGO_QNORM_H
 #define LIGO_QNORM_H
 
-#include "inlineMath.h"
+#include "util/inlineMath.h"
 
 
 #define ML_POSINF   (1.0 / 0.0)
diff --git a/src/include/util/kernel/exit_signaling.h b/src/include/util/kernel/exit_signaling.h
new file mode 100644
index 0000000000000000000000000000000000000000..675b9c04f81bcabf2ea9edbe86cc7ddafd149832
--- /dev/null
+++ b/src/include/util/kernel/exit_signaling.h
@@ -0,0 +1,24 @@
+#ifndef LIGO_EXIT_SIGNALING_H
+#define LIGO_EXIT_SIGNALING_H
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/atomic.h>
+
+// Used to signal the model to exit, defined in fe/moduleLoad.c
+extern atomic_t g_atom_should_exit;
+// Used by fe_start_controller() (The model) to signal it has exited,
+// defined in fe/moduleLoad.c
+extern atomic_t g_atom_has_exited; 
+
+// When a model experiences a nonrecoverable error and needs to exit
+// we block execution with this function until the model is rmmod-ed
+static void wait_for_exit_signal(void)
+{
+    while(atomic_read(&g_atom_should_exit) == 0)
+    {
+    }
+}
+
+
+#endif //LIGO_EXIT_SIGNALING_H
diff --git a/src/local_dc/CMakeLists.txt b/src/local_dc/CMakeLists.txt
index d70be10d2db0d78a331ed14ef43288d8c466e251..51ff45da5d119dadb7dad5cfc75dd68162e577dc 100644
--- a/src/local_dc/CMakeLists.txt
+++ b/src/local_dc/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_executable(local_dc local_dc.c ${CMAKE_CURRENT_SOURCE_DIR}/../drv/rfm.c)
+add_executable(local_dc local_dc.c ${CMAKE_CURRENT_SOURCE_DIR}/../drv/shmem.c)
 
 target_link_libraries(local_dc PUBLIC
         args
diff --git a/src/shmem/shmem_all.h b/src/shmem/shmem_all.h
index 812244a048c7291674ef97e88eeeb2916b6a7759..53e5e9d2737d1a0e379d50adf1f5c3f36ac99e1a 100644
--- a/src/shmem/shmem_all.h
+++ b/src/shmem/shmem_all.h
@@ -9,5 +9,6 @@
 #include "shmem_awg.h"
 #include "shmem_iomem.h"
 #include "shmem_testpoint.h"
+#include "shmem_ipccomms.h"
 
 #endif // DAQD_TRUNK_SHMEM_ALL_H
diff --git a/src/shmem/shmem_ipccomms.h b/src/shmem/shmem_ipccomms.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c45eff7761d49d85301475cfdedb64d173b7518
--- /dev/null
+++ b/src/shmem/shmem_ipccomms.h
@@ -0,0 +1,13 @@
+//
+// Created by ezekiel.dohmen 05/06/2022
+//
+
+#ifndef SHMEM_IPC_COMMS_H
+#define SHMEM_IPC_COMMS_H
+
+#define SHMEM_IPCCOMMS_NAME "shmipc"
+#define SHMEM_IPCCOMMS_SIZE_MB 16
+#define SHMEM_IPCCOMMS_SIZE ( SHMEM_IPCCOMMS_SIZE_MB * 1024 * 1024 )
+
+#endif // SHMEM_IPC_COMMS_H
+