diff --git a/cmds/st.cmd b/cmds/st.cmd
index c1655a0d1fdc812282d2be9f0832db7f131e1a05..d8cf5539c9f9968da13f28128bf366f3ec7d9548 100644
--- a/cmds/st.cmd
+++ b/cmds/st.cmd
@@ -11,27 +11,27 @@ drvAsynIPPortConfigure("L0", "$(IPADDR):$(IPPORT) UDP", 0, 0, 1)
 #asynSetTraceIOMask( L0, -1, 0x4)
 #asynSetTraceInfoMask ( L0, -1, 0x9)
 
-RMMConfig("RMM", "L0", "$(IOCSH_TOP)/config_file/lab_testbed.json", 0)
+RMMConfig("RMM", "$(IPADDR)", "$(IPPORT)", "$(E3_CMD_TOP)/config_file/lab_testbed.json")
 
-#VMMTblConfig("portName", ring, number_hybrids)
-VMMTblConfig("RMM", 0, 2)
+#VMMTblConfig("RMM portName", "VMMPortName", ring, number_hybrids)
+VMMTblConfig("RMM", "VMM", 0, 2)
 
 dbLoadRecords("${asyn_DIR}/db/asynRecord.db","P=asyn:,R=Test,PORT=L0,ADDR=0,IMAX=0,OMAX=0")
 dbLoadRecords($(rmm_DB)/rmm.db, "P=$(P), R=$(R), PORT=RMM, ADDR=0, TIMEOUT=1")
-dbLoadRecords($(rmm_DB)/rmm_sensors.db, "P=$(P), R=$(R), PORT=RMM, TIMEOUT=1")
-dbLoadRecords($(rmm_DB)/ring.db, "P=$(P), R=$(R), ADDR=0, PORT=RMM, TIMEOUT=1")
+dbLoadRecords($(rmm_DB)/rmm_sensors.db, "P=$(P), R=$(R), PORT=RMM, ADDR=0, TIMEOUT=1")
+dbLoadRecords($(rmm_DB)/ring.db, "P=$(P), R=$(R), ADDR=0, PORT=RMM, ADDR=0, TIMEOUT=1")
 
 dbLoadRecords("$(rmm_DB)/rmm_packets.template", "P=$(P), R=$(R), PORT=RMM, RING=0, NODE=0, ADDR=0, TIMEOUT=1")
 dbLoadRecords("$(rmm_DB)/topology.template", "P=$(P), R=$(R), PORT=RMM, RING=0, NODE=0, ADDR=0, TIMEOUT=1")
 
-dbLoadRecords("$(vmmTbl_DB)/vmm_tbl.db", "P=$(P), R=NDet-VMM-001:, PORT=RMM, RING=0, NODE=0, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(vmmTbl_DB)/hybrid.db", "P=$(P), R=NDet-VMM-001:, PORT=RMM, HYB=0, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(vmmTbl_DB)/hybrid.db", "P=$(P), R=NDet-VMM-001:, PORT=RMM, HYB=1, ADDR=0, TIMEOUT=1")
+dbLoadRecords("$(vmmTbl_DB)/vmm_tbl.db", "P=$(P), R=NDet-VMM-001:, PORT=VMM, RING=0, NODE=0, ADDR=0, TIMEOUT=1")
+dbLoadRecords("$(vmmTbl_DB)/hybrid.db", "P=$(P), R=NDet-VMM-001:, PORT=VMM, HYB=0, ADDR=0, TIMEOUT=1")
+dbLoadRecords("$(vmmTbl_DB)/hybrid.db", "P=$(P), R=NDet-VMM-001:, PORT=VMM, HYB=1, ADDR=0, TIMEOUT=1")
 
-dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=NDet-VMMHYB-00, HYB=0, VMM=0, C=:, PORT=RMM, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=NDet-VMMHYB-00, HYB=0, VMM=1, C=:, PORT=RMM, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=NDet-VMMHYB-00, HYB=1, VMM=0, C=:, PORT=RMM, ADDR=0, TIMEOUT=1")
-dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=NDet-VMMHYB-00, HYB=1, VMM=1, C=:, PORT=RMM, ADDR=0, TIMEOUT=1")
+dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=NDet-VMMHYB-00, HYB=0, VMM=0, C=:, PORT=VMM, ADDR=0, TIMEOUT=1")
+dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=NDet-VMMHYB-00, HYB=0, VMM=1, C=:, PORT=VMM, ADDR=0, TIMEOUT=1")
+dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=NDet-VMMHYB-00, HYB=1, VMM=0, C=:, PORT=VMM, ADDR=0, TIMEOUT=1")
+dbLoadRecords("$(vmmTbl_DB)/channels.db", "P=$(P), R=NDet-VMMHYB-00, HYB=1, VMM=1, C=:, PORT=VMM, ADDR=0, TIMEOUT=1")
 
 iocInit()
 
diff --git a/vmmTbl.Makefile b/vmmTbl.Makefile
index 4f6b10b72d58cbfc27c8e26e3da8621263ab0dd2..2b52e6a83c9342079411e0fbc331b16e33cc785a 100644
--- a/vmmTbl.Makefile
+++ b/vmmTbl.Makefile
@@ -13,16 +13,10 @@ SUBS = $(APPDB)/channels.sub
 
 SOURCES += $(APPSRC)/hybrid.cpp
 SOURCES += $(APPSRC)/vmm3a.cpp
-SOURCES += $(APPSRC)/vmm_config.cpp
+SOURCES += $(APPSRC)/VmmTblAPI.cpp
 SOURCES += $(APPSRC)/vmm_tbl.cpp
-SOURCES += $(APPSRC)/vmm_tbl_regs_map.cpp
+SOURCES += $(APPSRC)/VmmTblRegsMap.cpp
 
-HEADERS += $(APPSRC)/hybrid.h
-HEADERS += $(APPSRC)/vmm3a.h
-HEADERS += $(APPSRC)/vmm_config.h
-HEADERS += $(APPSRC)/vmm_params.h
-HEADERS += $(APPSRC)/vmm_tbl.h
-HEADERS += $(APPSRC)/vmm_tbl_regs_map.h
 DBDS    += $(APPSRC)/vmm_tbl.dbd
 
 USR_DBFLAGS += -I . -I ..
diff --git a/vmmTblApp/src/vmm_config.cpp b/vmmTblApp/src/VmmTblAPI.cpp
similarity index 79%
rename from vmmTblApp/src/vmm_config.cpp
rename to vmmTblApp/src/VmmTblAPI.cpp
index 3b583aa6b82ba752ef45f156a5eb95c01cb41b57..77b69cd06cd12dbb7a398d07122d77830c2ad3e8 100644
--- a/vmmTblApp/src/vmm_config.cpp
+++ b/vmmTblApp/src/VmmTblAPI.cpp
@@ -1,4 +1,4 @@
-#include "vmm_config.h"
+#include "VmmTblAPI.h"
 #include <sstream>
 #include <bitset>
 #include <algorithm>
@@ -12,13 +12,15 @@ void delayMilliseconds(int milliseconds) {
   std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
 }
 
-FENConfigModule::FENConfigModule(FrontEndBase& frontend) : pFEN(&frontend) {
+VmmTblAPI::VmmTblAPI(RMMAPI* rmmApi, int ring, int node, std::string name)
+        : FrontEndBase(rmmApi, ring, node, name)
+{
 }
 
-FENConfigModule::~FENConfigModule() {
+VmmTblAPI::~VmmTblAPI() {
 }
 
-void FENConfigModule::acquire(bool acquire) {
+void VmmTblAPI::acquire(bool acquire) {
   if (acquire) {
     enableAcquisition(false);
     sendAll(true);
@@ -28,8 +30,8 @@ void FENConfigModule::acquire(bool acquire) {
   }
 }
 
-void FENConfigModule::sendAll(bool useConfigCheck) {
-  configFEN();
+void VmmTblAPI::sendAll(bool useConfigCheck) {
+  configFE();
   for(int hybrid = 0; hybrid <= HYBRIDS_PER_FEN; hybrid++) {
     if (isHybridEnabled(hybrid)) {
       configHybrid(hybrid);
@@ -41,35 +43,35 @@ void FENConfigModule::sendAll(bool useConfigCheck) {
   }
 }
 
-void FENConfigModule::enableAcquisition(bool enabled) {
-  pFEN->userRegWrite("app_acq_enable", enabled);
-  pFEN->userRegWrite("sc_acq_on_off", 0x00000000);
-  pFEN->userRegWrite("sc_acq_on_off", 0x00000001);
-  pFEN->userRegWrite("sc_acq_on_off", 0x00000000);
+void VmmTblAPI::enableAcquisition(bool enabled) {
+  userRegWrite("app_acq_enable", enabled);
+  userRegWrite("sc_acq_on_off", 0x00000000);
+  userRegWrite("sc_acq_on_off", 0x00000001);
+  userRegWrite("sc_acq_on_off", 0x00000000);
 }
 
-std::string FENConfigModule::checkLinkStatus(int hyb) {
+std::string VmmTblAPI::checkLinkStatus(int hyb) {
   uint32_t result = readWriteRegs("sc_app_link_status", 0, "app_link_status");
   int pos = 7 - hyb;
-  return int_to_hex_string(result).substr(pos, 1);
+  return intToHexString(result).substr(pos, 1);
 }
 
-void FENConfigModule::configFEN() {
-  pFEN->userRegWrite("app_debug_data_format", 0);
-  pFEN->userRegWrite("app_latency_reset", 27);
-  pFEN->userRegWrite("app_latency_data_max", 1024);
-  pFEN->userRegWrite("app_latency_data_jitter", 0);
-  pFEN->userRegWrite("app_tp_offset_first", 100);
-  pFEN->userRegWrite("app_tp_offset", 1000);
-  pFEN->userRegWrite("app_tp_latency", 46);
-  pFEN->userRegWrite("app_tp_number", 1);
-  pFEN->userRegWrite("app_chmask", getChMap());
-  pFEN->userRegWrite("sc_cfg_app", 0x00000000);
-  pFEN->userRegWrite("sc_cfg_app", 0x00000001);
-  pFEN->userRegWrite("sc_cfg_app", 0x00000000);
+void VmmTblAPI::configFE() {
+  userRegWrite("app_debug_data_format", 0);
+  userRegWrite("app_latency_reset", 27);
+  userRegWrite("app_latency_data_max", 1024);
+  userRegWrite("app_latency_data_jitter", 0);
+  userRegWrite("app_tp_offset_first", 100);
+  userRegWrite("app_tp_offset", 1000);
+  userRegWrite("app_tp_latency", 46);
+  userRegWrite("app_tp_number", 1);
+  userRegWrite("app_chmask", getChMap());
+  userRegWrite("sc_cfg_app", 0x00000000);
+  userRegWrite("sc_cfg_app", 0x00000001);
+  userRegWrite("sc_cfg_app", 0x00000000);
 }
 
-uint16_t FENConfigModule::getChMap() {
+uint16_t VmmTblAPI::getChMap() {
   std::string chMapString = "0000000000000000";
   for (int hybrid = 0; hybrid < HYBRIDS_PER_FEN; hybrid++) {
     if (isHybridEnabled(hybrid)) {
@@ -82,67 +84,67 @@ uint16_t FENConfigModule::getChMap() {
   return chMap;
 }
 
-bool FENConfigModule::enableHybrid(int hybrid, bool onOff) {
+bool VmmTblAPI::enableHybrid(int hybrid, bool onOff) {
   if(hybrid < HYBRIDS_PER_FEN) {
     enabled_hybrids[hybrid] = onOff;
     return true;
   } else return false;
 }
 
-bool FENConfigModule::isHybridEnabled(int hybrid) {
+bool VmmTblAPI::isHybridEnabled(int hybrid) {
   if(hybrid < HYBRIDS_PER_FEN) return enabled_hybrids[hybrid];
   else return false;
 }
 
-Hybrid& FENConfigModule::getHybrid(int index) {
+Hybrid& VmmTblAPI::getHybrid(int index) {
   if (index < 0 || index >= HYBRIDS_PER_FEN)
     throw std::out_of_range("Invalid hybrid index");
   return hybrids[index];
 }
 
-void FENConfigModule::configHybrid(int hybrid_index) {
+void VmmTblAPI::configHybrid(int hybrid_index) {
   std::array<std::string, 3> registers = {"hyb_tp_skew0", "hyb_tp_width0", "hyb_tp_polarity0"};
 
   for (const auto& reg : registers) {
     unsigned short result = 0;
     hybrids[hybrid_index].getRegister(reg, result);
-    pFEN->userRegWrite(reg + std::to_string(hybrid_index), result);
+    userRegWrite(reg + std::to_string(hybrid_index), result);
   }
 
   uint32_t value = (1 << hybrid_index);
-  pFEN->userRegWrite("sc_cfg_hyb", 0x0);
-  pFEN->userRegWrite("sc_cfg_hyb", value);
-  pFEN->userRegWrite("sc_cfg_hyb", 0x0);
+  userRegWrite("sc_cfg_hyb", 0x0);
+  userRegWrite("sc_cfg_hyb", value);
+  userRegWrite("sc_cfg_hyb", 0x0);
 }
 
-std::string FENConfigModule::readFwVersion(int hyb) {
+std::string VmmTblAPI::readFwVersion(int hyb) {
   uint32_t result = readWriteRegs("sc_i2c_firmware_version",
                                   hyb,
                                   "hyb_i2c_firmware_version0" + std::to_string(hyb));
-  return int_to_hex_string(result);
+  return intToHexString(result);
 }
 
-std::string FENConfigModule::readGeoPos(int hyb) {
+std::string VmmTblAPI::readGeoPos(int hyb) {
   uint32_t result = readWriteRegs("sc_i2c_geo_id", hyb, "hyb_i2c_geoid0" + std::to_string(hyb));
-  return int_to_hex_string(result).substr(6);
+  return intToHexString(result).substr(6);
 }
 
-std::string FENConfigModule::readIDChip(int hyb) {
+std::string VmmTblAPI::readIDChip(int hyb) {
   std::string full_string;
   uint32_t result = 0;
   result = readWriteRegs("sc_i2c_hybrid_id", hyb, "hyb_i2c_hybrid_id00" + std::to_string(hyb));
-  full_string += int_to_hex_string(result);
+  full_string += intToHexString(result);
   result = readWriteRegs("sc_i2c_hybrid_id", hyb, "hyb_i2c_hybrid_id10" + std::to_string(hyb));
-  full_string += int_to_hex_string(result);
+  full_string += intToHexString(result);
   result = readWriteRegs("sc_i2c_hybrid_id", hyb, "hyb_i2c_hybrid_id20" + std::to_string(hyb));
-  full_string += int_to_hex_string(result);
+  full_string += intToHexString(result);
   result = readWriteRegs("sc_i2c_hybrid_id", hyb, "hyb_i2c_hybrid_id30" + std::to_string(hyb));
-  full_string += int_to_hex_string(result);
+  full_string += intToHexString(result);
   return full_string;
 }
 
 
-bool FENConfigModule::configVMM(int hybrid_index, int vmm_index, bool enableConfigCheck)
+bool VmmTblAPI::configVMM(int hybrid_index, int vmm_index, bool enableConfigCheck)
 {
   bool result = true;
   bool ok;
@@ -203,7 +205,7 @@ bool FENConfigModule::configVMM(int hybrid_index, int vmm_index, bool enableConf
   for(unsigned int i = firstGlobalRegSPI_2; i <= lastGlobalRegSPI_2; i++) {
     std::string param = "vmm_global_bank2_sp" + std::to_string(i - firstGlobalRegSPI_2) + sVmmIndex;
     uint32_t value = std::stoul(globalRegisters2[i - firstGlobalRegSPI_2], nullptr, 2);
-    pFEN->userRegWrite(param, value);
+    userRegWrite(param, value);
   }
 
   //channel SPI
@@ -213,25 +215,25 @@ bool FENConfigModule::configVMM(int hybrid_index, int vmm_index, bool enableConf
     std::string param = "vmm_ch" + position_str + sVmmIndex;
     uint32_t value = std::stoul(channelRegisters[i], nullptr, 2);
     std::cout << "param: " << param << std::endl;
-    pFEN->userRegWrite(param, value);
+    userRegWrite(param, value);
   }
 
   // global SPI / VMM3: global bank 1
   for(unsigned int i = firstGlobalRegSPI_1; i <= lastGlobalRegSPI_1; i++) {
     std::string param = "vmm_global_bank1_sp" + std::to_string(i - firstGlobalRegSPI_1) + sVmmIndex;
     uint32_t value = std::stoul(globalRegisters[i - firstGlobalRegSPI_1], nullptr, 2);
-    pFEN->userRegWrite(param, value);
+    userRegWrite(param, value);
   }
 
   uint32_t value = (1 << idx);
-  pFEN->userRegWrite("sc_cfg_vmm", 0x00000000);
-  pFEN->userRegWrite("sc_cfg_vmm", value);
-  pFEN->userRegWrite("sc_cfg_vmm", 0x00000000);
+  userRegWrite("sc_cfg_vmm", 0x00000000);
+  userRegWrite("sc_cfg_vmm", value);
+  userRegWrite("sc_cfg_vmm", 0x00000000);
   
   return result;
 }
 
-void FENConfigModule::fillGlobalRegisters(std::vector<std::string>& global, int hybrid_index, int vmm_index)
+void VmmTblAPI::fillGlobalRegisters(std::vector<std::string>& global, int hybrid_index, int vmm_index)
 {
   unsigned short result;
 
@@ -324,7 +326,7 @@ void FENConfigModule::fillGlobalRegisters(std::vector<std::string>& global, int
 
 }
 
-void FENConfigModule::fillChRegisters(std::vector<std::string>& registers, int hybrid_index, int vmm_index)
+void VmmTblAPI::fillChRegisters(std::vector<std::string>& registers, int hybrid_index, int vmm_index)
 {
   registers.clear();
   unsigned short result;
@@ -362,7 +364,7 @@ void FENConfigModule::fillChRegisters(std::vector<std::string>& registers, int h
   }
 }
 
-void FENConfigModule::fillGlobalRegisters2(std::vector<std::string>& global, int hybrid_index, int vmm_index)
+void VmmTblAPI::fillGlobalRegisters2(std::vector<std::string>& global, int hybrid_index, int vmm_index)
 {
   unsigned short result;
   int sequence = 0;
@@ -407,7 +409,7 @@ void FENConfigModule::fillGlobalRegisters2(std::vector<std::string>& global, int
   global.push_back(spi2);
 }
 
-int FENConfigModule::readADC(int hybrid_index, int vmm_index) {
+int VmmTblAPI::readADC(int hybrid_index, int vmm_index) {
   int adc_result = 0;
   int vmm = hybrid_index * 2 + vmm_index;
   std::string sVmmIndex = "99";
@@ -427,17 +429,17 @@ int FENConfigModule::readADC(int hybrid_index, int vmm_index) {
   return adc_result;
 }
 
-uint32_t FENConfigModule::readWriteRegs(std::string command_reg, int index, std::string read_reg) {
+uint32_t VmmTblAPI::readWriteRegs(std::string command_reg, int index, std::string read_reg) {
   unsigned int data = 0x00000000;
-  pFEN->userRegWrite(command_reg, data);
+  userRegWrite(command_reg, data);
   data = (1 << index);
-  pFEN->userRegWrite(command_reg, data);
+  userRegWrite(command_reg, data);
 
   //Do not read registers back too soon, otherwise old ADC value is read
   delayMilliseconds(7);
 
-  uint32_t value = pFEN->userRegRead(read_reg);
-  pFEN->userRegWrite(command_reg, 0x0);
+  uint32_t value = userRegRead(read_reg);
+  userRegWrite(command_reg, 0x0);
 
   return value;
 }
diff --git a/vmmTblApp/src/vmm_config.h b/vmmTblApp/src/VmmTblAPI.h
similarity index 84%
rename from vmmTblApp/src/vmm_config.h
rename to vmmTblApp/src/VmmTblAPI.h
index 8518df02312d314dc72da7d0f66a4884e03695df..3a50365d7d6929900f16f73772c59b5f9b6cfa1d 100644
--- a/vmmTblApp/src/vmm_config.h
+++ b/vmmTblApp/src/VmmTblAPI.h
@@ -6,15 +6,17 @@
 #include <vector>
 #include <memory>
 #include <iostream>
-#include "hybrid.h"
 
-class FrontEndBase;
+#include "FrontEndBase.h"
+#include "FrontEndFactory.h"
+#include "VmmTblRegsMap.h"
+
+#include "hybrid.h"
 
-class FENConfigModule {
+class VmmTblAPI : public FrontEndBase {
 public:
-  FENConfigModule(FrontEndBase& frontend);
-  ~FENConfigModule();
-  void configFEN();
+  VmmTblAPI(RMMAPI* rmmApi, int ring, int node, std::string name);
+  ~VmmTblAPI();
   void configHybrid(int hybrid_index);
   bool configVMM(int hybrid_index, int vmm_index, bool enableConfigCheck=false);
   void fillGlobalRegisters(std::vector<std::string>& global, int hybrid_index, int vmm_index);
@@ -29,9 +31,9 @@ public:
   std::string readIDChip(int hyb);
   std::string readGeoPos(int hyb);
   std::string checkLinkStatus(int hyb);
+  void configFE();
 
 private:
-  FrontEndBase *pFEN;
   Hybrid hybrids[HYBRIDS_PER_FEN];
   bool enabled_hybrids[HYBRIDS_PER_FEN] = {};
   uint32_t readWriteRegs(std::string command_reg, int index, std::string read_reg);
diff --git a/vmmTblApp/src/vmm_tbl_regs_map.cpp b/vmmTblApp/src/VmmTblRegsMap.cpp
similarity index 99%
rename from vmmTblApp/src/vmm_tbl_regs_map.cpp
rename to vmmTblApp/src/VmmTblRegsMap.cpp
index 0b4d174685ebd4d8c4d53d1b76c53e3ccbfe7b31..1cdb3dda804881ecaf05d353353e12e72a2f6823 100644
--- a/vmmTblApp/src/vmm_tbl_regs_map.cpp
+++ b/vmmTblApp/src/VmmTblRegsMap.cpp
@@ -1,6 +1,6 @@
-#include "vmm_tbl_regs_map.h"
+#include "VmmTblRegsMap.h"
 
-const std::unordered_map<std::string, uint32_t> vmm_tbl_register_map = {
+extern const std::unordered_map<std::string, uint32_t> vmm_tbl_register_map = {
     { "REGBANK_VERSION", 0x00000000 },
     { "PHASH", 0x00000004 },
     { "ro_test", 0x00000008 },
diff --git a/vmmTblApp/src/vmm_tbl_regs_map.h b/vmmTblApp/src/VmmTblRegsMap.h
similarity index 90%
rename from vmmTblApp/src/vmm_tbl_regs_map.h
rename to vmmTblApp/src/VmmTblRegsMap.h
index 2ef88e96743530a2817cfe6bb737cc89b497414f..8f0f3d003f3a6f53be8740e2c6d63b19d0c3a42f 100644
--- a/vmmTblApp/src/vmm_tbl_regs_map.h
+++ b/vmmTblApp/src/VmmTblRegsMap.h
@@ -3,4 +3,4 @@
 #include <unordered_map>
 #include <string>
 
-extern const std::unordered_map<std::string, uint32_t> vmm_tbl_register_map;
+extern const std::unordered_map<std::string, uint32_t> vmm_tbl_register_map;
\ No newline at end of file
diff --git a/vmmTblApp/src/vmm_tbl.cpp b/vmmTblApp/src/vmm_tbl.cpp
index ef5eb0d6b47d0c115db65c0a6cd211a24cfd10ca..1274a9a1c8b7807c48b1025b4a07695c80e8bddd 100644
--- a/vmmTblApp/src/vmm_tbl.cpp
+++ b/vmmTblApp/src/vmm_tbl.cpp
@@ -1,29 +1,34 @@
 #include "vmm_tbl.h"
 
 /** Constructor for the VMMTbl class */
-VMMTbl::VMMTbl(RMM& rmm, int ring, int node, int hybrids)
-  : FrontEndBase(rmm.get_rmm_reg_access(), ring, node),
-    pVMMConfig(*this),
-    pRMM(&rmm)
+VMMTbl::VMMTbl(RMM* rmm, const char *FENPortName, int ring, int node, int hybrids)
+  : asynPortDriver(FENPortName, 0,
+      asynInt8ArrayMask | asynInt32Mask | asynInt64Mask | asynDrvUserMask | asynFloat64Mask | asynOctetMask,          // Interfaces that we implement
+      asynInt8ArrayMask | asynInt64Mask | asynInt32ArrayMask | asynFloat64Mask | asynInt32Mask | asynOctetMask,       // Interfaces that do callbacks
+      ASYN_MULTIDEVICE | ASYN_CANBLOCK, 1, /* ASYN_CANBLOCK=1, ASYN_MULTIDEVICE=1, autoConnect=1 */
+      0, 0),
+      number_hybrids(hybrids)
 {
-  number_hybrids = hybrids;
-  addr_list = ring * NUMBER_NODES_PER_RING + node;
-  fe_addr_map[ring] = vmm_tbl_register_map;
+
+  pVmmTblAPI = FrontEndFactory::createAndRegister<VmmTblAPI>(
+    rmm->getRMMAPI(),
+    ring,
+    node,
+    "VmmTbl",
+    vmm_tbl_register_map);
+
   createEpicsParams();
   setInitialEpicsParams();
-  pRMM->get_rmm_rings().set_topology(ring, node, "vmm-tbl");
-  pRMM->updateTopologyPvs(ring, node, "vmmTbl");
-  for (int hyb = 0; hyb < number_hybrids; hyb++) {
-    pVMMConfig.enableHybrid(hyb, true);
-    pRMM->setStringParam(addr_list, vmmHybFwVersion_[hyb], pVMMConfig.readFwVersion(hyb).c_str());
-    pRMM->setStringParam(addr_list, vmmHybId_[hyb], pVMMConfig.readIDChip(hyb).c_str());
-    pRMM->setStringParam(addr_list, vmmHybGeoPos_[hyb], pVMMConfig.readGeoPos(hyb).c_str());
-    pRMM->setIntegerParam(addr_list, vmmHybLinkStatus_[hyb], std::stoi(pVMMConfig.checkLinkStatus(hyb)));
+  rmm->updateTopologyPvs(ring, node, "vmmTbl");
+  if (rmm->getRMMAPI()->checkRings() == rmmSuccess) {
+    for (int hyb = 0; hyb < number_hybrids; hyb++) {
+      pVmmTblAPI->enableHybrid(hyb, true);
+      setStringParam(vmmHybFwVersion_[hyb], pVmmTblAPI->readFwVersion(hyb).c_str());
+      setStringParam(vmmHybId_[hyb], pVmmTblAPI->readIDChip(hyb).c_str());
+      setStringParam(vmmHybGeoPos_[hyb], pVmmTblAPI->readGeoPos(hyb).c_str());
+      setIntegerParam(vmmHybLinkStatus_[hyb], std::stoi(pVmmTblAPI->checkLinkStatus(hyb)));
+  }
   }
-}
-
-void VMMTbl::configFE() {
-  puts("config_FE");
 }
 
 void VMMTbl::setInitialEpicsParams() {
@@ -31,46 +36,46 @@ void VMMTbl::setInitialEpicsParams() {
 }
 
 asynStatus VMMTbl::createEpicsParams() {
-  pRMM->createParam(addr_list, "SEL_ANALOG_MONITOR_VMM0", asynParamInt32, &vmmSelectMonitorVMM0_);
-  pRMM->createParam(addr_list, "SEL_ANALOG_MONITOR_VMM1", asynParamInt32, &vmmSelectMonitorVMM1_);
-  pRMM->createParam(addr_list, "READ_ADC_VMMS", asynParamInt32, &vmmProcessReadMonitorVMMs_);
-  pRMM->createParam(addr_list, "ADC_VALUE_VMM0", asynParamFloat64, &vmmMonitorValueVMM0_);
-  pRMM->createParam(addr_list, "ADC_VALUE_VMM1", asynParamFloat64, &vmmMonitorValueVMM1_);
-  pRMM->createParam(addr_list, "VMM_FEN_ACQUIRE", asynParamInt32, &vmmAcquire_);
+  createParam("SEL_ANALOG_MONITOR_VMM0", asynParamInt32, &vmmSelectMonitorVMM0_);
+  createParam("SEL_ANALOG_MONITOR_VMM1", asynParamInt32, &vmmSelectMonitorVMM1_);
+  createParam("READ_ADC_VMMS", asynParamInt32, &vmmProcessReadMonitorVMMs_);
+  createParam("ADC_VALUE_VMM0", asynParamFloat64, &vmmMonitorValueVMM0_);
+  createParam("ADC_VALUE_VMM1", asynParamFloat64, &vmmMonitorValueVMM1_);
+  createParam("VMM_FEN_ACQUIRE", asynParamInt32, &vmmAcquire_);
 
   for (int hyb = 0; hyb < number_hybrids; hyb++) {
     std::ostringstream param_name;
     param_name << "HYB_" << hyb <<"_FW_VERSION";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamOctet, &vmmHybFwVersion_[hyb]);
+    createParam(param_name.str().c_str(), asynParamOctet, &vmmHybFwVersion_[hyb]);
     param_name.str("");
     param_name << "HYB_" << hyb <<"_ID";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamOctet, &vmmHybId_[hyb]);
+    createParam(param_name.str().c_str(), asynParamOctet, &vmmHybId_[hyb]);
     param_name.str("");
     param_name << "HYB_" << hyb <<"_GEOPOS";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamOctet, &vmmHybGeoPos_[hyb]);
+    createParam(param_name.str().c_str(), asynParamOctet, &vmmHybGeoPos_[hyb]);
     param_name.str("");
     param_name << "HYB_" << hyb <<"_LINK_STATUS";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamInt32, &vmmHybLinkStatus_[hyb]);
+    createParam(param_name.str().c_str(), asynParamInt32, &vmmHybLinkStatus_[hyb]);
     for (int vmm=0; vmm < VMMS_PER_HYBRID; vmm++)
     {
     param_name.str("");
     param_name << "HYB_" << hyb <<"_" << vmm << "_ST";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamInt8Array, &vmmST_[hyb][vmm]);
+    createParam(param_name.str().c_str(), asynParamInt8Array, &vmmST_[hyb][vmm]);
     param_name.str("");
     param_name << "HYB_" << hyb <<"_" << vmm << "_SC";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamInt8Array, &vmmSC_[hyb][vmm]);
+    createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSC_[hyb][vmm]);
     param_name.str("");
     param_name << "HYB_" << hyb <<"_" << vmm << "_SL";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamInt8Array, &vmmSL_[hyb][vmm]);
+    createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSL_[hyb][vmm]);
     param_name.str("");
     param_name << "HYB_" << hyb <<"_" << vmm << "_STH";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamInt8Array, &vmmSTH_[hyb][vmm]);
+    createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSTH_[hyb][vmm]);
     param_name.str("");
     param_name << "HYB_" << hyb <<"_" << vmm << "_SM";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamInt8Array, &vmmSM_[hyb][vmm]);
+    createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSM_[hyb][vmm]);
     param_name.str("");
     param_name << "HYB_" << hyb <<"_" << vmm << "_SMX";
-    pRMM->createParam(addr_list, param_name.str().c_str(), asynParamInt8Array, &vmmSMX_[hyb][vmm]);
+    createParam(param_name.str().c_str(), asynParamInt8Array, &vmmSMX_[hyb][vmm]);
     }
   }
 
@@ -80,37 +85,35 @@ asynStatus VMMTbl::createEpicsParams() {
 asynStatus VMMTbl::writeInt32(asynUser *pasynUser, epicsInt32 value) {
   asynStatus status = asynSuccess;
   int function = pasynUser->reason;
-  int addr = 0;
-  pRMM->getAddress(pasynUser, &addr);
 
   if ((value) && (function == vmmProcessReadMonitorVMMs_)) {
     int adc_sensor = 0;
     for (int vmm = 0; vmm <= 1; vmm++) {
-      pRMM->getIntegerParam(addr, vmmSelectMonitorVMM0_ + vmm, &adc_sensor);
+      getIntegerParam(vmmSelectMonitorVMM0_ + vmm, &adc_sensor);
       std::cout << "adc_sensor" << adc_sensor << std::endl;
-      pVMMConfig.getHybrid(0).getVMM(vmm).setRegister("sm5_sm0", adc_sensor + 64);
-      pVMMConfig.configVMM(0, vmm);
-      int adc_read = pVMMConfig.readADC(0, vmm);
+      pVmmTblAPI->getHybrid(0).getVMM(vmm).setRegister("sm5_sm0", adc_sensor + 64);
+      pVmmTblAPI->configVMM(0, vmm);
+      int adc_read = pVmmTblAPI->readADC(0, vmm);
 
       std::cout << "adc_read" << adc_read << std::endl;
 
       if (adc_sensor == 3) {
         double temperature = (725 - adc_read) / 1.85;
-        pRMM->setDoubleParam(addr, vmmMonitorValueVMM0_ + vmm, temperature);
+        setDoubleParam(vmmMonitorValueVMM0_ + vmm, temperature);
       }
       else {
-        pRMM->setDoubleParam(addr, vmmMonitorValueVMM0_ + vmm, adc_read);
+        setDoubleParam(vmmMonitorValueVMM0_ + vmm, adc_read);
       }
     }
   }
 
   else if (function == vmmAcquire_) {
   
-    if (value) pVMMConfig.acquire(true);
-    else pVMMConfig.acquire(false);
+    if (value) pVmmTblAPI->acquire(true);
+    else pVmmTblAPI->acquire(false);
 
     for (int hyb = 0; hyb < number_hybrids; hyb++)
-      pRMM->setIntegerParam(addr_list, vmmHybLinkStatus_[hyb], std::stoi(pVMMConfig.checkLinkStatus(hyb)));
+      setIntegerParam(vmmHybLinkStatus_[hyb], std::stoi(pVmmTblAPI->checkLinkStatus(hyb)));
   }
 
   return status;
@@ -127,28 +130,28 @@ asynStatus VMMTbl::writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t
   std::vector<epicsInt8> int8Array;
   Reg pair;
 
-  status |= pRMM->parseAsynUser(pasynUser, &function, &addr, &paramName);
-  pRMM->getParamName(addr, function, &paramName);
+  status |= parseAsynUser(pasynUser, &function, &addr, &paramName);
+  getParamName(function, &paramName);
   status |= findRegister(function, &pair);
   if (status) {
     asynPrint(pasynUser, ASYN_TRACE_ERROR,
               "%s:%s: function=%d, name=%s, value=%d. Cannot find which Hybrid-VMM pair is function related to.\n",
-              driverName, functionName, function, paramName, value);
+              driverName, functionName, function, paramName, *value);
     return (asynStatus) status;
   }
 
   asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
             "%s:%s: function=%d, name=%s, value=%d, hybrid=%d, vmm=%d, register=%s\n",
-            driverName, functionName, function, paramName, value, pair.hyb, pair.vmm, pair.rg.c_str());
+            driverName, functionName, function, paramName, *value, pair.hyb, pair.vmm, pair.rg.c_str());
 
   for (epicsInt8 i = 0; i < ncopy; ++i) {
     int8Array.push_back(static_cast<int>(value[i]) >= 1 ? 1 : 0);
-    pVMMConfig.getHybrid(pair.hyb).getVMM(pair.vmm).setRegister(pair.rg.c_str(),
+    pVmmTblAPI->getHybrid(pair.hyb).getVMM(pair.vmm).setRegister(pair.rg.c_str(),
                                                   static_cast<int>(value[i]),
                                                   i);
   }
 
-  status |= pRMM->doCallbacksInt8Array(int8Array.data(), int8Array.size(), function, 0);
+  status |= doCallbacksInt8Array(int8Array.data(), int8Array.size(), function, 0);
   return (asynStatus) status;
 
 }
@@ -185,35 +188,39 @@ asynStatus VMMTbl::findRegister(int function, Reg *reg_){
 
 asynStatus VMMTbl::writeFloat64(asynUser *pasynUser, epicsFloat64 value) {
   asynStatus status = asynSuccess;
-  int function = pasynUser->reason;
   int addr = 0;
-  pRMM->getAddress(pasynUser, &addr);
+  getAddress(pasynUser, &addr);
 
   return status;
 }
 
-
 extern "C" {
-  static void VMMTblConfig(const char *rmm_port_name, int ring, int hybrids) {
+  static void VMMTblConfig(const char *RMMPortName, const char* FENPortName, int ring, int hybrids) {
     int node = 0; // VMM use always only the Node 0
     RMM *pRMM;
-    pRMM = (RMM *) findAsynPortDriver(rmm_port_name);
-    pRMM->frontends[ring][node] = std::make_shared<VMMTbl>(*pRMM, ring, node, hybrids);
+    pRMM = (RMM *) findAsynPortDriver(RMMPortName);
+    if (pRMM != nullptr) {
+      new VMMTbl(pRMM, FENPortName, ring, node, hybrids);
+    } else {
+      std::cerr << "Error: Failed to find RMM for port " << RMMPortName << std::endl;
+    }
   }
 
   static const iocshArg configArg0 = { "RMM Port name", iocshArgString};
-  static const iocshArg configArg1 = { "Ring", iocshArgInt};
-  static const iocshArg configArg2 = { "Hybrids", iocshArgInt};
+  static const iocshArg configArg1 = { "Front End Port Name", iocshArgString};
+  static const iocshArg configArg2 = { "Ring", iocshArgInt};
+  static const iocshArg configArg3 = { "Hybrids", iocshArgInt};
 
 
   static const iocshArg * const configArgs[] = {&configArg0,
                                                 &configArg1,
-                                                &configArg2};
+                                                &configArg2,
+                                                &configArg3};
 
-  static const iocshFuncDef configFuncDef = {"VMMTblConfig", 3, configArgs};
+  static const iocshFuncDef configFuncDef = {"VMMTblConfig", 4, configArgs};
 
   static void configCallFunc(const iocshArgBuf *args) {
-    VMMTblConfig(args[0].sval, args[1].ival, args[2].ival);
+    VMMTblConfig(args[0].sval, args[1].sval, args[2].ival, args[3].ival);
   }
 
   static void VMMTblRegister(void) {
diff --git a/vmmTblApp/src/vmm_tbl.h b/vmmTblApp/src/vmm_tbl.h
index 98676877dbdd960052c0eef43b59b07e39ac90c5..f369eed6aac6a94cb72a9e97b9997a37b0af7537 100644
--- a/vmmTblApp/src/vmm_tbl.h
+++ b/vmmTblApp/src/vmm_tbl.h
@@ -1,9 +1,7 @@
 #pragma once
 
 #include "rmm.h"
-#include "FrontEndBase.h"
-#include "vmm_tbl_regs_map.h"
-#include "vmm_config.h"
+#include "VmmTblAPI.h"
 
 /* Struct to hold Hyb, VMM pair values */
 struct Reg {
@@ -13,15 +11,14 @@ struct Reg {
 };
 
 /** Class definition for the VMMTbl class */
-class VMMTbl : public FrontEndBase {
+class VMMTbl : public asynPortDriver {
 public:
-  VMMTbl(RMM& rmm, int ring, int node, int hybrids);
+  VMMTbl(RMM* rmm, const char *FENPortName, int ring, int node, int hybrids);
   asynStatus createEpicsParams();
 	virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
   virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
   virtual asynStatus writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements);
   void setInitialEpicsParams();
-  void configFE();
   asynStatus findRegister(int function, Reg *reg_);
 
 protected:
@@ -48,8 +45,6 @@ protected:
 
 private:
   static constexpr const char *driverName = "VMMTbl";
-  FENConfigModule pVMMConfig;
-  RMM *pRMM;
-  int addr_list = 0;
+  std::shared_ptr<VmmTblAPI> pVmmTblAPI;
   int number_hybrids;
 };