diff --git a/CMake/External/External_FTD2XX.cmake b/CMake/External/External_FTD2XX.cmake
index 533ad866d101f94639fd9cfac295f672b6b8a1e5..d3f6c7d8fc89fe05a3763b69683929cbefadbbd2 100644
--- a/CMake/External/External_FTD2XX.cmake
+++ b/CMake/External/External_FTD2XX.cmake
@@ -28,12 +28,23 @@ set(copy_ftd2xx_lib_command
   ${FTD2XX_EXTRACT_DIR}/${ftd2xx_libdir}/ftd2xx.lib
   ${CMAKE_INSTALL_PREFIX}/lib/ftd2xx.lib
   )
+  
 set(copy_ftd2xx_dll_command
   ${CMAKE_COMMAND} -E copy
   ${FTD2XX_EXTRACT_DIR}/${ftd2xx_libdir}/ftd2xx64.dll
   ${CMAKE_INSTALL_PREFIX}/bin/ftd2xx64.dll
   )
 
+# HS 2021-aug-08 Some dependencies expect the dll name to 
+# be ftd2xx.dll rather than ftd2xx64.dll we're copying here
+# to the renamed version as the whole chain is built via 64 bit builds
+set(copy_ftd2xx_dll_command_rename
+  ${CMAKE_COMMAND} -E copy
+  ${FTD2XX_EXTRACT_DIR}/${ftd2xx_libdir}/ftd2xx64.dll
+  ${CMAKE_INSTALL_PREFIX}/bin/ftd2xx.dll
+  )
+
+
 #-----------------------------------------------------------------------------
 # Add External Project
 #-----------------------------------------------------------------------------
@@ -51,6 +62,7 @@ imstk_add_external_project( FTD2XX
     COMMAND ${copy_ftd2xx_headers_command}
     COMMAND ${copy_ftd2xx_lib_command}
     COMMAND ${copy_ftd2xx_dll_command}
+    COMMAND ${copy_ftd2xx_dll_command_rename}
   RELATIVE_INCLUDE_PATH "/"
   #VERBOSE
 )
diff --git a/CMake/External/External_VRPN.cmake b/CMake/External/External_VRPN.cmake
index f7212a7775a37714f4786ab008441c444640bb9a..0d651c1d139d8d3979f4380f3cfdfa9023e4b0db 100644
--- a/CMake/External/External_VRPN.cmake
+++ b/CMake/External/External_VRPN.cmake
@@ -19,11 +19,13 @@ if(${${PROJECT_NAME}_USE_OpenHaptics})
   if(NOT EXISTS ${OPENHAPTICS_ROOT_DIR})
     message(FATAL_ERROR "\nCan not support Phantom Omni without OpenHaptics.\nSet OPENHAPTICS_ROOT_DIR to OpenHaptics installation directory.\n\n")
   endif()
+  list(APPEND VRPN_DEPENDENCIES "OpenHaptics")
 else()
   message(STATUS "Superbuild -   VRPN => Phantom Omni support DISABLED")
   if(DEFINED OPENHAPTICS_ROOT_DIR)
     unset(OPENHAPTICS_ROOT_DIR CACHE)
   endif()
+
 endif()
 
 #-----------------------------------------------------------------------------
@@ -46,13 +48,19 @@ imstk_add_external_project( VRPN
     -DVRPN_BUILD_PYTHON:BOOL=OFF
     -DVRPN_USE_GPM_MOUSE:BOOL=OFF
     -DVRPN_USE_LIBUSB_1_0:BOOL=ON
-    -DVRPN_USE_HID:BOOL=OFF
-    -DVRPN_USE_LIBNIFALCON:BOOL=ON
-    -DVRPN_BUILD_SERVERS:BOOL=${${PROJECT_NAME}_USE_OpenHaptics}
-    -DVRPN_USE_PHANTOM_SERVER:BOOL=${${PROJECT_NAME}_USE_OpenHaptics}
-    -DVRPN_USE_HDAPI:BOOL=${${PROJECT_NAME}_USE_OpenHaptics}
-    -DOPENHAPTICS_ROOT_DIR:PATH=${OPENHAPTICS_ROOT_DIR}
+    -DVRPN_USE_HID:BOOL=ON
+    -DVRPN_USE_LIBNIFALCON:BOOL=OFF
+    -DVRPN_BUILD_SERVERS:BOOL=ON
+    -DVRPN_USE_PHANTOM_SERVER:BOOL=OFF
+    -DVRPN_USE_HDAPI:BOOL=OFF
+    #-DOPENHAPTICS_ROOT_DIR:PATH=${OPENHAPTICS_ROOT_DIR}
   DEPENDENCIES ${VRPN_DEPENDENCIES}
   RELATIVE_INCLUDE_PATH ""
   #VERBOSE
-)
\ No newline at end of file
+)
+
+# Note HS-2021-28-7 currently disabled openhaptics with regards to VRPN, 
+# between the imstk superbuild and the VRPN cmake files the Openhaptics 
+# libraries can't be found by the VRPN build inside of the imstk superbuild
+# as we will mostly run haptics through the imstkOpenHaptics module this is 
+# not an issue for now 
\ No newline at end of file
diff --git a/CMake/FindVRPN.cmake b/CMake/FindVRPN.cmake
index ad58d9788136bd474ee3329c887e9bb74e20903d..5f09584faf6f79b8210a4e352f768478c7b7e0ed 100644
--- a/CMake/FindVRPN.cmake
+++ b/CMake/FindVRPN.cmake
@@ -5,6 +5,7 @@ include(imstkFind)
 
 imstk_find_header(VRPN vrpn_Configure.h vrpn)
 imstk_find_libary(VRPN vrpn)#Use same library for debug
+imstk_find_libary(VRPN quat)
 imstk_find_package(VRPN)
 
 #message(STATUS "VRPN include : ${VRPN_INCLUDE_DIRS}")
diff --git a/CMake/iMSTKConfig.cmake.in b/CMake/iMSTKConfig.cmake.in
index 2d76e631d8431f47a2d08380022d85de7ddc65a2..fb41d63d50a51bba56cc46202715643c06bbd248 100644
--- a/CMake/iMSTKConfig.cmake.in
+++ b/CMake/iMSTKConfig.cmake.in
@@ -14,6 +14,7 @@ set(iMSTK_USE_OpenHaptics @iMSTK_USE_OpenHaptics@)
 set(iMSTK_USE_VTK_OSMESA @iMSTK_USE_VTK_OSMESA@)
 set(iMSTK_BUILD_TESTING @iMSTK_BUILD_TESTING@)
 set(iMSTK_USE_PHYSX @iMSTK_USE_PHYSX@)
+set(iMSTK_USE_VRPN @iMSTK_USE_VRPN@)
 
 # Use the iMSTK modules to find all required packages
 set(CACHE_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
diff --git a/Docs/source/Devices.rst b/Docs/source/Devices.rst
index b0ec7b57f62946741bbc90abe9beb576329d2c39..780428e125aebb8b3431588b1646b48d5216b437 100644
--- a/Docs/source/Devices.rst
+++ b/Docs/source/Devices.rst
@@ -156,4 +156,19 @@ We can also apply forces on a haptics devices so the user may feel feedback. Whe
 
     ...
 
-    client->applyForce(Vec3d(0.0, 1.0, 0.0)); // Apply upwards force
\ No newline at end of file
+    client->applyForce(Vec3d(0.0, 1.0, 0.0)); // Apply upwards force
+
+VRPN
+====
+iMSTK currently supports the Tracker, Button and Analog device types of the VRPN library. It utilizes the normal VRPN server that will be in the installation directory when VRPN is enabled. The VRPNManager utilizes the VRPN client protocol to connect to the server and retrieve the data delivered by the VRPN. As VRPN uses TCP/IP for communication devices may be connected to a remote machine. With VRPN most of the device configuration is being done in the vrpn.cfg that is being used, ports, speeds, or world to virtual space transforms can be set up there. To use VRPN in iMSTK vrpn_server has to be started from the command line. When VRPN is enabled it will be installed in the iMSTK binary directory.
+
+::
+    
+    auto server = std::make_shared<VRPNDeviceManager>("localhost", 38833);
+    auto client = vrpnManager->makeDeviceClient("Tracker0", VRPNTracker)
+
+    auto manager = std::make_shared<SimulationManager>();
+    manager->addModule(server)
+    ...  
+
+If a special device is needs there are multiple extensions points, VRPNDeviceClient can be derived from and data could be mapped there. There are some VRPN devices that map data, or a specific VRPN device client could be implemented by overriding the update() method in the client. 
\ No newline at end of file
diff --git a/Examples/VRPNDeviceClient/CMakeLists.txt b/Examples/VRPNDeviceClient/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..34d7cd694960a98f475789f36eb1a180930af85f
--- /dev/null
+++ b/Examples/VRPNDeviceClient/CMakeLists.txt
@@ -0,0 +1,38 @@
+###########################################################################
+#
+# Copyright (c) Kitware, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0.txt
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+###########################################################################
+
+if(iMSTK_USE_VRPN)
+
+project(Example-VRPNDeviceClient)
+
+#-----------------------------------------------------------------------------
+# Create executable
+#-----------------------------------------------------------------------------
+imstk_add_executable(${PROJECT_NAME} VRPNDeviceClientExample.cpp)
+
+#-----------------------------------------------------------------------------
+# Add the target to Examples folder
+#-----------------------------------------------------------------------------
+SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples)
+
+#-----------------------------------------------------------------------------
+# Link libraries to executable
+#-----------------------------------------------------------------------------
+target_link_libraries(${PROJECT_NAME} SimulationManager Devices)
+
+endif()
\ No newline at end of file
diff --git a/Examples/VRPNDeviceClient/VRPNDeviceClientExample.cpp b/Examples/VRPNDeviceClient/VRPNDeviceClientExample.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c428be5463179ceb7075fac4758f420ba382324f
--- /dev/null
+++ b/Examples/VRPNDeviceClient/VRPNDeviceClientExample.cpp
@@ -0,0 +1,124 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+#include "imstkCamera.h"
+#include "imstkCollidingObject.h"
+#include "imstkDirectionalLight.h"
+#include "imstkKeyboardSceneControl.h"
+#include "imstkLight.h"
+#include "imstkLogger.h"
+#include "imstkMouseSceneControl.h"
+#include "imstkNew.h"
+#include "imstkOrientedBox.h"
+#include "imstkScene.h"
+#include "imstkSceneManager.h"
+#include "imstkSceneObjectController.h"
+#include "imstkSimulationManager.h"
+#include "imstkVRPNDeviceClient.h"
+#include "imstkVRPNDeviceManager.h"
+#include "imstkVTKViewer.h"
+
+using namespace imstk;
+
+///
+/// \brief This example demonstrates controlling the object
+/// using external device.
+///
+/// You should see a rectangular object that can be controlled with
+/// whatever device you configured as the designated tracker
+///
+/// Expects vrpn_server to be running and listening to the default port
+/// and have a tracker to configured as the "Tracker0" device in it `vrpn.cfg`
+int
+main()
+{
+    // Setup logger (write to file and stdout)
+    Logger::startLogger();
+
+    // Create Scene
+    imstkNew<Scene> scene("ObjectController");
+
+    /// \ IP address of the server.
+    const std::string serverIP = "localhost";
+
+    /// \ the default VRPN port 38833
+    const int serverPort = 38833;
+
+    //VRPN Server
+    auto server = std::make_shared<VRPNDeviceManager>(serverIP, serverPort);
+
+    auto client = server->makeDeviceClient("Tracker0", VRPNTracker);
+
+    std::shared_ptr<AnalyticalGeometry> geometries[] = {
+        std::make_shared<OrientedBox>(Vec3d::Zero(), Vec3d(1.0, 5.0, 1.0)),
+    };
+
+    imstkNew<SceneObject> object("VirtualObject");
+    object->setVisualGeometry(geometries[0]);
+    scene->addSceneObject(object);
+
+    imstkNew<SceneObjectController> controller(object, client);
+    controller->setTranslationScaling(0.1);
+    scene->addController(controller);
+
+    // Update Camera position
+    std::shared_ptr<Camera> cam = scene->getActiveCamera();
+    cam->setPosition(Vec3d(0.0, 0.0, 10.0));
+    cam->setFocalPoint(geometries[0]->getPosition());
+
+    // Light
+    imstkNew<DirectionalLight> light;
+    light->setDirection(Vec3d(5.0, -8.0, -5.0));
+    light->setIntensity(1.0);
+    scene->addLight("light", light);
+
+    //Run the simulation
+    {
+        // Setup a viewer to render
+        imstkNew<VTKViewer> viewer("Viewer 1");
+        viewer->setActiveScene(scene);
+
+        // Setup a scene manager to advance the scene
+        imstkNew<SceneManager> sceneManager("Scene Manager 1");
+        sceneManager->setActiveScene(scene);
+        sceneManager->setExecutionType(Module::ExecutionType::ADAPTIVE);
+
+        imstkNew<SimulationManager> driver;
+        driver->addModule(viewer);
+        driver->addModule(sceneManager);
+        driver->addModule(server);
+        driver->setDesiredDt(0.01);
+
+        // Add mouse and keyboard controls to the viewer
+        {
+            imstkNew<MouseSceneControl> mouseControl(viewer->getMouseDevice());
+            mouseControl->setSceneManager(sceneManager);
+            viewer->addControl(mouseControl);
+
+            imstkNew<KeyboardSceneControl> keyControl(viewer->getKeyboardDevice());
+            keyControl->setSceneManager(sceneManager);
+            keyControl->setModuleDriver(driver);
+            viewer->addControl(keyControl);
+        }
+
+        driver->start();
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 350f7389aef8787038a25704bbb86b5266182951..f1a8ddd6665d10bd2ae8145c5160b7309aef7c99 100644
--- a/README.md
+++ b/README.md
@@ -118,6 +118,22 @@ To support the [Geomagic Touch (formerly Sensable Phantom Omni)](http://www.geom
   2. Reboot your system.
   3. Configure your CMake project with the variable `iMSTK_USE_OpenHaptics` set to `ON`.
   4. After configuration, the CMake variable `OPENHAPTICS_ROOT_DIR` should be set to the OpenHaptics path on your system.
+  
+* ##### VRPN Support
+
+The `VRPNDeviceModule` enables access to a large number devices supported by VRPN. The `VRPNDeviceModule` expects a `vrpn_server` to be running. The iMSTK superbuild builds and
+installs a server with some default settings but if you want to configure a specific server
+it might be easier to separately build a server. The file `CMake\External\External_VRPN.cmake`
+shows how to pass configuration into VRPN in case you want to modify the modules enabled and
+disabled by the build
+
+The `vrpn.cfg` that is installed by default doesn't have any devices enabled, before use you 
+will need to uncomment the devices that you would like to use. If you use the one inside the 
+iMSTK install directory please note that it will be overwritten every time the superbuild is 
+run. 
+
+Currently iMSTK supports VRPN `Analog`, `Button` and `Tracker` devices. Future support will
+depend on user demand.
 
 * ##### Offscreen Rendering
 To render without the usage of a GPU or without the usage of a screen on linux (or WSL), iMSTK's VTK renderer may be built with OSMesa.
diff --git a/Source/Devices/CMakeLists.txt b/Source/Devices/CMakeLists.txt
index 04052d960afa970981a606ea27db87d497a067e9..3f054bfd2f875425319a87ecaad761756f292f0c 100644
--- a/Source/Devices/CMakeLists.txt
+++ b/Source/Devices/CMakeLists.txt
@@ -21,10 +21,8 @@ if(NOT iMSTK_USE_OpenHaptics)
 endif()
 if(NOT iMSTK_USE_VRPN)
   list(APPEND ExclusionFiles
-    imstkVRPNDeviceServer.h
-    imstkVRPNDeviceServer.cpp
-    imstkVRPNArduinoDeviceClient.h
-    imstkVRPNArduinoDeviceClient.cpp
+    imstkVRPNDeviceManager.h
+    imstkVRPNDeviceManager.cpp
     imstkVRPNDeviceClient.h
     imstkVRPNDeviceClient.cpp)
 endif()
diff --git a/Source/Devices/imstkDeviceClient.cpp b/Source/Devices/imstkDeviceClient.cpp
index 22beb0ceedb3e5008260e105af0f4982af5d5ea3..e1a94e5fabe62c1fa340549bfa6c2c7adea0fd31 100644
--- a/Source/Devices/imstkDeviceClient.cpp
+++ b/Source/Devices/imstkDeviceClient.cpp
@@ -91,4 +91,20 @@ DeviceClient::setForce(Vec3d force)
     m_force = force;
     m_forceLock.unlock();
 }
+
+const std::unordered_map<int, int>&
+DeviceClient::getButtons() const
+{
+    return m_buttons;
+}
+
+const std::vector<double>
+DeviceClient::getAnalog() const
+{
+    std::vector<double> result;
+    m_dataLock.lock();
+    result = m_analogChannels;
+    m_dataLock.unlock();
+    return result;
+}
 } // imstk
diff --git a/Source/Devices/imstkDeviceClient.h b/Source/Devices/imstkDeviceClient.h
index 44c835cc973fc168a9a03227830662ff0ee08c89..228d73bb1a871f6c2f110df92fdeea4510e35239 100644
--- a/Source/Devices/imstkDeviceClient.h
+++ b/Source/Devices/imstkDeviceClient.h
@@ -135,7 +135,7 @@ public:
     ///
     /// \brief Get button map
     ///
-    const std::unordered_map<int, int>& getButtons() const { return m_buttons; }
+    const std::unordered_map<int, int>& getButtons() const;
 
     ///
     /// \brief Get the state of a button
@@ -143,16 +143,18 @@ public:
     ///
     const int getButton(const int buttonId)
     {
+        int result = 0;
+        m_dataLock.lock();
         if (m_buttons.find(buttonId) != m_buttons.end())
         {
-            return m_buttons.at(buttonId);
-        }
-        else
-        {
-            return 0;
+            result = m_buttons.at(buttonId);
         }
+        m_dataLock.unlock();
+        return result;
     }
 
+    const std::vector<double> getAnalog() const;
+
     ///
     /// \brief Do runtime logic
     ///
@@ -174,11 +176,14 @@ protected:
     Vec3d m_angularVelocity;                          ///< Angular velocity of the end effector
     Quatd m_orientation;                              ///< Orientation of the end effector
     Vec3d m_force;                                    ///< Force vector
-    Vec3d m_endEffectorOffset = Vec3d(0.0, 0.0, 0.0); ///> Offset from origin
+    Vec3d m_endEffectorOffset = Vec3d(0.0, 0.0, 0.0); ///< Offset from origin
 
     std::unordered_map<int, int> m_buttons;
+    std::vector<double> m_analogChannels;
 
-    ParallelUtils::SpinLock m_transformLock; /// > Used for devices filling data from other threads
-    ParallelUtils::SpinLock m_forceLock;     /// > Used for devices filling data from other threads
+    ParallelUtils::SpinLock m_transformLock;    /// > Used for devices filling data from other threads
+    ParallelUtils::SpinLock m_forceLock;        /// > Used for devices filling data from other threads
+    mutable ParallelUtils::SpinLock m_dataLock; /// > Used for button and analog data
+private:
 };
 }
diff --git a/Source/Devices/imstkVRPNArduinoDeviceClient.cpp b/Source/Devices/imstkVRPNArduinoDeviceClient.cpp
deleted file mode 100644
index afe7734e123b6791ce86ed1fcfe16e79968c437a..0000000000000000000000000000000000000000
--- a/Source/Devices/imstkVRPNArduinoDeviceClient.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*=========================================================================
-
-   Library: iMSTK
-
-   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
-   & Imaging in Medicine, Rensselaer Polytechnic Institute.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0.txt
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
-=========================================================================*/
-
-#include "imstkVRPNArduinoDeviceClient.h"
-
-namespace imstk
-{
-bool
-VRPNArduinoDeviceClient::initModule()
-{
-    m_vrpnAnalog = std::make_shared<vrpn_Analog_Remote>(getDeviceName().c_str());
-    m_vrpnAnalog->register_change_handler(this, analogChangeHandler);
-    m_vrpnAnalog->shutup = true;
-    return true;
-}
-
-void
-VRPNArduinoDeviceClient::updateModule()
-{
-    m_vrpnAnalog->mainloop();
-}
-
-void
-VRPNArduinoDeviceClient::uninitModule()
-{
-    //Module cleanup is causing TCP errors - seems to work fine without it
-    //m_vrpnAnalog->unregister_change_handler(this, analogChangeHandler);
-    //m_vrpnAnalog.reset();
-}
-
-void VRPN_CALLBACK
-VRPNArduinoDeviceClient::analogChangeHandler(void* userData, const _vrpn_ANALOGCB a)
-{
-    auto deviceClient = reinterpret_cast<VRPNArduinoDeviceClient*>(userData);
-
-    //deviceClient->m_ypr << a.channel[0], a.channel[1], a.channel[2];
-    //deviceClient->m_accel << a.channel[3], a.channel[4], a.channel[5];
-    deviceClient->m_roll = (float)a.channel[0];
-}
-} // imstk
diff --git a/Source/Devices/imstkVRPNArduinoDeviceClient.h b/Source/Devices/imstkVRPNArduinoDeviceClient.h
deleted file mode 100644
index e4e393246e304015273c0ab63d45a755023283aa..0000000000000000000000000000000000000000
--- a/Source/Devices/imstkVRPNArduinoDeviceClient.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*=========================================================================
-
-   Library: iMSTK
-
-   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
-   & Imaging in Medicine, Rensselaer Polytechnic Institute.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0.txt
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
-=========================================================================*/
-
-#pragma once
-
-#include "imstkDeviceClient.h"
-#include "imstkModule.h"
-
-#include <vrpn_Configure.h>
-#include <vrpn_Analog.h>
-
-namespace imstk
-{
-///
-/// \class VRPNDeviceClient
-/// \brief Subclass of DeviceClient using VRPN
-///
-class VRPNArduinoDeviceClient : public DeviceClient, public Module
-{
-public:
-
-    ///
-    /// \brief Constructor
-    ///
-    VRPNArduinoDeviceClient(const std::string& deviceName, const std::string& ip) :
-        DeviceClient(deviceName, ip),
-        m_ypr(Vec3d::Zero()),
-        m_accel(Vec3d::Zero()),
-        m_roll(0) {}
-
-    ///
-    /// \brief Destructor
-    ///
-    virtual ~VRPNArduinoDeviceClient() override = default;
-
-    ///
-    /// \brief Get YPR
-    ///
-    Vec3d& getYPR() { return m_ypr; }
-
-    ///
-    /// \brief Get acceleration
-    ///
-    Vec3d& getAcceleration() { return m_accel; }
-
-    ///
-    /// \brief Get the roll
-    ///
-    float getRoll() { return m_roll; }
-
-protected:
-    ///
-    /// \brief Initialize device client module
-    ///
-    bool initModule() override;
-
-    ///
-    /// \brief Run the device client
-    ///
-    void updateModule() override;
-
-    ///
-    /// \brief Clean the device client
-    ///
-    void uninitModule() override;
-
-private:
-
-    ///
-    /// \brief VRPN call back for position and orientation data
-    /// \param userData Pointer to this to allow updating
-    /// internal data
-    /// \param b VRPN callback structure containing new position and
-    /// orientation data
-    ///
-    static void VRPN_CALLBACK analogChangeHandler(void* userData, const _vrpn_ANALOGCB a);
-
-    std::shared_ptr<vrpn_Analog_Remote> m_vrpnAnalog;           //!< VRPN position/orientation interface
-    Vec3d m_ypr;
-    Vec3d m_accel;
-    float m_roll;
-};
-}
diff --git a/Source/Devices/imstkVRPNDeviceClient.cpp b/Source/Devices/imstkVRPNDeviceClient.cpp
index b7fff1a372d67e4875337616649a493cf1be3b5d..06f589a3545b808fcfc48a6b450d29a2cd92ad99 100644
--- a/Source/Devices/imstkVRPNDeviceClient.cpp
+++ b/Source/Devices/imstkVRPNDeviceClient.cpp
@@ -20,115 +20,64 @@
 =========================================================================*/
 
 #include "imstkVRPNDeviceClient.h"
+
+#include "quat.h"
+
 #include "imstkLogger.h"
 
 namespace imstk
 {
-bool
-VRPNDeviceClient::initModule()
+VRPNDeviceClient::VRPNDeviceClient(const std::string& deviceName, VRPNDeviceType type, const std::string& ip /*= "localhost"*/) :
+    DeviceClient(deviceName, ip), m_type(type)
 {
-    const char* fullDeviceIp = (getDeviceName() + "@" + m_ip).c_str();
-
-    m_vrpnTracker     = std::make_shared<vrpn_Tracker_Remote>(fullDeviceIp);
-    m_vrpnAnalog      = std::make_shared<vrpn_Analog_Remote>(fullDeviceIp);
-    m_vrpnButton      = std::make_shared<vrpn_Button_Remote>(fullDeviceIp);
-    m_vrpnForceDevice = std::make_shared<vrpn_ForceDevice_Remote>(fullDeviceIp);
-
-    m_vrpnTracker->register_change_handler(this, trackerChangeHandler);
-    m_vrpnTracker->register_change_handler(this, velocityChangeHandler);
-    m_vrpnAnalog->register_change_handler(this, analogChangeHandler);
-    m_vrpnButton->register_change_handler(this, buttonChangeHandler);
-    m_vrpnForceDevice->register_force_change_handler(this, forceChangeHandler);
-
-    m_vrpnForceDevice->setFF_Origin(0, 0, 0);
-    m_vrpnForceDevice->setFF_Jacobian(0, 0, 0, 0, 0, 0, 0, 0, 0);
-    m_vrpnForceDevice->setFF_Radius(2);
-    return true;
-}
-
-void
-VRPNDeviceClient::updateModule()
-{
-    if (this->getTrackingEnabled())
-    {
-        m_vrpnTracker->mainloop();
-    }
-    if (this->getAnalogicEnabled())
-    {
-        m_vrpnAnalog->mainloop();
-    }
-    if (this->getButtonsEnabled())
-    {
-        m_vrpnButton->mainloop();
-    }
-    if (this->getForceEnabled())
-    {
-        m_vrpnForceDevice->setFF_Force(vrpn_float32(m_force[0]), vrpn_float32(m_force[1]), vrpn_float32(m_force[2]));
-        m_vrpnForceDevice->sendForceField();
-        m_vrpnForceDevice->mainloop();
-    }
-}
-
-void
-VRPNDeviceClient::uninitModule()
-{
-    m_vrpnTracker->unregister_change_handler(this, trackerChangeHandler);
-    m_vrpnTracker->unregister_change_handler(this, velocityChangeHandler);
-    m_vrpnAnalog->unregister_change_handler(this, analogChangeHandler);
-    m_vrpnButton->unregister_change_handler(this, buttonChangeHandler);
-    m_vrpnForceDevice->unregister_force_change_handler(this, forceChangeHandler);
-
-    m_vrpnForceDevice->stopForceField();
-
-    m_vrpnTracker.reset();
-    m_vrpnAnalog.reset();
-    m_vrpnButton.reset();
-    m_vrpnForceDevice.reset();
+    m_trackingEnabled = (type & VRPNTracker) != 0;
+    m_buttonsEnabled  = (type & VRPNButton) != 0;
+    m_analogicEnabled = (type & VRPNAnalog) != 0;
+    m_forceEnabled    = (type & VRPNForce) != 0;
 }
 
 void VRPN_CALLBACK
-VRPNDeviceClient::trackerChangeHandler(void* userData, const _vrpn_TRACKERCB t)
+VRPNDeviceClient::trackerPositionChangeHandler(void* userData, const _vrpn_TRACKERCB t)
 {
-    auto deviceClient = reinterpret_cast<VRPNDeviceClient*>(userData);
-    deviceClient->m_position << t.pos[0], t.pos[1], t.pos[2];
+    auto deviceClient = static_cast<VRPNDeviceClient*>(userData);
 
     Quatd quat;
-    quat.x() = t.quat[0];
-    quat.y() = t.quat[1];
-    quat.z() = t.quat[2];
-    quat.w() = t.quat[3];
-    deviceClient->m_orientation = quat;
+    quat.x() = t.quat[1];
+    quat.y() = t.quat[2];
+    quat.z() = t.quat[3];
+    quat.w() = t.quat[0];
 
-    //LOG(DEBUG) << "tracker: position = " << t.pos[0] << " " << t.pos[1] << " " << t.pos[2];
-    //LOG(DEBUG) << "tracker: orientation = " << deviceClient->m_orientation.matrix();
+    deviceClient->m_transformLock.lock();
+    deviceClient->m_position << t.pos[0], t.pos[1], t.pos[2];
+    deviceClient->m_orientation = quat;
+    deviceClient->m_transformLock.unlock();
 }
 
 void VRPN_CALLBACK
 VRPNDeviceClient::analogChangeHandler(void* userData, const _vrpn_ANALOGCB a)
 {
-    auto deviceClient = reinterpret_cast<VRPNDeviceClient*>(userData);
-
-    if (a.num_channel >= 3)
-    {
-        deviceClient->m_position << a.channel[0], a.channel[1], a.channel[2];
-        //LOG(DEBUG) << "analog: position = " << deviceClient->m_position;
-    }
-    if (a.num_channel >= 6)
+    auto deviceClient = static_cast<VRPNDeviceClient*>(userData);
+    deviceClient->m_dataLock.lock();
+    deviceClient->m_analogChannels.resize(a.num_channel);
+    for (int i = 0; i < a.num_channel; i++)
     {
-        deviceClient->m_orientation =
-            Rotd(a.channel[3] * PI, Vec3d::UnitX()) *
-            Rotd(a.channel[4] * PI, Vec3d::UnitY()) *
-            Rotd(a.channel[5] * PI, Vec3d::UnitZ());
-        //LOG(DEBUG) << "analog: orientation = " << deviceClient->m_orientation.matrix();
+        deviceClient->m_analogChannels[i] = a.channel[i];
     }
+    deviceClient->m_dataLock.unlock();
 }
 
 void VRPN_CALLBACK
-VRPNDeviceClient::velocityChangeHandler(void* userData, const _vrpn_TRACKERVELCB v)
+VRPNDeviceClient::trackerVelocityChangeHandler(void* userData, const _vrpn_TRACKERVELCB v)
 {
-    auto deviceClient = reinterpret_cast<VRPNDeviceClient*>(userData);
+    auto  deviceClient = reinterpret_cast<VRPNDeviceClient*>(userData);
+    Quatd quat(v.vel_quat[1], v.vel_quat[2], v.vel_quat[3], v.vel_quat[0]);
+
+    deviceClient->m_transformLock.lock();
     deviceClient->m_velocity << v.vel[0], v.vel[1], v.vel[2];
-    //LOG(DEBUG) << "tracker: velocity = " << deviceClient->m_velocity;
+    // \todo translate velocity quaternion to imstk
+    // deviceClient->m_angularVelocity = quat;
+    //
+    deviceClient->m_transformLock.unlock();
 }
 
 void VRPN_CALLBACK
@@ -136,14 +85,11 @@ VRPNDeviceClient::buttonChangeHandler(void* userData, const _vrpn_BUTTONCB b)
 {
     auto deviceClient = reinterpret_cast<VRPNDeviceClient*>(userData);
     deviceClient->m_buttons[b.button] = (b.state == 1);
-    //LOG(DEBUG) << "buttons: " << b.button << " = " << deviceClient->m_buttons[b.button];
 }
 
-void VRPN_CALLBACK
-VRPNDeviceClient::forceChangeHandler(void* userData, const _vrpn_FORCECB f)
+imstk::VRPNDeviceType
+VRPNDeviceClient::getType() const
 {
-    auto deviceClient = reinterpret_cast<VRPNDeviceClient*>(userData);
-    deviceClient->m_force << f.force[0], f.force[1], f.force[2];
-    LOG(DEBUG) << "forceDevice: force = " << deviceClient->m_force;
+    return m_type;
 }
 } // imstk
diff --git a/Source/Devices/imstkVRPNDeviceClient.h b/Source/Devices/imstkVRPNDeviceClient.h
index eba7d025d0966fed0134a2b9d237ac63b0a31e7b..5fd2a51e68e7ab0b9104d0091c64b1242e8ae7d5 100644
--- a/Source/Devices/imstkVRPNDeviceClient.h
+++ b/Source/Devices/imstkVRPNDeviceClient.h
@@ -22,104 +22,73 @@
 #pragma once
 
 #include "imstkDeviceClient.h"
-#include "imstkModule.h"
 
-#include <vrpn_Configure.h>
-#include <vrpn_Tracker.h>
-#include <vrpn_Analog.h>
-#include <vrpn_Button.h>
-#include <vrpn_ForceDevice.h>
-#include <unordered_map>
+#include "vrpn_Tracker.h"
+#include "vrpn_Analog.h"
+#include "vrpn_Button.h"
+#include "vrpn_ForceDevice.h"
+
+#include "imstkVRPNDeviceManager.h"
 
 namespace imstk
 {
 ///
 /// \class VRPNDeviceClient
-/// \brief Subclass of DeviceClient using VRPN
+/// \brief This class is the receiver of the updates sent by the vrpn_server
+///
+/// After adding a `VRPNDeviceClient` to the `VRPNDeviceManger` the static functions
+/// in this class will be called whenever new data comes in from `vrpn_server`.
 ///
-class VRPNDeviceClient : public DeviceClient, public Module
+class VRPNDeviceClient : public DeviceClient
 {
 public:
 
     ///
     /// \brief Constructor
     ///
-    VRPNDeviceClient(const std::string& deviceName, const std::string& ip) : Module(),
-        DeviceClient(deviceName, ip)
-    {}
+    VRPNDeviceClient(const std::string& deviceName, VRPNDeviceType type, const std::string& ip = "localhost");
 
     ///
     /// \brief Destructor
     ///
     virtual ~VRPNDeviceClient() override = default;
 
-protected:
-    ///
-    /// \brief Initialize device client module
-    ///
-    bool initModule() override;
-
-    ///
-    /// \brief Run the device client
-    ///
-    void updateModule() override;
-
-    ///
-    /// \brief Clean the device client
-    ///
-    void uninitModule() override;
-
-private:
-
     ///
     /// \brief VRPN call back for position and orientation data
-    /// \param userData Pointer to this to allow updating
-    /// internal data
-    /// \param b VRPN callback structure containing new position and
-    /// orientation data
+    /// \param userData Pointer to a VRPNDeviceClient to allow updating internal data the server class
+    ///                 used the device client pointer when registering
+    /// \param t VRPN callback structure containing new position and orientation data
     ///
-    static void VRPN_CALLBACK trackerChangeHandler(void* userData, const _vrpn_TRACKERCB t);
+    static void VRPN_CALLBACK trackerPositionChangeHandler(void* userData, const _vrpn_TRACKERCB t);
 
     ///
-    /// \brief VRPN call back for position and orientation data
-    /// \param userData Pointer to this to allow updating
-    /// internal data
-    /// \param b VRPN callback structure containing new position and
-    /// orientation data
+    /// \brief VRPN call back for velocity data
+    /// \param userData Pointer to a VRPNDeviceClient to allow updating internal data the server class
+    ///                 used the device client pointer when registering
+    /// \param v VRPN callback structure tracker velocity
     ///
-    static void VRPN_CALLBACK analogChangeHandler(void* userData, const _vrpn_ANALOGCB a);
+    static void VRPN_CALLBACK trackerVelocityChangeHandler(void* userData, const _vrpn_TRACKERVELCB v);
 
     ///
-    /// \brief VRPN call back for velocity data
-    /// \param userData Pointer to this to allow updating
-    /// internal data
-    /// \param v VRPN callback structure containing new position and
-    /// orientation data
+    /// \brief VRPN call back analog data
+    /// \param userData Pointer to a VRPNDeviceClient to allow updating internal data the server class
+    ///                 used the device client pointer when registering
+    /// \param a VRPN callback structure for the analog data
     ///
-    static void VRPN_CALLBACK velocityChangeHandler(void* userData, const _vrpn_TRACKERVELCB v);
+    static void VRPN_CALLBACK analogChangeHandler(void* userData, const _vrpn_ANALOGCB a);
 
     ///
     /// \brief VRPN call back for button changed (pressed or released)
-    /// \param userData Pointer to this to allow updating
-    /// internal data
+    /// \param userData Pointer to a VRPNDeviceClient to allow updating internal data the server class
+    ///                 used the device client pointer when registering
     /// \param b VRPN callback structure containing new button data
     ///
     static void VRPN_CALLBACK buttonChangeHandler(void* userData, const _vrpn_BUTTONCB b);
 
-    ///
-    /// \brief VRPN call back for force data
-    /// \param userData Pointer to this to allow updating
-    /// internal data
-    /// \param f VRPN callback structure containing new force data
-    ///
-    static void VRPN_CALLBACK forceChangeHandler(void* userData, const _vrpn_FORCECB f);
-
-    std::shared_ptr<vrpn_Tracker_Remote>     m_vrpnTracker;     //!< VRPN position/orientation interface
-    std::shared_ptr<vrpn_Analog_Remote>      m_vrpnAnalog;      //!< VRPN position/orientation interface
-    std::shared_ptr<vrpn_Button_Remote>      m_vrpnButton;      //!< VRPN button interface
-    std::shared_ptr<vrpn_ForceDevice_Remote> m_vrpnForceDevice; //!< VRPN force interface
+    /// \return all the types that this client is tracking
+    VRPNDeviceType getType() const;
 
-public:
-    std::unordered_map<int, bool> m_buttons;
+private:
+    VRPNDeviceType m_type;
 };
 }
diff --git a/Source/Devices/imstkVRPNDeviceManager.cpp b/Source/Devices/imstkVRPNDeviceManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0ce8045b4e10c3476d27a26423563100a6fb7978
--- /dev/null
+++ b/Source/Devices/imstkVRPNDeviceManager.cpp
@@ -0,0 +1,105 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkVRPNDeviceManager.h"
+
+#include "vrpn_Analog.h"
+#include "vrpn_Button.h"
+#include "vrpn_Tracker.h"
+
+#include "imstkDeviceClient.h"
+#include "imstkLogger.h"
+#include "imstkVRPNDeviceClient.h"
+
+namespace imstk
+{
+VRPNDeviceManager::VRPNDeviceManager(const std::string& machine /*= "localhost"*/, int port /*= vrpn_DEFAULT_LISTEN_PORT_NO*/) : Module(),
+    m_machine(machine),
+    m_port(port),
+    m_deviceConnections(new vrpn_MainloopContainer())
+{
+    setSleepDelay(1000 / 60);
+}
+
+void
+VRPNDeviceManager::addDeviceClient(std::shared_ptr<VRPNDeviceClient> client)
+{
+    std::string name   = client->getDeviceName();
+    void*       handle = client.get();
+
+    std::string address  = name + "@" + m_machine;
+    const char* _address = address.c_str();
+
+    int type = client->getType();
+
+    if ( (type & VRPNAnalog) != 0)
+    {
+        LOG(INFO) << "Adding Analog Device: " << name;
+        vrpn_Analog_Remote* vrpnAnalog = new vrpn_Analog_Remote(_address);
+        m_deviceConnections->add(vrpnAnalog);
+        vrpnAnalog->register_change_handler(handle, VRPNDeviceClient::analogChangeHandler);
+        m_deviceMap[VRPNAnalog].push_back(client);
+    }
+    if ( (type & VRPNTracker) != 0)
+    {
+        LOG(INFO) << "Adding Tracker Device: " << name;
+        vrpn_Tracker_Remote* vrpnTracker = new vrpn_Tracker_Remote(_address);
+        m_deviceConnections->add(vrpnTracker);
+        vrpnTracker->register_change_handler(handle, VRPNDeviceClient::trackerPositionChangeHandler);
+        vrpnTracker->register_change_handler(handle, VRPNDeviceClient::trackerVelocityChangeHandler);
+        m_deviceMap[VRPNTracker].push_back(client);
+    }
+    if ( (type & VRPNButton) != 0)
+    {
+        LOG(INFO) << "Adding Button Device: " << name;
+        vrpn_Button_Remote* vrpnButton = new vrpn_Button_Remote(_address);
+        m_deviceConnections->add(vrpnButton);
+        vrpnButton->register_change_handler(handle, VRPNDeviceClient::buttonChangeHandler);
+        m_deviceMap[VRPNButton].push_back(client);
+    }
+}
+
+std::shared_ptr<imstk::DeviceClient>
+VRPNDeviceManager::makeDeviceClient(const std::string& deviceName, VRPNDeviceType deviceType)
+{
+    auto client = std::make_shared<VRPNDeviceClient>(deviceName, deviceType, m_machine);
+    addDeviceClient(client);
+    return client;
+}
+
+bool
+VRPNDeviceManager::initModule()
+{
+    return true;
+}
+
+void
+VRPNDeviceManager::updateModule()
+{
+    m_deviceConnections->mainloop();
+}
+
+void
+VRPNDeviceManager::uninitModule()
+{
+    m_deviceConnections->clear();
+}
+} // imstk
diff --git a/Source/Devices/imstkVRPNDeviceManager.h b/Source/Devices/imstkVRPNDeviceManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..b85db0d4723da33a009f665f55f886512c8c721c
--- /dev/null
+++ b/Source/Devices/imstkVRPNDeviceManager.h
@@ -0,0 +1,113 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkModule.h"
+
+#include <map>
+#include <string>
+
+#include <vrpn_Connection.h>
+#include <vrpn_MainloopContainer.h>
+
+//VRPN
+#include "imstkDeviceClient.h"
+#include "quat.h"
+
+namespace imstk
+{
+class VRPNDeviceClient;
+
+using VRPNDeviceType = int;
+const VRPNDeviceType VRPNAnalog  = 0x1;
+const VRPNDeviceType VRPNButton  = 0x2;
+const VRPNDeviceType VRPNTracker = 0x4;
+const VRPNDeviceType VRPNForce   = 0x8;
+
+///
+/// \class VRPNDeviceManager
+///
+/// \brief connects to the vrpn.exe server and lets iMSTK attach devices to the server
+///
+/// This module enables communication with VRPN and lets us map VRPN devices to the
+/// imstk DeviceClient interface. The VRPN server is external to iMSTK and needs to
+/// be run from the command line `vrpn_server`, when using the default vrpn.cfg file needs to be
+/// edited represent the projects requirements.
+/// For more information on VRPN see the wiki https://github.com/vrpn/vrpn/wiki
+///
+class VRPNDeviceManager : public Module
+{
+public:
+
+    ///
+    /// \brief Constructor
+    /// \param machine The ip address of the machine where the vrpn server is running, "localhost" and "loopback"
+    ///                are also options
+    /// \param port The port that the vrpn server is listening to (can set on the command line)
+    ///
+    VRPNDeviceManager(const std::string& machine = "localhost", int port = vrpn_DEFAULT_LISTEN_PORT_NO);
+
+    virtual ~VRPNDeviceManager() override = default;
+
+    void addDeviceClient(std::shared_ptr<VRPNDeviceClient> client);
+
+    ///
+    /// \brief Creates a client from the given parameters
+    /// \param deviceName The name of the device that you want, it must match (case-sensitive) with the
+    ///                   name in the selected `vrpn.cfg` file
+    /// \param deviceType A binary combination of the parameters that should be updated. Note that this
+    ///                   is a request, if the server doesn't supply the requested updates no changes
+    ///                   will be observable
+    ///
+    std::shared_ptr<DeviceClient> makeDeviceClient(const std::string& deviceName, VRPNDeviceType deviceType);
+
+protected:
+    ///
+    /// \brief Initialize the server module
+    ///
+    bool initModule() override;
+
+    ///
+    /// \brief Run the server module
+    ///
+    void updateModule() override;
+
+    ///
+    /// \brief Clean the server module
+    ///
+    void uninitModule() override;
+
+private:
+
+    const std::string m_machine;                                       ///< machine name or IP
+    const int m_port;                                                  ///< connection port
+
+    struct Client
+    {
+        std::shared_ptr<VRPNDeviceClient> client;
+        VRPNDeviceType type;
+    };
+
+    std::map<VRPNDeviceType, std::vector<std::shared_ptr<VRPNDeviceClient>>> m_deviceMap; ///< keeping track of clients
+    std::unique_ptr<vrpn_MainloopContainer> m_deviceConnections;                          ///< VRPN device connections
+};
+} // imstk
diff --git a/Source/Devices/imstkVRPNDeviceServer.cpp b/Source/Devices/imstkVRPNDeviceServer.cpp
deleted file mode 100644
index c1adf8df3be1a0bc0c697032057a1d7f7a324731..0000000000000000000000000000000000000000
--- a/Source/Devices/imstkVRPNDeviceServer.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*=========================================================================
-
-   Library: iMSTK
-
-   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
-   & Imaging in Medicine, Rensselaer Polytechnic Institute.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0.txt
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
-=========================================================================*/
-
-#include "imstkVRPNDeviceServer.h"
-#include "imstkLogger.h"
-
-#include <vrpn_3DConnexion.h>
-#include <vrpn_Streaming_Arduino.h>
-#include <vrpn_Tracker_NovintFalcon.h>
-#include <vrpn_Tracker_OSVRHackerDevKit.h>
-#ifdef VRPN_USE_PHANTOM_SERVER
-#include <vrpn_Phantom.h>
-#endif
-
-namespace imstk
-{
-void
-VRPNDeviceServer::addDevice(const std::string& deviceName, DeviceType deviceType, int id)
-{
-    m_deviceInfoMap[deviceName] = std::make_pair(deviceType, id);
-
-    if (deviceType == DeviceType::PhantomOmni)
-    {
-        LOG(WARNING) << "warning: OpenHaptics support on VRPN "
-                     << "currently unstable for the Phantom Omni (no force feedback implemented).\n"
-                     << "Use HDAPIDeviceClient instead of VRPNDeviceServer/Client for ";
-    }
-}
-
-void
-VRPNDeviceServer::addSerialDevice(const std::string& deviceName, DeviceType deviceType, const std::string& port, int baudRate, int id)
-{
-    SerialInfo serialSettings;
-    serialSettings.baudRate     = baudRate;
-    serialSettings.port         = port;
-    m_deviceInfoMap[deviceName] = std::make_pair(deviceType, id);
-    m_SerialInfoMap[deviceName] = serialSettings;
-}
-
-bool
-VRPNDeviceServer::initModule()
-{
-    std::string ip = m_machine + ":" + std::to_string(m_port);
-    m_serverConnection = vrpn_create_server_connection(ip.c_str());
-
-    m_deviceConnections = new vrpn_MainloopContainer();
-
-    for (const auto& device : m_deviceInfoMap)
-    {
-        std::string name = device.first;
-        DeviceType  type = device.second.first;
-        auto        id   = device.second.second;
-
-        switch (type)
-        {
-        case DeviceType::SpaceExplorer3DConnexion:
-        {
-            m_deviceConnections->add(new vrpn_3DConnexion_SpaceExplorer(name.c_str(), m_serverConnection));
-        } break;
-        case DeviceType::Navigator3DConnexion:
-        {
-            m_deviceConnections->add(new vrpn_3DConnexion_Navigator(name.c_str(), m_serverConnection));
-        } break;
-        case DeviceType::NovintFalcon:
-        {
-#ifdef VRPN_USE_LIBNIFALCON
-            m_deviceConnections->add(new vrpn_Tracker_NovintFalcon(name.c_str(), m_serverConnection,
-                                                                   id, "4-button", "stamper"));
-#else
-            LOG(WARNING) << "error: no support for Novint Falcon in VRPN. "
-                         << "Build VRPN with VRPN_USE_LIBNIFALCON.";
-#endif
-        } break;
-        case DeviceType::PhantomOmni:
-        {
-#ifdef VRPN_USE_PHANTOM_SERVER
-            char* deviceName = const_cast<char*>(name.c_str());
-            m_deviceConnections->add(new vrpn_Phantom(deviceName, m_serverConnection, 90.0f, deviceName));
-#else
-            LOG(WARNING) << "error: no support for Phantom Omni in VRPN. "
-                         << "Install OpenHaptics SDK, the omni driver, and build VRPN with VRPN_USE_PHANTOM_SERVER.";
-#endif
-        } break;
-        //case DeviceType::OSVR_HDK:
-        //{
-        //    m_deviceConnections->add(new vrpn_Tracker_OSVRHackerDevKit(name.c_str(), m_serverConnection));
-        //} break;
-        case DeviceType::Arduino:
-        {
-            SerialInfo connectionSettings = m_SerialInfoMap[name];
-            //open with 6 channels (max needed for IMU, can use less)
-            m_deviceConnections->add(new vrpn_Streaming_Arduino(name.c_str(), m_serverConnection, connectionSettings.port, 6, connectionSettings.baudRate));
-        } break;
-        default:
-        {
-            LOG(WARNING) << "error: can not connect to "
-                         << name << ", device type unknown.";
-            return false;
-        } break;
-        }
-    }
-    return true;
-}
-
-void
-VRPNDeviceServer::updateModule()
-{
-    m_serverConnection->mainloop();
-    m_deviceConnections->mainloop();
-}
-
-void
-VRPNDeviceServer::uninitModule()
-{
-    m_deviceConnections->clear();
-    delete(m_deviceConnections);
-
-    m_serverConnection->removeReference();
-    //delete(m_connection);
-}
-} // imstk
diff --git a/Source/Devices/imstkVRPNDeviceServer.h b/Source/Devices/imstkVRPNDeviceServer.h
deleted file mode 100644
index 0a38f2bd7c83facd47a041b30fdbd7ce72640933..0000000000000000000000000000000000000000
--- a/Source/Devices/imstkVRPNDeviceServer.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*=========================================================================
-
-   Library: iMSTK
-
-   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
-   & Imaging in Medicine, Rensselaer Polytechnic Institute.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0.txt
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
-=========================================================================*/
-
-#pragma once
-
-#include "imstkModule.h"
-
-#include <map>
-#include <string>
-
-#include <vrpn_Connection.h>
-#include <vrpn_MainloopContainer.h>
-
-namespace imstk
-{
-///
-/// \brief Enumeration for device types
-///
-enum class DeviceType
-{
-    SpaceExplorer3DConnexion,
-    Navigator3DConnexion,
-    NovintFalcon,
-    PhantomOmni,
-    OSVR_HDK,
-    Arduino
-};
-
-///
-/// \class VRPNDeviceServer
-/// \brief Devices server using VRPN
-///
-class VRPNDeviceServer : public Module
-{
-public:
-
-    ///
-    /// \brief Constructor
-    ///
-    VRPNDeviceServer(const std::string& machine = "localhost", int port = vrpn_DEFAULT_LISTEN_PORT_NO) : Module(),
-        m_machine(machine),
-        m_port(port)
-    {}
-
-    ///
-    /// \brief Destructor
-    ///
-    virtual ~VRPNDeviceServer() override = default;
-
-    ///
-    /// \brief Add device
-    ///
-    void addDevice(const std::string& deviceName, DeviceType deviceType, int id = 0);
-
-    ///
-    /// \brief Add serial device
-    ///
-    void addSerialDevice(const std::string& deviceName, DeviceType deviceType, const std::string& port = "COM6", int baudRate = 57600, int id = 0);
-
-protected:
-    ///
-    /// \brief Initialize the server module
-    ///
-    bool initModule() override;
-
-    ///
-    /// \brief Run the server module
-    ///
-    void updateModule() override;
-
-    ///
-    /// \brief Clean the server module
-    ///
-    void uninitModule() override;
-
-private:
-
-    ///
-    /// \struct
-    /// \brief TODO
-    ///
-    struct SerialInfo
-    {
-        int baudRate;
-        std::string port;
-    };
-
-    const std::string m_machine;                                       ///< machine name or IP
-    const int m_port;                                                  ///< connection port
-
-    std::map<std::string, std::pair<DeviceType, int>> m_deviceInfoMap; ///< list of iMSTK client info
-    std::map<std::string, SerialInfo> m_SerialInfoMap;
-    vrpn_Connection* m_serverConnection = nullptr;                     ///< VRPN server connection
-    vrpn_MainloopContainer* m_deviceConnections = nullptr;             ///< VRPN device connections
-};
-} // imstk